Skip to content

Commit 631bea8

Browse files
joyeecheungtargos
authored andcommitted
src: implement IsolateData serialization and deserialization
This patch allows serializing per-isolate data into an isolate snapshot and deserializing them from an isolate snapthot. PR-URL: #27321 Refs: #17058 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent a636338 commit 631bea8

File tree

4 files changed

+149
-50
lines changed

4 files changed

+149
-50
lines changed

src/env.cc

Lines changed: 104 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using v8::NewStringType;
3737
using v8::Number;
3838
using v8::Object;
3939
using v8::Private;
40+
using v8::SnapshotCreator;
4041
using v8::StackTrace;
4142
using v8::String;
4243
using v8::Symbol;
@@ -49,22 +50,58 @@ int const Environment::kNodeContextTag = 0x6e6f64;
4950
void* const Environment::kNodeContextTagPtr = const_cast<void*>(
5051
static_cast<const void*>(&Environment::kNodeContextTag));
5152

52-
IsolateData::IsolateData(Isolate* isolate,
53-
uv_loop_t* event_loop,
54-
MultiIsolatePlatform* platform,
55-
ArrayBufferAllocator* node_allocator)
56-
: isolate_(isolate),
57-
event_loop_(event_loop),
58-
allocator_(isolate->GetArrayBufferAllocator()),
59-
node_allocator_(node_allocator == nullptr ?
60-
nullptr : node_allocator->GetImpl()),
61-
uses_node_allocator_(allocator_ == node_allocator_),
62-
platform_(platform) {
63-
CHECK_NOT_NULL(allocator_);
53+
std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
54+
Isolate* isolate = creator->GetIsolate();
55+
std::vector<size_t> indexes;
56+
HandleScope handle_scope(isolate);
57+
// XXX(joyeecheung): technically speaking, the indexes here should be
58+
// consecutive and we could just return a range instead of an array,
59+
// but that's not part of the V8 API contract so we use an array
60+
// just to be safe.
61+
62+
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
63+
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
64+
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
65+
#define V(TypeName, PropertyName) \
66+
indexes.push_back(creator->AddData(PropertyName##_.Get(isolate)));
67+
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
68+
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
69+
PER_ISOLATE_STRING_PROPERTIES(VS)
70+
#undef V
71+
#undef VY
72+
#undef VS
73+
#undef VP
6474

65-
options_.reset(
66-
new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
75+
return indexes;
76+
}
6777

78+
void IsolateData::DeserializeProperties(
79+
const NodeMainInstance::IndexArray* indexes) {
80+
size_t i = 0;
81+
HandleScope handle_scope(isolate_);
82+
83+
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
84+
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
85+
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
86+
#define V(TypeName, PropertyName) \
87+
do { \
88+
MaybeLocal<TypeName> field = \
89+
isolate_->GetDataFromSnapshotOnce<TypeName>(indexes->Get(i++)); \
90+
if (field.IsEmpty()) { \
91+
fprintf(stderr, "Failed to deserialize " #PropertyName "\n"); \
92+
} \
93+
PropertyName##_.Set(isolate_, field.ToLocalChecked()); \
94+
} while (0);
95+
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
96+
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
97+
PER_ISOLATE_STRING_PROPERTIES(VS)
98+
#undef V
99+
#undef VY
100+
#undef VS
101+
#undef VP
102+
}
103+
104+
void IsolateData::CreateProperties() {
68105
// Create string and private symbol properties as internalized one byte
69106
// strings after the platform is properly initialized.
70107
//
@@ -76,44 +113,68 @@ IsolateData::IsolateData(Isolate* isolate,
76113
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
77114
// decoding step.
78115

79-
HandleScope handle_scope(isolate);
116+
HandleScope handle_scope(isolate_);
80117

81-
#define V(PropertyName, StringValue) \
82-
PropertyName ## _.Set( \
83-
isolate, \
84-
Private::New( \
85-
isolate, \
86-
String::NewFromOneByte( \
87-
isolate, \
88-
reinterpret_cast<const uint8_t*>(StringValue), \
89-
NewStringType::kInternalized, \
90-
sizeof(StringValue) - 1).ToLocalChecked()));
118+
#define V(PropertyName, StringValue) \
119+
PropertyName##_.Set( \
120+
isolate_, \
121+
Private::New(isolate_, \
122+
String::NewFromOneByte( \
123+
isolate_, \
124+
reinterpret_cast<const uint8_t*>(StringValue), \
125+
NewStringType::kInternalized, \
126+
sizeof(StringValue) - 1) \
127+
.ToLocalChecked()));
91128
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
92129
#undef V
93-
#define V(PropertyName, StringValue) \
94-
PropertyName ## _.Set( \
95-
isolate, \
96-
Symbol::New( \
97-
isolate, \
98-
String::NewFromOneByte( \
99-
isolate, \
100-
reinterpret_cast<const uint8_t*>(StringValue), \
101-
NewStringType::kInternalized, \
102-
sizeof(StringValue) - 1).ToLocalChecked()));
130+
#define V(PropertyName, StringValue) \
131+
PropertyName##_.Set( \
132+
isolate_, \
133+
Symbol::New(isolate_, \
134+
String::NewFromOneByte( \
135+
isolate_, \
136+
reinterpret_cast<const uint8_t*>(StringValue), \
137+
NewStringType::kInternalized, \
138+
sizeof(StringValue) - 1) \
139+
.ToLocalChecked()));
103140
PER_ISOLATE_SYMBOL_PROPERTIES(V)
104141
#undef V
105-
#define V(PropertyName, StringValue) \
106-
PropertyName ## _.Set( \
107-
isolate, \
108-
String::NewFromOneByte( \
109-
isolate, \
110-
reinterpret_cast<const uint8_t*>(StringValue), \
111-
NewStringType::kInternalized, \
112-
sizeof(StringValue) - 1).ToLocalChecked());
142+
#define V(PropertyName, StringValue) \
143+
PropertyName##_.Set( \
144+
isolate_, \
145+
String::NewFromOneByte(isolate_, \
146+
reinterpret_cast<const uint8_t*>(StringValue), \
147+
NewStringType::kInternalized, \
148+
sizeof(StringValue) - 1) \
149+
.ToLocalChecked());
113150
PER_ISOLATE_STRING_PROPERTIES(V)
114151
#undef V
115152
}
116153

