From c480559347be39bec4f2361272e599acba5d699e Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 5 May 2023 22:01:02 +0200 Subject: [PATCH] bootstrap: put is_building_snapshot state in IsolateData Previously we modify the CLI options store to indicate whether the isolate is created for building snapshot, which is a bit hacky and makes it difficult to tell whether the snapshot is built from the command line or through other APIs. This patch adds is_building_snapshot to IsolateData and use this instead when we need to know whether the isolate is created for building snapshot (but do not care about where that request is coming from). PR-URL: https://github.com/nodejs/node/pull/47887 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Chengzhong Wu --- lib/internal/v8/startup_snapshot.js | 4 +- src/api/embed_helpers.cc | 4 +- src/base_object_types.h | 1 + src/env.h | 4 ++ src/node.cc | 4 +- src/node_binding.h | 1 + src/node_main_instance.cc | 2 + src/node_snapshotable.cc | 101 ++++++++++++++++++++++++---- src/node_snapshotable.h | 26 +++++++ src/node_worker.cc | 2 + 10 files changed, 131 insertions(+), 18 deletions(-) diff --git a/lib/internal/v8/startup_snapshot.js b/lib/internal/v8/startup_snapshot.js index 49623627706bc0..e5154446b01a3d 100644 --- a/lib/internal/v8/startup_snapshot.js +++ b/lib/internal/v8/startup_snapshot.js @@ -14,11 +14,11 @@ const { setSerializeCallback, setDeserializeCallback, setDeserializeMainFunction: _setDeserializeMainFunction, + isBuildingSnapshotBuffer } = internalBinding('mksnapshot'); function isBuildingSnapshot() { - // For now this is the only way to build a snapshot. - return require('internal/options').getOptionValue('--build-snapshot'); + return isBuildingSnapshotBuffer[0]; } function throwIfNotBuildingSnapshot() { diff --git a/src/api/embed_helpers.cc b/src/api/embed_helpers.cc index 5c8b733737a2e6..341d131f24f753 100644 --- a/src/api/embed_helpers.cc +++ b/src/api/embed_helpers.cc @@ -142,8 +142,8 @@ CommonEnvironmentSetup::CommonEnvironmentSetup( impl_->isolate_data.reset(CreateIsolateData( isolate, loop, platform, impl_->allocator.get(), snapshot_data)); - impl_->isolate_data->options()->build_snapshot = - impl_->snapshot_creator.has_value(); + impl_->isolate_data->set_is_building_snapshot( + impl_->snapshot_creator.has_value()); if (snapshot_data) { impl_->env.reset(make_env(this)); diff --git a/src/base_object_types.h b/src/base_object_types.h index 4916a20bbc6421..bb7a0e064b0b72 100644 --- a/src/base_object_types.h +++ b/src/base_object_types.h @@ -12,6 +12,7 @@ namespace node { #define SERIALIZABLE_BINDING_TYPES(V) \ V(encoding_binding_data, encoding_binding::BindingData) \ V(fs_binding_data, fs::BindingData) \ + V(mksnapshot_binding_data, mksnapshot::BindingData) \ V(v8_binding_data, v8_utils::BindingData) \ V(blob_binding_data, BlobBindingData) \ V(process_binding_data, process::BindingData) \ diff --git a/src/env.h b/src/env.h index 5359436be31e76..354d0bf414c55a 100644 --- a/src/env.h +++ b/src/env.h @@ -136,6 +136,9 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { void MemoryInfo(MemoryTracker* tracker) const override; IsolateDataSerializeInfo Serialize(v8::SnapshotCreator* creator); + bool is_building_snapshot() const { return is_building_snapshot_; } + void set_is_building_snapshot(bool value) { is_building_snapshot_ = value; } + inline uv_loop_t* event_loop() const; inline MultiIsolatePlatform* platform() const; inline const SnapshotData* snapshot_data() const; @@ -219,6 +222,7 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { const SnapshotData* snapshot_data_; std::shared_ptr options_; worker::Worker* worker_context_ = nullptr; + bool is_building_snapshot_ = false; }; struct ContextInfo { diff --git a/src/node.cc b/src/node.cc index 1806693d4bd204..acab0cb3d960b6 100644 --- a/src/node.cc +++ b/src/node.cc @@ -283,7 +283,7 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { auto reset_entry_point = OnScopeLeave([&]() { env->set_embedder_entry_point({}); }); - const char* entry = env->isolate_data()->options()->build_snapshot + const char* entry = env->isolate_data()->is_building_snapshot() ? "internal/main/mksnapshot" : "internal/main/embedding"; @@ -311,7 +311,7 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { return StartExecution(env, "internal/main/inspect"); } - if (env->isolate_data()->options()->build_snapshot) { + if (env->isolate_data()->is_building_snapshot()) { return StartExecution(env, "internal/main/mksnapshot"); } diff --git a/src/node_binding.h b/src/node_binding.h index f04be60c3890f0..dd7667899e5a7f 100644 --- a/src/node_binding.h +++ b/src/node_binding.h @@ -37,6 +37,7 @@ static_assert(static_cast(NM_F_LINKED) == V(contextify) \ V(encoding_binding) \ V(fs) \ + V(mksnapshot) \ V(timers) \ V(process_methods) \ V(performance) \ diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 34ed9075e0fe16..41e5bee353a579 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -56,6 +56,8 @@ NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data, platform, array_buffer_allocator_.get(), snapshot_data->AsEmbedderWrapper().get())); + isolate_data_->set_is_building_snapshot( + per_process::cli_options->per_isolate->build_snapshot); isolate_data_->max_young_gen_size = isolate_params_->constraints.max_young_generation_size_in_bytes(); diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index b2be437efff788..e5f6d0a60a3abb 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -3,6 +3,7 @@ #include #include #include +#include "aliased_buffer-inl.h" #include "base_object-inl.h" #include "blob_serializer_deserializer-inl.h" #include "debug_utils-inl.h" @@ -34,6 +35,7 @@ namespace node { using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; using v8::HandleScope; using v8::Isolate; using v8::Local; @@ -1177,8 +1179,6 @@ void SerializeSnapshotableObjects(Realm* realm, }); } -namespace mksnapshot { - // NB: This is also used by the regular embedding codepath. void GetEmbedderEntryFunction(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -1251,16 +1251,89 @@ void SetDeserializeMainFunction(const FunctionCallbackInfo& args) { env->set_snapshot_deserialize_main(args[0].As()); } -void Initialize(Local target, - Local unused, - Local context, - void* priv) { +namespace mksnapshot { + +BindingData::BindingData(Realm* realm, + v8::Local object, + InternalFieldInfo* info) + : SnapshotableObject(realm, object, type_int), + is_building_snapshot_buffer_( + realm->isolate(), + 1, + MAYBE_FIELD_PTR(info, is_building_snapshot_buffer)) { + if (info == nullptr) { + object + ->Set( + realm->context(), + FIXED_ONE_BYTE_STRING(realm->isolate(), "isBuildingSnapshotBuffer"), + is_building_snapshot_buffer_.GetJSArray()) + .Check(); + } else { + is_building_snapshot_buffer_.Deserialize(realm->context()); + } + // Reset the status according to the current state of the realm. + bool is_building_snapshot = realm->isolate_data()->is_building_snapshot(); + DCHECK_IMPLIES(is_building_snapshot, + realm->isolate_data()->snapshot_data() == nullptr); + is_building_snapshot_buffer_[0] = is_building_snapshot ? 1 : 0; + is_building_snapshot_buffer_.MakeWeak(); +} + +bool BindingData::PrepareForSerialization(Local context, + v8::SnapshotCreator* creator) { + DCHECK_NULL(internal_field_info_); + internal_field_info_ = InternalFieldInfoBase::New(type()); + internal_field_info_->is_building_snapshot_buffer = + is_building_snapshot_buffer_.Serialize(context, creator); + // Return true because we need to maintain the reference to the binding from + // JS land. + return true; +} + +InternalFieldInfoBase* BindingData::Serialize(int index) { + DCHECK_EQ(index, BaseObject::kEmbedderType); + InternalFieldInfo* info = internal_field_info_; + internal_field_info_ = nullptr; + return info; +} + +void BindingData::Deserialize(Local context, + Local holder, + int index, + InternalFieldInfoBase* info) { + DCHECK_EQ(index, BaseObject::kEmbedderType); + v8::HandleScope scope(context->GetIsolate()); + Realm* realm = Realm::GetCurrent(context); + // Recreate the buffer in the constructor. + InternalFieldInfo* casted_info = static_cast(info); + BindingData* binding = + realm->AddBindingData(context, holder, casted_info); + CHECK_NOT_NULL(binding); +} + +void BindingData::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("is_building_snapshot_buffer", + is_building_snapshot_buffer_); +} + +void CreatePerContextProperties(Local target, + Local unused, + Local context, + void* priv) { + Realm* realm = Realm::GetCurrent(context); + realm->AddBindingData(context, target); +} + +void CreatePerIsolateProperties(IsolateData* isolate_data, + Local ctor) { + Isolate* isolate = isolate_data->isolate(); + Local target = ctor->PrototypeTemplate(); SetMethod( - context, target, "getEmbedderEntryFunction", GetEmbedderEntryFunction); - SetMethod(context, target, "compileSerializeMain", CompileSerializeMain); - SetMethod(context, target, "setSerializeCallback", SetSerializeCallback); - SetMethod(context, target, "setDeserializeCallback", SetDeserializeCallback); - SetMethod(context, + isolate, target, "getEmbedderEntryFunction", GetEmbedderEntryFunction); + SetMethod(isolate, target, "compileSerializeMain", CompileSerializeMain); + SetMethod(isolate, target, "setSerializeCallback", SetSerializeCallback); + SetMethod(isolate, target, "setDeserializeCallback", SetDeserializeCallback); + SetMethod(isolate, target, "setDeserializeMainFunction", SetDeserializeMainFunction); @@ -1274,8 +1347,12 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(SetDeserializeMainFunction); } } // namespace mksnapshot + } // namespace node -NODE_BINDING_CONTEXT_AWARE_INTERNAL(mksnapshot, node::mksnapshot::Initialize) +NODE_BINDING_CONTEXT_AWARE_INTERNAL( + mksnapshot, node::mksnapshot::CreatePerContextProperties) +NODE_BINDING_PER_ISOLATE_INIT(mksnapshot, + node::mksnapshot::CreatePerIsolateProperties) NODE_BINDING_EXTERNAL_REFERENCE(mksnapshot, node::mksnapshot::RegisterExternalReferences) diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index 28d9dd8c0aee14..eed572beef3a0c 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -4,6 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#include "aliased_buffer.h" #include "base_object.h" #include "util.h" @@ -121,6 +122,31 @@ void DeserializeNodeInternalFields(v8::Local holder, void SerializeSnapshotableObjects(Realm* realm, v8::SnapshotCreator* creator, RealmSerializeInfo* info); + +namespace mksnapshot { +class BindingData : public SnapshotableObject { + public: + struct InternalFieldInfo : public node::InternalFieldInfoBase { + AliasedBufferIndex is_building_snapshot_buffer; + }; + + BindingData(Realm* realm, + v8::Local obj, + InternalFieldInfo* info = nullptr); + SET_BINDING_ID(mksnapshot_binding_data) + SERIALIZABLE_OBJECT_METHODS() + + void MemoryInfo(MemoryTracker* tracker) const override; + SET_SELF_SIZE(BindingData) + SET_MEMORY_INFO_NAME(BindingData) + + private: + AliasedUint8Array is_building_snapshot_buffer_; + InternalFieldInfo* internal_field_info_ = nullptr; +}; + +} // namespace mksnapshot + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/node_worker.cc b/src/node_worker.cc index 2bb5bdf569ebef..ed966073ec7286 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -186,6 +186,7 @@ class WorkerThreadData { allocator.get(), w->snapshot_data()->AsEmbedderWrapper().get())); CHECK(isolate_data_); + CHECK(!isolate_data_->is_building_snapshot()); if (w_->per_isolate_opts_) isolate_data_->set_options(std::move(w_->per_isolate_opts_)); isolate_data_->set_worker_context(w_); @@ -481,6 +482,7 @@ void Worker::New(const FunctionCallbackInfo& args) { THROW_ERR_MISSING_PLATFORM_FOR_WORKER(env); return; } + CHECK(!env->isolate_data()->is_building_snapshot()); std::string url; std::string name;