Skip to content

Commit

Permalink
bootstrap: put is_building_snapshot state in IsolateData
Browse files Browse the repository at this point in the history
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: #47887
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
  • Loading branch information
joyeecheung authored and targos committed May 30, 2023
1 parent 8d93af3 commit c480559
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 18 deletions.
4 changes: 2 additions & 2 deletions lib/internal/v8/startup_snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions src/api/embed_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/base_object_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
4 changes: 4 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -219,6 +222,7 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
const SnapshotData* snapshot_data_;
std::shared_ptr<PerIsolateOptions> options_;
worker::Worker* worker_context_ = nullptr;
bool is_building_snapshot_ = false;
};

struct ContextInfo {
Expand Down
4 changes: 2 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ MaybeLocal<Value> 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";

Expand Down Expand Up @@ -311,7 +311,7 @@ MaybeLocal<Value> 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");
}

Expand Down
1 change: 1 addition & 0 deletions src/node_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
V(contextify) \
V(encoding_binding) \
V(fs) \
V(mksnapshot) \
V(timers) \
V(process_methods) \
V(performance) \
Expand Down
2 changes: 2 additions & 0 deletions src/node_main_instance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
101 changes: 89 additions & 12 deletions src/node_snapshotable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <iostream>
#include <sstream>
#include <vector>
#include "aliased_buffer-inl.h"
#include "base_object-inl.h"
#include "blob_serializer_deserializer-inl.h"
#include "debug_utils-inl.h"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1177,8 +1179,6 @@ void SerializeSnapshotableObjects(Realm* realm,
});
}

namespace mksnapshot {

// NB: This is also used by the regular embedding codepath.
void GetEmbedderEntryFunction(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Expand Down Expand Up @@ -1251,16 +1251,89 @@ void SetDeserializeMainFunction(const FunctionCallbackInfo<Value>& args) {
env->set_snapshot_deserialize_main(args[0].As<Function>());
}

void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
namespace mksnapshot {

BindingData::BindingData(Realm* realm,
v8::Local<v8::Object> 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> context,
v8::SnapshotCreator* creator) {
DCHECK_NULL(internal_field_info_);
internal_field_info_ = InternalFieldInfoBase::New<InternalFieldInfo>(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> context,
Local<Object> 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<InternalFieldInfo*>(info);
BindingData* binding =
realm->AddBindingData<BindingData>(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<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Realm* realm = Realm::GetCurrent(context);
realm->AddBindingData<BindingData>(context, target);
}

void CreatePerIsolateProperties(IsolateData* isolate_data,
Local<FunctionTemplate> ctor) {
Isolate* isolate = isolate_data->isolate();
Local<ObjectTemplate> 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);
Expand All @@ -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)
26 changes: 26 additions & 0 deletions src/node_snapshotable.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "aliased_buffer.h"
#include "base_object.h"
#include "util.h"

Expand Down Expand Up @@ -121,6 +122,31 @@ void DeserializeNodeInternalFields(v8::Local<v8::Object> 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<v8::Object> 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
Expand Down
2 changes: 2 additions & 0 deletions src/node_worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
Expand Down Expand Up @@ -481,6 +482,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
THROW_ERR_MISSING_PLATFORM_FOR_WORKER(env);
return;
}
CHECK(!env->isolate_data()->is_building_snapshot());

std::string url;
std::string name;
Expand Down

0 comments on commit c480559

Please sign in to comment.