154+
IsolateData::IsolateData(Isolate* isolate,
155+
uv_loop_t* event_loop,
156+
MultiIsolatePlatform* platform,
157+
ArrayBufferAllocator* node_allocator,
158+
const NodeMainInstance::IndexArray* indexes)
159+
: isolate_(isolate),
160+
event_loop_(event_loop),
161+
allocator_(isolate->GetArrayBufferAllocator()),
162+
node_allocator_(node_allocator == nullptr ? nullptr
163+
: node_allocator->GetImpl()),
164+
uses_node_allocator_(allocator_ == node_allocator_),
165+
platform_(platform) {
166+
CHECK_NOT_NULL(allocator_);
167+
168+
options_.reset(
169+
new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
170+
171+
if (indexes == nullptr) {
172+
CreateProperties();
173+
} else {
174+
DeserializeProperties(indexes);
175+
}
176+
}
177+
117178
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
118179
#define V(PropertyName, StringValue) \
119180
tracker->TrackField(#PropertyName, PropertyName(isolate()));

src/env.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "node.h"
3434
#include "node_binding.h"
3535
#include "node_http2_state.h"
36+
#include "node_main_instance.h"
3637
#include "node_options.h"
3738
#include "req_wrap.h"
3839
#include "util.h"
@@ -418,10 +419,12 @@ class IsolateData : public MemoryRetainer {
418419
IsolateData(v8::Isolate* isolate,
419420
uv_loop_t* event_loop,
420421
MultiIsolatePlatform* platform = nullptr,
421-
ArrayBufferAllocator* node_allocator = nullptr);
422+
ArrayBufferAllocator* node_allocator = nullptr,
423+
const NodeMainInstance::IndexArray* indexes = nullptr);
422424
SET_MEMORY_INFO_NAME(IsolateData);
423425
SET_SELF_SIZE(IsolateData);
424426
void MemoryInfo(MemoryTracker* tracker) const override;
427+
std::vector<size_t> Serialize(v8::SnapshotCreator* creator);
425428

426429
inline uv_loop_t* event_loop() const;
427430
inline MultiIsolatePlatform* platform() const;
@@ -451,6 +454,9 @@ class IsolateData : public MemoryRetainer {
451454
IsolateData& operator=(const IsolateData&) = delete;
452455

453456
private:
457+
void DeserializeProperties(const NodeMainInstance::IndexArray* indexes);
458+
void CreateProperties();
459+
454460
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
455461
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
456462
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)

src/node_main_instance.cc

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ NodeMainInstance::NodeMainInstance(Isolate* isolate,
2323
isolate_(isolate),
2424
platform_(platform),
2525
isolate_data_(nullptr),
26-
owns_isolate_(false) {
26+
owns_isolate_(false),
27+
deserialize_mode_(false) {
2728
isolate_data_.reset(new IsolateData(isolate_, event_loop, platform, nullptr));
2829
SetIsolateUpForNode(isolate_, IsolateSettingCategories::kMisc);
2930
}
@@ -41,7 +42,8 @@ NodeMainInstance::NodeMainInstance(Isolate::CreateParams* params,
4142
uv_loop_t* event_loop,
4243
MultiIsolatePlatform* platform,
4344
const std::vector<std::string>& args,
44-
const std::vector<std::string>& exec_args)
45+
const std::vector<std::string>& exec_args,
46+
const IndexArray* per_isolate_data_indexes)
4547
: args_(args),
4648
exec_args_(exec_args),
4749
array_buffer_allocator_(ArrayBufferAllocator::Create()),
@@ -58,10 +60,20 @@ NodeMainInstance::NodeMainInstance(Isolate::CreateParams* params,
5860
SetIsolateCreateParamsForNode(params);
5961
Isolate::Initialize(isolate_, *params);
6062

61-
isolate_data_.reset(new IsolateData(
62-
isolate_, event_loop, platform, array_buffer_allocator_.get()));
63+
deserialize_mode_ = per_isolate_data_indexes != nullptr;
64+
// If the indexes are not nullptr, we are not deserializing
65+
CHECK_IMPLIES(deserialize_mode_, params->external_references != nullptr);
66+
isolate_data_.reset(new IsolateData(isolate_,
67+
event_loop,
68+
platform,
69+
array_buffer_allocator_.get(),
70+
per_isolate_data_indexes));
6371
SetIsolateUpForNode(isolate_, IsolateSettingCategories::kMisc);
64-
SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers);
72+
if (!deserialize_mode_) {
73+
// If in deserialize mode, delay until after the deserialization is
74+
// complete.
75+
SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers);
76+
}
6577
}
6678

6779
void NodeMainInstance::Dispose() {
@@ -160,6 +172,9 @@ std::unique_ptr<Environment> NodeMainInstance::CreateMainEnvironment(
160172
}
161173

162174
Local<Context> context = NewContext(isolate_);
175+
if (deserialize_mode_) {
176+
SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers);
177+
}
163178
CHECK(!context.IsEmpty());
164179
Context::Scope context_scope(context);
165180

src/node_main_instance.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ namespace node {
1515
// We may be able to create an abstract class to reuse some of the routines.
1616
class NodeMainInstance {
1717
public:
18+
// An array of indexes that can be used to deserialize data from a V8
19+
// snapshot.
20+
struct IndexArray {
21+
const size_t* data;
22+
size_t length;
23+
24+
size_t Get(size_t index) const {
25+
DCHECK_LT(index, length);
26+
return data[index];
27+
}
28+
};
29+
1830
// To create a main instance that does not own the isoalte,
1931
// The caller needs to do:
2032
//
@@ -45,12 +57,15 @@ class NodeMainInstance {
4557
uv_loop_t* event_loop,
4658
MultiIsolatePlatform* platform,
4759
const std::vector<std::string>& args,
48-
const std::vector<std::string>& exec_args);
60+
const std::vector<std::string>& exec_args,
61+
const IndexArray* per_isolate_data_indexes = nullptr);
4962
~NodeMainInstance();
5063

5164
// Start running the Node.js instances, return the exit code when finished.
5265
int Run();
5366

67+
IsolateData* isolate_data() { return isolate_data_.get(); }
68+
5469
// TODO(joyeecheung): align this with the CreateEnvironment exposed in node.h
5570
// and the environment creation routine in workers somehow.
5671
std::unique_ptr<Environment> CreateMainEnvironment(int* exit_code);
@@ -66,13 +81,15 @@ class NodeMainInstance {
6681
MultiIsolatePlatform* platform,
6782
const std::vector<std::string>& args,
6883
const std::vector<std::string>& exec_args);
84+
6985
std::vector<std::string> args_;
7086
std::vector<std::string> exec_args_;
7187
std::unique_ptr<ArrayBufferAllocator> array_buffer_allocator_;
7288
v8::Isolate* isolate_;
7389
MultiIsolatePlatform* platform_;
7490
std::unique_ptr<IsolateData> isolate_data_;
7591
bool owns_isolate_ = false;
92+
bool deserialize_mode_ = false;
7693
};
7794

7895
} // namespace node

0 commit comments

Comments
 (0)