From d2e5529e08d0e0f1eb111e48c5fd95eb90b69bf0 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 8 Feb 2021 23:19:37 +0800 Subject: [PATCH] bootstrap: include v8 module into the builtin snapshot PR-URL: https://github.com/nodejs/node/pull/36943 Fixes: https://github.com/nodejs/node/issues/35930 Refs: https://github.com/nodejs/node/issues/35711 Reviewed-By: James M Snell --- lib/internal/bootstrap/node.js | 1 + lib/v8.js | 15 ++++----- src/heap_utils.cc | 9 ++++++ src/inspector_profiler.cc | 12 +++++++- src/node_external_reference.h | 9 +++++- src/node_serdes.cc | 36 +++++++++++++++++++--- src/node_snapshotable.h | 3 +- src/node_v8.cc | 41 +++++++++++++++++++++++-- src/node_v8.h | 7 ++++- src/stream_wrap.cc | 20 +++++++----- src/stream_wrap.h | 3 +- src/uv.cc | 12 ++++++-- test/parallel/test-bootstrap-modules.js | 8 +++++ 13 files changed, 147 insertions(+), 29 deletions(-) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 5b6474d017d4eb..352eeb4083e7ee 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -279,6 +279,7 @@ process.emitWarning = emitWarning; // Preload modules so that they are included in the builtin snapshot. require('fs'); +require('v8'); function setupPrepareStackTrace() { const { diff --git a/lib/v8.js b/lib/v8.js index f1c624bc10add0..e7a44331b8b350 100644 --- a/lib/v8.js +++ b/lib/v8.js @@ -72,12 +72,13 @@ function getHeapSnapshot() { return new HeapSnapshotStream(handle); } +// We need to get the buffer from the binding at the callsite since +// it's re-initialized after deserialization. +const binding = internalBinding('v8'); + const { cachedDataVersionTag, setFlagsFromString: _setFlagsFromString, - heapStatisticsBuffer, - heapSpaceStatisticsBuffer, - heapCodeStatisticsBuffer, updateHeapStatisticsBuffer, updateHeapSpaceStatisticsBuffer, updateHeapCodeStatisticsBuffer, @@ -106,7 +107,7 @@ const { kCodeAndMetadataSizeIndex, kBytecodeAndMetadataSizeIndex, kExternalScriptSourceSizeIndex -} = internalBinding('v8'); +} = binding; const kNumberOfHeapSpaces = kHeapSpaces.length; @@ -116,7 +117,7 @@ function setFlagsFromString(flags) { } function getHeapStatistics() { - const buffer = heapStatisticsBuffer; + const buffer = binding.heapStatisticsBuffer; updateHeapStatisticsBuffer(); @@ -137,7 +138,7 @@ function getHeapStatistics() { function getHeapSpaceStatistics() { const heapSpaceStatistics = new Array(kNumberOfHeapSpaces); - const buffer = heapSpaceStatisticsBuffer; + const buffer = binding.heapSpaceStatisticsBuffer; for (let i = 0; i < kNumberOfHeapSpaces; i++) { updateHeapSpaceStatisticsBuffer(i); @@ -154,7 +155,7 @@ function getHeapSpaceStatistics() { } function getHeapCodeStatistics() { - const buffer = heapCodeStatisticsBuffer; + const buffer = binding.heapCodeStatisticsBuffer; updateHeapCodeStatisticsBuffer(); return { diff --git a/src/heap_utils.cc b/src/heap_utils.cc index c0c9ac2bdc7cee..bc779489637048 100644 --- a/src/heap_utils.cc +++ b/src/heap_utils.cc @@ -1,6 +1,7 @@ #include "diagnosticfilename-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" +#include "node_external_reference.h" #include "stream_base-inl.h" #include "util-inl.h" @@ -399,7 +400,15 @@ void Initialize(Local target, env->SetMethod(target, "createHeapSnapshotStream", CreateHeapSnapshotStream); } +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(BuildEmbedderGraph); + registry->Register(TriggerHeapSnapshot); + registry->Register(CreateHeapSnapshotStream); +} + } // namespace heap } // namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(heap_utils, node::heap::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(heap_utils, + node::heap::RegisterExternalReferences) diff --git a/src/inspector_profiler.cc b/src/inspector_profiler.cc index 092b263ada2fdd..e40b4b99cc8db3 100644 --- a/src/inspector_profiler.cc +++ b/src/inspector_profiler.cc @@ -3,8 +3,9 @@ #include "debug_utils-inl.h" #include "diagnosticfilename-inl.h" #include "memory_tracker-inl.h" -#include "node_file.h" #include "node_errors.h" +#include "node_external_reference.h" +#include "node_file.h" #include "node_internals.h" #include "util-inl.h" #include "v8-inspector.h" @@ -519,7 +520,16 @@ static void Initialize(Local target, env->SetMethod(target, "stopCoverage", StopCoverage); } +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(SetCoverageDirectory); + registry->Register(SetSourceMapCacheGetter); + registry->Register(TakeCoverage); + registry->Register(StopCoverage); +} + } // namespace profiler } // namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(profiler, node::profiler::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(profiler, + node::profiler::RegisterExternalReferences) diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 71d155cdb92caf..316d1d7b865dd8 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -56,6 +56,7 @@ class ExternalReferenceRegistry { V(fs) \ V(fs_dir) \ V(handle_wrap) \ + V(heap_utils) \ V(messaging) \ V(native_module) \ V(process_methods) \ @@ -63,10 +64,14 @@ class ExternalReferenceRegistry { V(task_queue) \ V(url) \ V(util) \ + V(serdes) \ V(string_decoder) \ + V(stream_wrap) \ V(trace_events) \ V(timers) \ V(types) \ + V(uv) \ + V(v8) \ V(worker) #if NODE_HAVE_I18N_SUPPORT @@ -76,7 +81,9 @@ class ExternalReferenceRegistry { #endif // NODE_HAVE_I18N_SUPPORT #if HAVE_INSPECTOR -#define EXTERNAL_REFERENCE_BINDING_LIST_INSPECTOR(V) V(inspector) +#define EXTERNAL_REFERENCE_BINDING_LIST_INSPECTOR(V) \ + V(inspector) \ + V(profiler) #else #define EXTERNAL_REFERENCE_BINDING_LIST_INSPECTOR(V) #endif // HAVE_INSPECTOR diff --git a/src/node_serdes.cc b/src/node_serdes.cc index 879253f9bc2ebc..be16f4dd053616 100644 --- a/src/node_serdes.cc +++ b/src/node_serdes.cc @@ -1,8 +1,9 @@ -#include "node_internals.h" +#include "base_object-inl.h" #include "node_buffer.h" #include "node_errors.h" +#include "node_external_reference.h" +#include "node_internals.h" #include "util-inl.h" -#include "base_object-inl.h" namespace node { @@ -26,7 +27,7 @@ using v8::Value; using v8::ValueDeserializer; using v8::ValueSerializer; -namespace { +namespace serdes { class SerializerContext : public BaseObject, public ValueSerializer::Delegate { @@ -503,7 +504,32 @@ void Initialize(Local target, env->SetConstructorFunction(target, "Deserializer", des); } -} // anonymous namespace +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(SerializerContext::New); + + registry->Register(SerializerContext::WriteHeader); + registry->Register(SerializerContext::WriteValue); + registry->Register(SerializerContext::ReleaseBuffer); + registry->Register(SerializerContext::TransferArrayBuffer); + registry->Register(SerializerContext::WriteUint32); + registry->Register(SerializerContext::WriteUint64); + registry->Register(SerializerContext::WriteDouble); + registry->Register(SerializerContext::WriteRawBytes); + registry->Register(SerializerContext::SetTreatArrayBufferViewsAsHostObjects); + + registry->Register(DeserializerContext::New); + registry->Register(DeserializerContext::ReadHeader); + registry->Register(DeserializerContext::ReadValue); + registry->Register(DeserializerContext::GetWireFormatVersion); + registry->Register(DeserializerContext::TransferArrayBuffer); + registry->Register(DeserializerContext::ReadUint32); + registry->Register(DeserializerContext::ReadUint64); + registry->Register(DeserializerContext::ReadDouble); + registry->Register(DeserializerContext::ReadRawBytes); +} + +} // namespace serdes } // namespace node -NODE_MODULE_CONTEXT_AWARE_INTERNAL(serdes, node::Initialize) +NODE_MODULE_CONTEXT_AWARE_INTERNAL(serdes, node::serdes::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(serdes, node::serdes::RegisterExternalReferences) diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index d0fbce800a63ec..3a0d3e42f4c712 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -13,7 +13,8 @@ class Environment; struct EnvSerializeInfo; #define SERIALIZABLE_OBJECT_TYPES(V) \ - V(fs_binding_data, fs::BindingData) + V(fs_binding_data, fs::BindingData) \ + V(v8_binding_data, v8_utils::BindingData) enum class EmbedderObjectType : uint8_t { k_default = 0, diff --git a/src/node_v8.cc b/src/node_v8.cc index 4354e1e1772d82..c1098e2d339578 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -24,6 +24,7 @@ #include "env-inl.h" #include "memory_tracker-inl.h" #include "node.h" +#include "node_external_reference.h" #include "util-inl.h" #include "v8.h" @@ -32,6 +33,7 @@ namespace v8_utils { using v8::Array; using v8::Context; using v8::FunctionCallbackInfo; +using v8::HandleScope; using v8::HeapCodeStatistics; using v8::HeapSpaceStatistics; using v8::HeapStatistics; @@ -45,6 +47,7 @@ using v8::Uint32; using v8::V8; using v8::Value; + #define HEAP_STATISTICS_PROPERTIES(V) \ V(0, total_heap_size, kTotalHeapSizeIndex) \ V(1, total_heap_size_executable, kTotalHeapSizeExecutableIndex) \ @@ -85,7 +88,7 @@ static const size_t kHeapCodeStatisticsPropertiesCount = #undef V BindingData::BindingData(Environment* env, Local obj) - : BaseObject(env, obj), + : SnapshotableObject(env, obj, type_int), heap_statistics_buffer(env->isolate(), kHeapStatisticsPropertiesCount), heap_space_statistics_buffer(env->isolate(), kHeapSpaceStatisticsPropertiesCount), @@ -105,6 +108,32 @@ BindingData::BindingData(Environment* env, Local obj) .Check(); } +void BindingData::PrepareForSerialization(Local context, + v8::SnapshotCreator* creator) { + // We'll just re-initialize the buffers in the constructor since their + // contents can be thrown away once consumed in the previous call. + heap_statistics_buffer.Release(); + heap_space_statistics_buffer.Release(); + heap_code_statistics_buffer.Release(); +} + +void BindingData::Deserialize(Local context, + Local holder, + int index, + InternalFieldInfo* info) { + DCHECK_EQ(index, BaseObject::kSlot); + HandleScope scope(context->GetIsolate()); + Environment* env = Environment::GetCurrent(context); + BindingData* binding = env->AddBindingData(context, holder); + CHECK_NOT_NULL(binding); +} + +InternalFieldInfo* BindingData::Serialize(int index) { + DCHECK_EQ(index, BaseObject::kSlot); + InternalFieldInfo* info = InternalFieldInfo::New(type()); + return info; +} + void BindingData::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("heap_statistics_buffer", heap_statistics_buffer); tracker->TrackField("heap_space_statistics_buffer", @@ -168,7 +197,6 @@ void SetFlagsFromString(const FunctionCallbackInfo& args) { V8::SetFlagsFromString(*flags, static_cast(flags.length())); } - void Initialize(Local target, Local unused, Local context, @@ -223,7 +251,16 @@ void Initialize(Local target, env->SetMethod(target, "setFlagsFromString", SetFlagsFromString); } +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(CachedDataVersionTag); + registry->Register(UpdateHeapStatisticsBuffer); + registry->Register(UpdateHeapCodeStatisticsBuffer); + registry->Register(UpdateHeapSpaceStatisticsBuffer); + registry->Register(SetFlagsFromString); +} + } // namespace v8_utils } // namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(v8, node::v8_utils::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(v8, node::v8_utils::RegisterExternalReferences) diff --git a/src/node_v8.h b/src/node_v8.h index 745c6580b844f4..5de8cb3f9c643c 100644 --- a/src/node_v8.h +++ b/src/node_v8.h @@ -5,18 +5,23 @@ #include "aliased_buffer.h" #include "base_object.h" +#include "node_snapshotable.h" #include "util.h" #include "v8.h" namespace node { class Environment; +struct InternalFieldInfo; namespace v8_utils { -class BindingData : public BaseObject { +class BindingData : public SnapshotableObject { public: BindingData(Environment* env, v8::Local obj); + SERIALIZABLE_OBJECT_METHODS() static constexpr FastStringKey type_name{"node::v8::BindingData"}; + static constexpr EmbedderObjectType type_int = + EmbedderObjectType::k_v8_binding_data; AliasedFloat64Array heap_statistics_buffer; AliasedFloat64Array heap_space_statistics_buffer; diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index a1fa5e94b73711..78d20f912b4cdb 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -25,6 +25,7 @@ #include "env-inl.h" #include "handle_wrap.h" #include "node_buffer.h" +#include "node_external_reference.h" #include "pipe_wrap.h" #include "req_wrap-inl.h" #include "tcp_wrap.h" @@ -51,6 +52,10 @@ using v8::ReadOnly; using v8::Signature; using v8::Value; +void IsConstructCallCallback(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + StreamReq::ResetObject(args.This()); +} void LibuvStreamWrap::Initialize(Local target, Local unused, @@ -58,13 +63,8 @@ void LibuvStreamWrap::Initialize(Local target, void* priv) { Environment* env = Environment::GetCurrent(context); - auto is_construct_call_callback = - [](const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); - StreamReq::ResetObject(args.This()); - }; Local sw = - FunctionTemplate::New(env->isolate(), is_construct_call_callback); + FunctionTemplate::New(env->isolate(), IsConstructCallCallback); sw->InstanceTemplate()->SetInternalFieldCount(StreamReq::kInternalFieldCount); // we need to set handle and callback to null, @@ -88,7 +88,7 @@ void LibuvStreamWrap::Initialize(Local target, env->set_shutdown_wrap_template(sw->InstanceTemplate()); Local ww = - FunctionTemplate::New(env->isolate(), is_construct_call_callback); + FunctionTemplate::New(env->isolate(), IsConstructCallCallback); ww->InstanceTemplate()->SetInternalFieldCount( StreamReq::kInternalFieldCount); ww->Inherit(AsyncWrap::GetConstructorTemplate(env)); @@ -103,6 +103,10 @@ void LibuvStreamWrap::Initialize(Local target, env->stream_base_state().GetJSArray()).Check(); } +void LibuvStreamWrap::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(IsConstructCallCallback); +} LibuvStreamWrap::LibuvStreamWrap(Environment* env, Local object, @@ -396,3 +400,5 @@ void LibuvStreamWrap::AfterUvWrite(uv_write_t* req, int status) { NODE_MODULE_CONTEXT_AWARE_INTERNAL(stream_wrap, node::LibuvStreamWrap::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE( + stream_wrap, node::LibuvStreamWrap::RegisterExternalReferences) diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 816f557ee6cb0a..3016e8d89cd367 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -31,6 +31,7 @@ namespace node { class Environment; +class ExternalReferenceRegistry; class LibuvStreamWrap : public HandleWrap, public StreamBase { public: @@ -38,7 +39,7 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase { v8::Local unused, v8::Local context, void* priv); - + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); int GetFD() override; bool IsAlive() override; bool IsClosing() override; diff --git a/src/uv.cc b/src/uv.cc index 7347826cab0fc8..0e6672c47269b3 100644 --- a/src/uv.cc +++ b/src/uv.cc @@ -22,6 +22,7 @@ #include "uv.h" #include "env-inl.h" #include "node.h" +#include "node_external_reference.h" #include "node_process.h" namespace node { @@ -42,7 +43,7 @@ static const struct UVError uv_errors_map[] = { }; } // namespace per_process -namespace { +namespace uv { using v8::Array; using v8::Context; @@ -130,7 +131,12 @@ void Initialize(Local target, env->SetMethod(target, "getErrorMap", GetErrMap); } -} // anonymous namespace +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(ErrName); + registry->Register(GetErrMap); +} +} // namespace uv } // namespace node -NODE_MODULE_CONTEXT_AWARE_INTERNAL(uv, node::Initialize) +NODE_MODULE_CONTEXT_AWARE_INTERNAL(uv, node::uv::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(uv, node::uv::RegisterExternalReferences) diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 236c95457fe779..db8d9eaa434b96 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -18,12 +18,15 @@ const expectedModules = new Set([ 'Internal Binding fs', 'Internal Binding fs_dir', 'Internal Binding fs_event_wrap', + 'Internal Binding heap_utils', 'Internal Binding messaging', 'Internal Binding module_wrap', 'Internal Binding native_module', 'Internal Binding options', 'Internal Binding process_methods', 'Internal Binding report', + 'Internal Binding serdes', + 'Internal Binding stream_wrap', 'Internal Binding string_decoder', 'Internal Binding symbols', 'Internal Binding task_queue', @@ -33,6 +36,7 @@ const expectedModules = new Set([ 'Internal Binding url', 'Internal Binding util', 'Internal Binding uv', + 'Internal Binding v8', 'Internal Binding worker', 'NativeModule buffer', 'NativeModule events', @@ -54,6 +58,7 @@ const expectedModules = new Set([ 'NativeModule internal/fs/promises', 'NativeModule internal/fs/rimraf', 'NativeModule internal/fs/watchers', + 'NativeModule internal/heap_utils', 'NativeModule internal/idna', 'NativeModule internal/linkedlist', 'NativeModule internal/modules/run_main', @@ -81,6 +86,7 @@ const expectedModules = new Set([ 'NativeModule internal/process/warning', 'NativeModule internal/querystring', 'NativeModule internal/source_map/source_map_cache', + 'NativeModule internal/stream_base_commons', 'NativeModule internal/streams/add-abort-signal', 'NativeModule internal/streams/buffer_list', 'NativeModule internal/streams/destroy', @@ -111,6 +117,7 @@ const expectedModules = new Set([ 'NativeModule timers', 'NativeModule url', 'NativeModule util', + 'NativeModule v8', 'NativeModule vm', ]); @@ -150,6 +157,7 @@ if (process.features.inspector) { expectedModules.add('Internal Binding inspector'); expectedModules.add('NativeModule internal/inspector_async_hook'); expectedModules.add('NativeModule internal/util/inspector'); + expectedModules.add('Internal Binding profiler'); } if (process.env.NODE_V8_COVERAGE) {