From 7a633c4107a5e9352af6fb649e362dc0ba8354b4 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 8 Feb 2021 20:34:02 +0800 Subject: [PATCH 1/3] src: support serialization of binding data This patch adds the SnapshotableObject interface. Native objects supporting serialization can inherit from it, implementing PrepareForSerialization(), Serialize() and Deserialize() to control how the native states should be serialized and deserialized. See doc: https://docs.google.com/document/d/15bu038I36oILq5t4Qju1sS2nKudVB6NSGWz00oD48Q8/edit --- src/aliased_buffer.h | 5 ++ src/base_object.h | 4 ++ src/env-inl.h | 11 ++++ src/env.cc | 28 ++++++++++ src/env.h | 26 +++++++++ src/node_snapshotable.cc | 117 +++++++++++++++++++++++++++++++++++---- src/node_snapshotable.h | 104 +++++++++++++++++++++++++++++++++- 7 files changed, 283 insertions(+), 12 deletions(-) diff --git a/src/aliased_buffer.h b/src/aliased_buffer.h index 134685542d4a75..53011c5fe0af25 100644 --- a/src/aliased_buffer.h +++ b/src/aliased_buffer.h @@ -198,6 +198,11 @@ class AliasedBufferBase { return js_array_.Get(isolate_); } + void Release() { + DCHECK_NULL(index_); + js_array_.Reset(); + } + /** * Get the underlying v8::ArrayBuffer underlying the TypedArray and * overlaying the native buffer diff --git a/src/base_object.h b/src/base_object.h index 3eac795e783e9d..6482bd85f86a56 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -158,6 +158,9 @@ class BaseObject : public MemoryRetainer { virtual inline void OnGCCollect(); + bool is_snapshotable() const { return is_snapshotable_; } + void set_is_snapshotable(bool val) { is_snapshotable_ = val; } + private: v8::Local WrappedObject() const override; bool IsRootNode() const override; @@ -206,6 +209,7 @@ class BaseObject : public MemoryRetainer { Environment* env_; PointerData* pointer_data_ = nullptr; + bool is_snapshotable_ = false; }; // Global alias for FromJSObject() to avoid churn. diff --git a/src/env-inl.h b/src/env-inl.h index 850363af5aeffb..86c870ca55f047 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -1085,6 +1085,17 @@ void Environment::ForEachBaseObject(T&& iterator) { } } +template +void Environment::ForEachBindingData(T&& iterator) { + BindingDataStore* map = static_cast( + context()->GetAlignedPointerFromEmbedderData( + ContextEmbedderIndex::kBindingListIndex)); + DCHECK_NOT_NULL(map); + for (auto& it : *map) { + iterator(it.first, it.second); + } +} + void Environment::modify_base_object_count(int64_t delta) { base_object_count_ += delta; } diff --git a/src/env.cc b/src/env.cc index 2757319b7b62bf..a113bf36dd8c6a 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1251,6 +1251,7 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) { EnvSerializeInfo info; Local ctx = context(); + SerializeBindingData(this, creator, &info); // Currently all modules are compiled without cache in builtin snapshot // builder. info.native_modules = std::vector( @@ -1317,6 +1318,9 @@ std::ostream& operator<<(std::ostream& output, std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) { output << "{\n" + << "// -- bindings begins --\n" + << i.bindings << ",\n" + << "// -- bindings ends --\n" << "// -- native_modules begins --\n" << i.native_modules << ",\n" << "// -- native_modules ends --\n" @@ -1342,9 +1346,33 @@ std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) { return output; } +void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb, + Local holder, + int index, + InternalFieldInfo* info) { + DeserializeRequest request{cb, {isolate(), holder}, index, info}; + deserialize_requests_.push_back(std::move(request)); +} + +void Environment::RunDeserializeRequests() { + HandleScope scope(isolate()); + Local ctx = context(); + Isolate* is = isolate(); + while (!deserialize_requests_.empty()) { + DeserializeRequest request(std::move(deserialize_requests_.front())); + deserialize_requests_.pop_front(); + Local holder = request.holder.Get(is); + request.cb(ctx, holder, request.index, request.info); + request.holder.Reset(); + request.info->Delete(); + } +} + void Environment::DeserializeProperties(const EnvSerializeInfo* info) { Local ctx = context(); + RunDeserializeRequests(); + native_modules_in_snapshot = info->native_modules; async_hooks_.Deserialize(ctx); immediate_info_.Deserialize(ctx); diff --git a/src/env.h b/src/env.h index dae522f25306d3..ba0626463f68b6 100644 --- a/src/env.h +++ b/src/env.h @@ -37,6 +37,7 @@ #include "node_main_instance.h" #include "node_options.h" #include "node_perf_common.h" +#include "node_snapshotable.h" #include "req_wrap.h" #include "util.h" #include "uv.h" @@ -899,7 +900,22 @@ struct PropInfo { SnapshotIndex index; // In the snapshot }; +typedef void (*DeserializeRequestCallback)(v8::Local context, + v8::Local holder, + int index, + InternalFieldInfo* info); +struct DeserializeRequest { + DeserializeRequestCallback cb; + v8::Global holder; + int index; + InternalFieldInfo* info = nullptr; // Owned by the request + + // Move constructor + DeserializeRequest(DeserializeRequest&& other) = default; +}; + struct EnvSerializeInfo { + std::vector bindings; std::vector native_modules; AsyncHooks::SerializeInfo async_hooks; TickInfo::SerializeInfo tick_info; @@ -934,6 +950,11 @@ class Environment : public MemoryRetainer { void PrintAllBaseObjects(); void VerifyNoStrongBaseObjects(); + void EnqueueDeserializeRequest(DeserializeRequestCallback cb, + v8::Local holder, + int index, + InternalFieldInfo* info); + void RunDeserializeRequests(); // Should be called before InitializeInspector() void InitializeDiagnostics(); @@ -1371,6 +1392,9 @@ class Environment : public MemoryRetainer { void AddUnmanagedFd(int fd); void RemoveUnmanagedFd(int fd); + template + void ForEachBindingData(T&& iterator); + private: inline void ThrowError(v8::Local (*fun)(v8::Local), const char* errmsg); @@ -1459,6 +1483,8 @@ class Environment : public MemoryRetainer { bool is_in_inspector_console_call_ = false; #endif + std::list deserialize_requests_; + // handle_wrap_queue_ and req_wrap_queue_ needs to be at a fixed offset from // the start of the class because it is used by // src/node_postmortem_metadata.cc to calculate offsets and generate debug diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 21de10868564d3..04ae6e26131b4e 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1,39 +1,134 @@ #include "node_snapshotable.h" #include "base_object-inl.h" +#include "debug_utils-inl.h" +#include "node_file.h" +#include "node_v8.h" namespace node { using v8::Local; using v8::Object; +using v8::SnapshotCreator; using v8::StartupData; +SnapshotableObject::SnapshotableObject(Environment* env, + Local wrap, + EmbedderObjectType type) + : BaseObject(env, wrap), type_(type) { + set_is_snapshotable(true); +} + +const char* SnapshotableObject::GetTypeNameChars() const { + switch (type_) { +#define V(PropertyName, NativeTypeName) \ + case EmbedderObjectType::k_##PropertyName: { \ + return NativeTypeName::type_name.c_str(); \ + } + SERIALIZABLE_OBJECT_TYPES(V) +#undef V + default: { UNREACHABLE(); } + } +} + +bool IsSnapshotableType(FastStringKey key) { +#define V(PropertyName, NativeTypeName) \ + if (key == NativeTypeName::type_name) { \ + return true; \ + } + SERIALIZABLE_OBJECT_TYPES(V) +#undef V + + return false; +} + void DeserializeNodeInternalFields(Local holder, int index, - v8::StartupData payload, + StartupData payload, void* env) { + per_process::Debug(DebugCategory::MKSNAPSHOT, + "Deserialize internal field %d of %p, size=%d\n", + static_cast(index), + (*holder), + static_cast(payload.raw_size)); if (payload.raw_size == 0) { holder->SetAlignedPointerInInternalField(index, nullptr); return; } - // No embedder object in the builtin snapshot yet. - UNREACHABLE(); + + Environment* env_ptr = static_cast(env); + const InternalFieldInfo* info = + reinterpret_cast(payload.data); + + switch (info->type) { +#define V(PropertyName, NativeTypeName) \ + case EmbedderObjectType::k_##PropertyName: { \ + per_process::Debug(DebugCategory::MKSNAPSHOT, \ + "Object %p is %s\n", \ + (*holder), \ + NativeTypeName::type_name.c_str()); \ + env_ptr->EnqueueDeserializeRequest( \ + NativeTypeName::Deserialize, holder, index, info->Copy()); \ + break; \ + } + SERIALIZABLE_OBJECT_TYPES(V) +#undef V + default: { UNREACHABLE(); } + } } StartupData SerializeNodeContextInternalFields(Local holder, int index, void* env) { - void* ptr = holder->GetAlignedPointerFromInternalField(index); - if (ptr == nullptr || ptr == env) { - return StartupData{nullptr, 0}; - } - if (ptr == env && index == ContextEmbedderIndex::kEnvironment) { + per_process::Debug(DebugCategory::MKSNAPSHOT, + "Serialize internal field, index=%d, holder=%p\n", + static_cast(index), + *holder); + void* ptr = holder->GetAlignedPointerFromInternalField(BaseObject::kSlot); + if (ptr == nullptr) { return StartupData{nullptr, 0}; } - // No embedder objects in the builtin snapshot yet. - UNREACHABLE(); - return StartupData{nullptr, 0}; + DCHECK(static_cast(ptr)->is_snapshotable()); + SnapshotableObject* obj = static_cast(ptr); + per_process::Debug(DebugCategory::MKSNAPSHOT, + "Object %p is %s, ", + *holder, + obj->GetTypeNameChars()); + InternalFieldInfo* info = obj->Serialize(index); + per_process::Debug(DebugCategory::MKSNAPSHOT, + "payload size=%d\n", + static_cast(info->length)); + return StartupData{reinterpret_cast(info), + static_cast(info->length)}; +} + +void SerializeBindingData(Environment* env, + SnapshotCreator* creator, + EnvSerializeInfo* info) { + size_t i = 0; + env->ForEachBindingData([&](FastStringKey key, + BaseObjectPtr binding) { + per_process::Debug(DebugCategory::MKSNAPSHOT, + "Serialize binding %i, %p, type=%s\n", + static_cast(i), + *(binding->object()), + key.c_str()); + + if (IsSnapshotableType(key)) { + size_t index = creator->AddData(env->context(), binding->object()); + per_process::Debug(DebugCategory::MKSNAPSHOT, + "Serialized with index=%d\n", + static_cast(index)); + info->bindings.push_back({key.c_str(), i, index}); + SnapshotableObject* ptr = static_cast(binding.get()); + ptr->PrepareForSerialization(env->context(), creator); + } else { + UNREACHABLE(); + } + + i++; + }); } } // namespace node diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index c45c1381b5554f..94a5a7a03ca731 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -4,9 +4,106 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "v8.h" +#include "base_object.h" +#include "util.h" + namespace node { +class Environment; +struct EnvSerializeInfo; + +#define SERIALIZABLE_OBJECT_TYPES(V) + +enum class EmbedderObjectType : uint8_t { + k_default = 0, +#define V(PropertyName, NativeType) k_##PropertyName, + SERIALIZABLE_OBJECT_TYPES(V) +#undef V +}; + +// When serializing an embedder object, we'll serialize the native states +// into a chunk that can be mapped into a subclass of InternalFieldInfo, +// and pass it into the V8 callback as the payload of StartupData. +// TODO(joyeecheung): the classification of types seem to be wrong. +// We'd need a type for each field of each class of native object. +// Maybe it's fine - we'll just use the type to invoke BaseObject constructors +// and specify that the BaseObject has only one field for us to serialize. +// And for non-BaseObject embedder objects, we'll use field-wise types. +// The memory chunk looks like this: +// +// [ type ] - EmbedderObjectType (a uint8_t) +// [ length ] - a size_t +// [ ... ] - custom bytes of size |length - header size| +struct InternalFieldInfo { + EmbedderObjectType type; + size_t length; + + InternalFieldInfo() = delete; + + static InternalFieldInfo* New(EmbedderObjectType type) { + return New(type, sizeof(InternalFieldInfo)); + } + + static InternalFieldInfo* New(EmbedderObjectType type, size_t length) { + InternalFieldInfo* result = + reinterpret_cast(::operator new(length)); + result->type = type; + result->length = length; + return result; + } + + InternalFieldInfo* Copy() const { + InternalFieldInfo* result = + reinterpret_cast(::operator new(length)); + memcpy(result, this, length); + return result; + } + + void Delete() { ::operator delete(this); } +}; + +// An interface for snapshotable native objects to inherit from. +// Use the SERIALIZABLE_OBJECT_METHODS() macro in the class to define +// the following methods to implement: +// +// - PrepareForSerialization(): This would be run prior to context +// serialization. Use this method to e.g. release references that +// can be re-initialized, or perform property store operations +// that needs a V8 context. +// - Serialize(): This would be called during context serialization, +// once for each embedder field of the object. +// Allocate and construct an InternalFieldInfo object that contains +// data that can be used to deserialize native states. +// - Deserialize(): This would be called after the context is +// deserialized and the object graph is complete, once for each +// embedder field of the object. Use this to restore native states +// in the object. +class SnapshotableObject : public BaseObject { + public: + SnapshotableObject(Environment* env, + v8::Local wrap, + EmbedderObjectType type = EmbedderObjectType::k_default); + const char* GetTypeNameChars() const; + + virtual void PrepareForSerialization(v8::Local context, + v8::SnapshotCreator* creator) = 0; + virtual InternalFieldInfo* Serialize(int index) = 0; + // We'll make sure that the type is set in the constructor + EmbedderObjectType type() { return type_; } + + private: + EmbedderObjectType type_; +}; + +#define SERIALIZABLE_OBJECT_METHODS() \ + void PrepareForSerialization(v8::Local context, \ + v8::SnapshotCreator* creator) override; \ + InternalFieldInfo* Serialize(int index) override; \ + static void Deserialize(v8::Local context, \ + v8::Local holder, \ + int index, \ + InternalFieldInfo* info); + v8::StartupData SerializeNodeContextInternalFields(v8::Local holder, int index, void* env); @@ -14,6 +111,11 @@ void DeserializeNodeInternalFields(v8::Local holder, int index, v8::StartupData payload, void* env); +void SerializeBindingData(Environment* env, + v8::SnapshotCreator* creator, + EnvSerializeInfo* info); + +bool IsSnapshotableType(FastStringKey key); } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS From ed19c326f9239044c7131c7241ed31ea0cbb77d9 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 8 Feb 2021 22:13:37 +0800 Subject: [PATCH 2/3] bootstrap: include fs module into the builtin snapshot --- lib/fs.js | 14 +++-- lib/internal/bootstrap/node.js | 3 + src/node_dir.cc | 9 +++ src/node_external_reference.h | 2 + src/node_file.cc | 104 ++++++++++++++++++++++++++++++--- src/node_file.h | 15 +++-- src/node_snapshotable.h | 3 +- src/node_stat_watcher.cc | 8 ++- src/node_stat_watcher.h | 2 + src/stream_base.cc | 28 ++++++++- src/stream_base.h | 3 +- 11 files changed, 165 insertions(+), 26 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 2bb629d58af081..31aff87d4bec86 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -67,6 +67,10 @@ const { const pathModule = require('path'); const { isArrayBufferView } = require('internal/util/types'); + +// We need to get the statValues from the binding at the callsite since +// it's re-initialized after deserialization. + const binding = internalBinding('fs'); const { Buffer } = require('buffer'); const { @@ -81,7 +85,7 @@ const { uvException } = require('internal/errors'); -const { FSReqCallback, statValues } = binding; +const { FSReqCallback } = binding; const { toPathIfFileURL } = require('internal/url'); const internalUtil = require('internal/util'); const { @@ -1772,8 +1776,8 @@ function realpathSync(p, options) { // Continue if not a symlink, break if a pipe/socket if (knownHard[base] || cache?.get(base) === base) { - if (isFileType(statValues, S_IFIFO) || - isFileType(statValues, S_IFSOCK)) { + if (isFileType(binding.statValues, S_IFIFO) || + isFileType(binding.statValues, S_IFSOCK)) { break; } continue; @@ -1915,8 +1919,8 @@ function realpath(p, options, callback) { // Continue if not a symlink, break if a pipe/socket if (knownHard[base]) { - if (isFileType(statValues, S_IFIFO) || - isFileType(statValues, S_IFSOCK)) { + if (isFileType(binding.statValues, S_IFIFO) || + isFileType(binding.statValues, S_IFSOCK)) { return callback(null, encodeRealpathResult(p, options)); } return process.nextTick(LOOP); diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 818f51ae02ad6d..72fcd2233b5c21 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -347,6 +347,9 @@ process.emitWarning = emitWarning; // Note: only after this point are the timers effective } +// Preload modules so that they are included in the builtin snapshot. +require('fs'); + function setupPrepareStackTrace() { const { setEnhanceStackForFatalException, diff --git a/src/node_dir.cc b/src/node_dir.cc index d94d78f560bf39..b103c08262a5e8 100644 --- a/src/node_dir.cc +++ b/src/node_dir.cc @@ -1,4 +1,5 @@ #include "node_dir.h" +#include "node_external_reference.h" #include "node_file-inl.h" #include "node_process.h" #include "memory_tracker-inl.h" @@ -364,8 +365,16 @@ void Initialize(Local target, env->set_dir_instance_template(dirt); } +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(OpenDir); + registry->Register(DirHandle::New); + registry->Register(DirHandle::Read); + registry->Register(DirHandle::Close); +} + } // namespace fs_dir } // end namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs_dir, node::fs_dir::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(fs_dir, node::fs_dir::RegisterExternalReferences) diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 0544979dd9a6f1..71d155cdb92caf 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -53,6 +53,8 @@ class ExternalReferenceRegistry { V(credentials) \ V(env_var) \ V(errors) \ + V(fs) \ + V(fs_dir) \ V(handle_wrap) \ V(messaging) \ V(native_module) \ diff --git a/src/node_file.cc b/src/node_file.cc index c4a75912419002..502f2968b6c08a 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -23,6 +23,7 @@ #include "aliased_buffer.h" #include "memory_tracker-inl.h" #include "node_buffer.h" +#include "node_external_reference.h" #include "node_process.h" #include "node_stat_watcher.h" #include "util-inl.h" @@ -2398,6 +2399,47 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const { file_handle_read_wrap_freelist); } +BindingData::BindingData(Environment* env, v8::Local wrap) + : SnapshotableObject(env, wrap, type_int), + stats_field_array(env->isolate(), kFsStatsBufferLength), + stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) { + wrap->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "statValues"), + stats_field_array.GetJSArray()) + .Check(); + + wrap->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatValues"), + stats_field_bigint_array.GetJSArray()) + .Check(); +} + +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); +} + +void BindingData::PrepareForSerialization(Local context, + v8::SnapshotCreator* creator) { + CHECK(file_handle_read_wrap_freelist.empty()); + // We'll just re-initialize the buffers in the constructor since their + // contents can be thrown away once consumed in the previous call. + stats_field_array.Release(); + stats_field_bigint_array.Release(); +} + +InternalFieldInfo* BindingData::Serialize(int index) { + DCHECK_EQ(index, BaseObject::kSlot); + InternalFieldInfo* info = InternalFieldInfo::New(type()); + return info; +} + // TODO(addaleax): Remove once we're on C++17. constexpr FastStringKey BindingData::type_name; @@ -2461,14 +2503,6 @@ void Initialize(Local target, static_cast(FsStatsOffset::kFsStatsFieldsNumber))) .Check(); - target->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "statValues"), - binding_data->stats_field_array.GetJSArray()).Check(); - - target->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"), - binding_data->stats_field_bigint_array.GetJSArray()).Check(); - StatWatcher::Initialize(env, target); // Create FunctionTemplate for FSReqCallback @@ -2532,8 +2566,62 @@ void Initialize(Local target, BindingData* FSReqBase::binding_data() { return binding_data_.get(); } + +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(Access); + StatWatcher::RegisterExternalReferences(registry); + + registry->Register(Close); + registry->Register(Open); + registry->Register(OpenFileHandle); + registry->Register(Read); + registry->Register(ReadBuffers); + registry->Register(Fdatasync); + registry->Register(Fsync); + registry->Register(Rename); + registry->Register(FTruncate); + registry->Register(RMDir); + registry->Register(MKDir); + registry->Register(ReadDir); + registry->Register(InternalModuleReadJSON); + registry->Register(InternalModuleStat); + registry->Register(Stat); + registry->Register(LStat); + registry->Register(FStat); + registry->Register(Link); + registry->Register(Symlink); + registry->Register(ReadLink); + registry->Register(Unlink); + registry->Register(WriteBuffer); + registry->Register(WriteBuffers); + registry->Register(WriteString); + registry->Register(RealPath); + registry->Register(CopyFile); + + registry->Register(Chmod); + registry->Register(FChmod); + // registry->Register(LChmod); + + registry->Register(Chown); + registry->Register(FChown); + registry->Register(LChown); + + registry->Register(UTimes); + registry->Register(FUTimes); + registry->Register(LUTimes); + + registry->Register(Mkdtemp); + registry->Register(NewFSReqCallback); + + registry->Register(FileHandle::New); + registry->Register(FileHandle::Close); + registry->Register(FileHandle::ReleaseFD); + StreamBase::RegisterExternalReferences(registry); +} + } // namespace fs } // end namespace node NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences) diff --git a/src/node_file.h b/src/node_file.h index 9e652dc7a4afa4..f1515a3e25d6d1 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -3,23 +3,19 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "node.h" #include "aliased_buffer.h" #include "node_messaging.h" +#include "node_snapshotable.h" #include "stream_base.h" -#include namespace node { namespace fs { class FileHandleReadWrap; -class BindingData : public BaseObject { +class BindingData : public SnapshotableObject { public: - explicit BindingData(Environment* env, v8::Local wrap) - : BaseObject(env, wrap), - stats_field_array(env->isolate(), kFsStatsBufferLength), - stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {} + explicit BindingData(Environment* env, v8::Local wrap); AliasedFloat64Array stats_field_array; AliasedBigUint64Array stats_field_bigint_array; @@ -27,7 +23,10 @@ class BindingData : public BaseObject { std::vector> file_handle_read_wrap_freelist; - static constexpr FastStringKey type_name { "fs" }; + SERIALIZABLE_OBJECT_METHODS() + static constexpr FastStringKey type_name{"node::fs::BindingData"}; + static constexpr EmbedderObjectType type_int = + EmbedderObjectType::k_fs_binding_data; void MemoryInfo(MemoryTracker* tracker) const override; SET_SELF_SIZE(BindingData) diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index 94a5a7a03ca731..d0fbce800a63ec 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -12,7 +12,8 @@ namespace node { class Environment; struct EnvSerializeInfo; -#define SERIALIZABLE_OBJECT_TYPES(V) +#define SERIALIZABLE_OBJECT_TYPES(V) \ + V(fs_binding_data, fs::BindingData) enum class EmbedderObjectType : uint8_t { k_default = 0, diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index 344ea6bb7ea2e6..b9f7903a2fdcb6 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -19,10 +19,11 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "memory_tracker-inl.h" #include "node_stat_watcher.h" #include "async_wrap-inl.h" #include "env-inl.h" +#include "memory_tracker-inl.h" +#include "node_external_reference.h" #include "node_file-inl.h" #include "util-inl.h" @@ -55,6 +56,11 @@ void StatWatcher::Initialize(Environment* env, Local target) { env->SetConstructorFunction(target, "StatWatcher", t); } +void StatWatcher::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(StatWatcher::New); + registry->Register(StatWatcher::Start); +} StatWatcher::StatWatcher(fs::BindingData* binding_data, Local wrap, diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h index c1d6ccce69bdbb..7efd22fdfdb841 100644 --- a/src/node_stat_watcher.h +++ b/src/node_stat_watcher.h @@ -35,10 +35,12 @@ class BindingData; } class Environment; +class ExternalReferenceRegistry; class StatWatcher : public HandleWrap { public: static void Initialize(Environment* env, v8::Local target); + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); protected: StatWatcher(fs::BindingData* binding_data, diff --git a/src/stream_base.cc b/src/stream_base.cc index 87781efb0e8111..925dc3f152e550 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -3,11 +3,12 @@ #include "stream_wrap.h" #include "allocated_buffer-inl.h" +#include "env-inl.h" +#include "js_stream.h" #include "node.h" #include "node_buffer.h" #include "node_errors.h" -#include "env-inl.h" -#include "js_stream.h" +#include "node_external_reference.h" #include "string_bytes.h" #include "util-inl.h" #include "v8.h" @@ -423,6 +424,29 @@ void StreamBase::AddMethods(Environment* env, Local t) { &Value::IsFunction>); } +void StreamBase::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(GetFD); + registry->Register(GetExternal); + registry->Register(GetBytesRead); + registry->Register(GetBytesWritten); + registry->Register(JSMethod<&StreamBase::ReadStartJS>); + registry->Register(JSMethod<&StreamBase::ReadStopJS>); + registry->Register(JSMethod<&StreamBase::Shutdown>); + registry->Register(JSMethod<&StreamBase::UseUserBuffer>); + registry->Register(JSMethod<&StreamBase::Writev>); + registry->Register(JSMethod<&StreamBase::WriteBuffer>); + registry->Register(JSMethod<&StreamBase::WriteString>); + registry->Register(JSMethod<&StreamBase::WriteString>); + registry->Register(JSMethod<&StreamBase::WriteString>); + registry->Register(JSMethod<&StreamBase::WriteString>); + registry->Register( + BaseObject::InternalFieldGet); + registry->Register( + BaseObject::InternalFieldSet); +} + void StreamBase::GetFD(const FunctionCallbackInfo& args) { // Mimic implementation of StreamBase::GetFD() and UDPWrap::GetFD(). StreamBase* wrap = StreamBase::FromObject(args.This().As()); diff --git a/src/stream_base.h b/src/stream_base.h index a5680ba8860d49..e0da891501ac85 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -19,6 +19,7 @@ class ShutdownWrap; class WriteWrap; class StreamBase; class StreamResource; +class ExternalReferenceRegistry; struct StreamWriteResult { bool async; @@ -308,7 +309,7 @@ class StreamBase : public StreamResource { static void AddMethods(Environment* env, v8::Local target); - + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); virtual bool IsAlive() = 0; virtual bool IsClosing() = 0; virtual bool IsIPCPipe(); From 8da45ff2294fc8224d327e27ef1c26b593a60ba9 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 8 Feb 2021 23:19:37 +0800 Subject: [PATCH 3/3] bootstrap: include v8 module into the builtin snapshot --- 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 72fcd2233b5c21..260670a20226cb 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -349,6 +349,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) {