Skip to content

Commit b2405e9

Browse files
joyeecheungjasnell
authored andcommitted
src: migrate from deprecated SnapshotCreator constructor
Previously we have been using the variant of SnapshotCreator that only passes the external references instead of v8::Isolate::CreateParams and it's about to be deprecated. Switch to using the new constructor that takes a fully CreateParams instead. This also makes sure that the snapshot building script is using the Node.js array buffer allocator instead of a separate default one that was previously used by the old constructor. The zero fill toggle in the Node.js array buffer allocator would still be ignored during snapshot building, however, until we fixes the array buffer allocator and let V8 own the toggle backing store instead, because otherwise the snapshot would contain the external toggle address and become unreproducible. PR-URL: #55337 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 11bb7cd commit b2405e9

File tree

5 files changed

+59
-26
lines changed

5 files changed

+59
-26
lines changed

lib/internal/buffer.js

+18-10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ const {
3939
},
4040
} = internalBinding('util');
4141

42+
const {
43+
namespace: {
44+
isBuildingSnapshot,
45+
},
46+
addAfterUserSerializeCallback,
47+
} = require('internal/v8/startup_snapshot');
48+
4249
// Temporary buffers to convert numbers.
4350
const float32Array = new Float32Array(1);
4451
const uInt8Float32Array = new Uint8Array(float32Array.buffer);
@@ -1090,8 +1097,18 @@ function isMarkedAsUntransferable(obj) {
10901097
// in C++.
10911098
// |zeroFill| can be undefined when running inside an isolate where we
10921099
// do not own the ArrayBuffer allocator. Zero fill is always on in that case.
1093-
let zeroFill = getZeroFillToggle();
1100+
let zeroFill;
10941101
function createUnsafeBuffer(size) {
1102+
if (!zeroFill) {
1103+
zeroFill = getZeroFillToggle();
1104+
if (isBuildingSnapshot()) {
1105+
// Reset the toggle so that after serialization, we'll re-create a real
1106+
// toggle connected to the C++ one via getZeroFillToggle().
1107+
addAfterUserSerializeCallback(() => {
1108+
zeroFill = undefined;
1109+
});
1110+
}
1111+
}
10951112
zeroFill[0] = 0;
10961113
try {
10971114
return new FastBuffer(size);
@@ -1100,14 +1117,6 @@ function createUnsafeBuffer(size) {
11001117
}
11011118
}
11021119

1103-
// The connection between the JS land zero fill toggle and the
1104-
// C++ one in the NodeArrayBufferAllocator gets lost if the toggle
1105-
// is deserialized from the snapshot, because V8 owns the underlying
1106-
// memory of this toggle. This resets the connection.
1107-
function reconnectZeroFillToggle() {
1108-
zeroFill = getZeroFillToggle();
1109-
}
1110-
11111120
module.exports = {
11121121
FastBuffer,
11131122
addBufferPrototypeMethods,
@@ -1116,5 +1125,4 @@ module.exports = {
11161125
createUnsafeBuffer,
11171126
readUInt16BE,
11181127
readUInt32BE,
1119-
reconnectZeroFillToggle,
11201128
};

lib/internal/process/pre_execution.js

-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const {
2121
refreshOptions,
2222
getEmbedderOptions,
2323
} = require('internal/options');
24-
const { reconnectZeroFillToggle } = require('internal/buffer');
2524
const {
2625
exposeLazyInterfaces,
2726
defineReplaceableLazyAttribute,
@@ -91,7 +90,6 @@ function prepareExecution(options) {
9190
const { expandArgv1, initializeModules, isMainThread } = options;
9291

9392
refreshRuntimeOptions();
94-
reconnectZeroFillToggle();
9593

9694
// Patch the process object and get the resolved main entry point.
9795
const mainEntry = patchProcessObject(expandArgv1);

src/api/embed_helpers.cc

+29-11
Original file line numberDiff line numberDiff line change
@@ -110,22 +110,40 @@ CommonEnvironmentSetup::CommonEnvironmentSetup(
110110
}
111111
loop->data = this;
112112

113+
impl_->allocator = ArrayBufferAllocator::Create();
114+
const std::vector<intptr_t>& external_references =
115+
SnapshotBuilder::CollectExternalReferences();
116+
Isolate::CreateParams params;
117+
params.array_buffer_allocator = impl_->allocator.get();
118+
params.external_references = external_references.data();
119+
params.external_references = external_references.data();
120+
params.cpp_heap =
121+
v8::CppHeap::Create(platform, v8::CppHeapCreateParams{{}}).release();
122+
113123
Isolate* isolate;
124+
125+
// Isolates created for snapshotting should be set up differently since
126+
// it will be owned by the snapshot creator and needs to be cleaned up
127+
// before serialization.
114128
if (flags & Flags::kIsForSnapshotting) {
115-
const std::vector<intptr_t>& external_references =
116-
SnapshotBuilder::CollectExternalReferences();
129+
// The isolate must be registered before the SnapshotCreator initializes the
130+
// isolate, so that the memory reducer can be initialized.
117131
isolate = impl_->isolate = Isolate::Allocate();
118-
// Must be done before the SnapshotCreator creation so that the
119-
// memory reducer can be initialized.
120132
platform->RegisterIsolate(isolate, loop);
121-
impl_->snapshot_creator.emplace(isolate, external_references.data());
133+
134+
impl_->snapshot_creator.emplace(isolate, params);
122135
isolate->SetCaptureStackTraceForUncaughtExceptions(
123-
true, 10, v8::StackTrace::StackTraceOptions::kDetailed);
136+
true,
137+
static_cast<int>(
138+
per_process::cli_options->per_isolate->stack_trace_limit),
139+
v8::StackTrace::StackTraceOptions::kDetailed);
124140
SetIsolateMiscHandlers(isolate, {});
125141
} else {
126-
impl_->allocator = ArrayBufferAllocator::Create();
127142
isolate = impl_->isolate =
128-
NewIsolate(impl_->allocator, &impl_->loop, platform, snapshot_data);
143+
NewIsolate(&params,
144+
&impl_->loop,
145+
platform,
146+
SnapshotData::FromEmbedderWrapper(snapshot_data));
129147
}
130148

131149
{
@@ -220,10 +238,10 @@ CommonEnvironmentSetup::~CommonEnvironmentSetup() {
220238
*static_cast<bool*>(data) = true;
221239
}, &platform_finished);
222240
impl_->platform->UnregisterIsolate(isolate);
223-
if (impl_->snapshot_creator.has_value())
241+
if (impl_->snapshot_creator.has_value()) {
224242
impl_->snapshot_creator.reset();
225-
else
226-
isolate->Dispose();
243+
}
244+
isolate->Dispose();
227245

228246
// Wait until the platform has cleaned up all relevant resources.
229247
while (!platform_finished)

src/node_buffer.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -1222,12 +1222,20 @@ void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
12221222
Local<ArrayBuffer> ab;
12231223
// It can be a nullptr when running inside an isolate where we
12241224
// do not own the ArrayBuffer allocator.
1225-
if (allocator == nullptr) {
1225+
if (allocator == nullptr || env->isolate_data()->is_building_snapshot()) {
12261226
// Create a dummy Uint32Array - the JS land can only toggle the C++ land
12271227
// setting when the allocator uses our toggle. With this the toggle in JS
12281228
// land results in no-ops.
1229+
// When building a snapshot, just use a dummy toggle as well to avoid
1230+
// introducing the dynamic external reference. We'll re-initialize the
1231+
// toggle with a real one connected to the C++ allocator after snapshot
1232+
// deserialization.
1233+
12291234
ab = ArrayBuffer::New(env->isolate(), sizeof(uint32_t));
12301235
} else {
1236+
// TODO(joyeecheung): save ab->GetBackingStore()->Data() in the Node.js
1237+
// array buffer allocator and include it into the C++ toggle while the
1238+
// Environment is still alive.
12311239
uint32_t* zero_fill_field = allocator->zero_fill_field();
12321240
std::unique_ptr<BackingStore> backing =
12331241
ArrayBuffer::NewBackingStore(zero_fill_field,

src/node_snapshotable.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -863,9 +863,10 @@ const std::vector<intptr_t>& SnapshotBuilder::CollectExternalReferences() {
863863

864864
void SnapshotBuilder::InitializeIsolateParams(const SnapshotData* data,
865865
Isolate::CreateParams* params) {
866-
CHECK_NULL(params->external_references);
867866
CHECK_NULL(params->snapshot_blob);
868-
params->external_references = CollectExternalReferences().data();
867+
if (params->external_references == nullptr) {
868+
params->external_references = CollectExternalReferences().data();
869+
}
869870
params->snapshot_blob =
870871
const_cast<v8::StartupData*>(&(data->v8_snapshot_blob_data));
871872
}

0 commit comments

Comments
 (0)