Skip to content

Commit

Permalink
src: use v8::(Des|S)erializeInternalFieldsCallback
Browse files Browse the repository at this point in the history
Previously V8 would just try to serialize the context data fields
"verbatim" by copying the pointer values. This patch makes
use of the new callbacks so that at serialization, the embedder
data for the context can at least be serialized in a meaningful
way (which are all reset to empty for now). Otherwise the
upstream may have difficulties serializing these pointer values
"verbatim" especially with the introduction of external pointer
tables, even though the verbatim pointer values from a previous
process is meaningless to Node.js.

For Node.js the callback currently just checks that the slots are
know. We will reassign the pointers with newly created native
structures during deserialization and there isn't much we can
reuse for now.

PR-URL: #53217
Refs: https://chromium-review.googlesource.com/c/v8/v8/+/5512712/comments/cfc2b28d_c921ac80?tab=comments
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
  • Loading branch information
joyeecheung authored and RafaelGSS committed Jun 7, 2024
1 parent e66eb37 commit cb1329a
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,13 @@ Environment* CreateEnvironment(
if (use_snapshot) {
context = Context::FromSnapshot(isolate,
SnapshotData::kNodeMainContextIndex,
{DeserializeNodeInternalFields, env})
v8::DeserializeInternalFieldsCallback(
DeserializeNodeInternalFields, env),
nullptr,
MaybeLocal<Value>(),
nullptr,
v8::DeserializeContextDataCallback(
DeserializeNodeContextData, env))
.ToLocalChecked();

CHECK(!context.IsEmpty());
Expand Down
42 changes: 40 additions & 2 deletions src/node_snapshotable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1155,8 +1155,11 @@ ExitCode SnapshotBuilder::CreateSnapshot(SnapshotData* out,
CHECK_EQ(index, SnapshotData::kNodeVMContextIndex);
index = creator->AddContext(base_context);
CHECK_EQ(index, SnapshotData::kNodeBaseContextIndex);
index = creator->AddContext(main_context,
{SerializeNodeContextInternalFields, env});
index = creator->AddContext(
main_context,
v8::SerializeInternalFieldsCallback(SerializeNodeContextInternalFields,
env),
v8::SerializeContextDataCallback(SerializeNodeContextData, env));
CHECK_EQ(index, SnapshotData::kNodeMainContextIndex);
}

Expand Down Expand Up @@ -1255,6 +1258,41 @@ std::string SnapshotableObject::GetTypeName() const {
}
}

void DeserializeNodeContextData(Local<Context> holder,
int index,
StartupData payload,
void* callback_data) {
// This is unreachable for now. We will reset all the pointers in
// Environment::AssignToContext() via the realm constructor.
UNREACHABLE();
}

StartupData SerializeNodeContextData(Local<Context> holder,
int index,
void* callback_data) {
// For now we just reset all of them in Environment::AssignToContext().
// We return empty data here to make sure that the embedder data serialized
// into the snapshot is reproducible and V8 doesn't have to try to serialize
// the pointer values that won't be useful during deserialization.
switch (index) {
case ContextEmbedderIndex::kEnvironment:
case ContextEmbedderIndex::kContextifyContext:
case ContextEmbedderIndex::kRealm:
case ContextEmbedderIndex::kContextTag: {
void* data = holder->GetAlignedPointerFromEmbedderData(index);
per_process::Debug(
DebugCategory::MKSNAPSHOT,
"Serialize context data, index=%d, holder=%p, ptr=%p\n",
static_cast<int>(index),
*holder,
data);
return {nullptr, 0};
}
default:
UNREACHABLE();
}
}

void DeserializeNodeInternalFields(Local<Object> holder,
int index,
StartupData payload,
Expand Down
7 changes: 7 additions & 0 deletions src/node_snapshotable.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,17 @@ class SnapshotableObject : public BaseObject {
v8::StartupData SerializeNodeContextInternalFields(v8::Local<v8::Object> holder,
int index,
void* env);
v8::StartupData SerializeNodeContextData(v8::Local<v8::Context> holder,
int index,
void* env);
void DeserializeNodeInternalFields(v8::Local<v8::Object> holder,
int index,
v8::StartupData payload,
void* env);
void DeserializeNodeContextData(v8::Local<v8::Context> holder,
int index,
v8::StartupData payload,
void* env);
void SerializeSnapshotableObjects(Realm* realm,
v8::SnapshotCreator* creator,
RealmSerializeInfo* info);
Expand Down

0 comments on commit cb1329a

Please sign in to comment.