Skip to content

Commit

Permalink
src: per-isolate eternal template properties
Browse files Browse the repository at this point in the history
`FunctionTemplate` and `ObjectTemplate` can be shared across realms.
They should be per-isolate eternal handles and can not be modified.

As these templates are lazily initialized, their setters are still
exposed with DCHECK on their value presence.

PR-URL: nodejs#43802
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
  • Loading branch information
legendecas authored and Fyko committed Sep 15, 2022
1 parent fd7bcc8 commit def00f8
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 99 deletions.
34 changes: 27 additions & 7 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,16 @@ void Environment::set_process_exit_handler(
#undef VY
#undef VP

#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> IsolateData::PropertyName() const { \
return PropertyName##_.Get(isolate_); \
} \
inline void IsolateData::set_##PropertyName(v8::Local<TypeName> value) { \
PropertyName##_.Set(isolate_, value); \
}
PER_ISOLATE_TEMPLATE_PROPERTIES(V)
#undef V

#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
Expand All @@ -891,14 +901,24 @@ void Environment::set_process_exit_handler(
#undef VY
#undef VP

#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> Environment::PropertyName() const { \
return PersistentToLocal::Strong(PropertyName ## _); \
} \
inline void Environment::set_ ## PropertyName(v8::Local<TypeName> value) { \
PropertyName ## _.Reset(isolate(), value); \
#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> Environment::PropertyName() const { \
return isolate_data()->PropertyName(); \
} \
inline void Environment::set_##PropertyName(v8::Local<TypeName> value) { \
DCHECK(isolate_data()->PropertyName().IsEmpty()); \
isolate_data()->set_##PropertyName(value); \
}
PER_ISOLATE_TEMPLATE_PROPERTIES(V)
#undef V

#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> Environment::PropertyName() const { \
return PersistentToLocal::Strong(PropertyName##_); \
} \
inline void Environment::set_##PropertyName(v8::Local<TypeName> value) { \
PropertyName##_.Reset(isolate(), value); \
}
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
#undef V

Expand Down
162 changes: 96 additions & 66 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,43 @@ AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
: DefaultTriggerAsyncIdScope(async_wrap->env(),
async_wrap->get_async_id()) {}

std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
std::ostream& operator<<(std::ostream& output,
const std::vector<SnapshotIndex>& v) {
output << "{ ";
for (const SnapshotIndex i : v) {
output << i << ", ";
}
output << " }";
return output;
}

std::ostream& operator<<(std::ostream& output,
const std::vector<PropInfo>& vec) {
output << "{\n";
for (const auto& info : vec) {
output << " { \"" << info.name << "\", " << std::to_string(info.id) << ", "
<< std::to_string(info.index) << " },\n";
}
output << "}";
return output;
}

std::ostream& operator<<(std::ostream& output,
const IsolateDataSerializeInfo& i) {
output << "{\n"
<< "// -- primitive begins --\n"
<< i.primitive_values << ",\n"
<< "// -- primitive ends --\n"
<< "// -- template_values begins --\n"
<< i.template_values << ",\n"
<< "// -- template_values ends --\n"
<< "}";
return output;
}

IsolateDataSerializeInfo IsolateData::Serialize(SnapshotCreator* creator) {
Isolate* isolate = creator->GetIsolate();
std::vector<size_t> indexes;
IsolateDataSerializeInfo info;
HandleScope handle_scope(isolate);
// XXX(joyeecheung): technically speaking, the indexes here should be
// consecutive and we could just return a range instead of an array,
Expand All @@ -251,21 +285,36 @@ std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(String, PropertyName)
#define V(TypeName, PropertyName) \
indexes.push_back(creator->AddData(PropertyName##_.Get(isolate)));
info.primitive_values.push_back( \
creator->AddData(PropertyName##_.Get(isolate)));
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V
#undef VY
#undef VS
#undef VP

for (size_t i = 0; i < AsyncWrap::PROVIDERS_LENGTH; i++)
indexes.push_back(creator->AddData(async_wrap_provider(i)));
info.primitive_values.push_back(creator->AddData(async_wrap_provider(i)));

size_t id = 0;
#define V(PropertyName, TypeName) \
do { \
Local<TypeName> field = PropertyName(); \
if (!field.IsEmpty()) { \
size_t index = creator->AddData(field); \
info.template_values.push_back({#PropertyName, id, index}); \
} \
id++; \
} while (0);
PER_ISOLATE_TEMPLATE_PROPERTIES(V)
#undef V

return indexes;
return info;
}

void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
size_t i = 0;
HandleScope handle_scope(isolate_);

Expand All @@ -275,7 +324,8 @@ void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
#define V(TypeName, PropertyName) \
do { \
MaybeLocal<TypeName> maybe_field = \
isolate_->GetDataFromSnapshotOnce<TypeName>((*indexes)[i++]); \
isolate_->GetDataFromSnapshotOnce<TypeName>( \
info->primitive_values[i++]); \
Local<TypeName> field; \
if (!maybe_field.ToLocal(&field)) { \
fprintf(stderr, "Failed to deserialize " #PropertyName "\n"); \
Expand All @@ -292,13 +342,38 @@ void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {

for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) {
MaybeLocal<String> maybe_field =
isolate_->GetDataFromSnapshotOnce<String>((*indexes)[i++]);
isolate_->GetDataFromSnapshotOnce<String>(info->primitive_values[i++]);
Local<String> field;
if (!maybe_field.ToLocal(&field)) {
fprintf(stderr, "Failed to deserialize AsyncWrap provider %zu\n", j);
}
async_wrap_providers_[j].Set(isolate_, field);
}

const std::vector<PropInfo>& values = info->template_values;
i = 0; // index to the array
size_t id = 0;
#define V(PropertyName, TypeName) \
do { \
if (values.size() > i && id == values[i].id) { \
const PropInfo& d = values[i]; \
DCHECK_EQ(d.name, #PropertyName); \
MaybeLocal<TypeName> maybe_field = \
isolate_->GetDataFromSnapshotOnce<TypeName>(d.index); \
Local<TypeName> field; \
if (!maybe_field.ToLocal(&field)) { \
fprintf(stderr, \
"Failed to deserialize isolate data template " #PropertyName \
"\n"); \
} \
set_##PropertyName(field); \
i++; \
} \
id++; \
} while (0);

PER_ISOLATE_TEMPLATE_PROPERTIES(V);
#undef V
}

void IsolateData::CreateProperties() {
Expand Down Expand Up @@ -363,13 +438,15 @@ void IsolateData::CreateProperties() {
sizeof(#Provider) - 1).ToLocalChecked());
NODE_ASYNC_PROVIDER_TYPES(V)
#undef V

// TODO(legendecas): eagerly create per isolate templates.
}

IsolateData::IsolateData(Isolate* isolate,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform,
ArrayBufferAllocator* node_allocator,
const std::vector<size_t>* indexes)
const IsolateDataSerializeInfo* isolate_data_info)
: isolate_(isolate),
event_loop_(event_loop),
node_allocator_(node_allocator == nullptr ? nullptr
Expand All @@ -378,10 +455,10 @@ IsolateData::IsolateData(Isolate* isolate,
options_.reset(
new PerIsolateOptions(*(per_process::cli_options->per_isolate)));

if (indexes == nullptr) {
if (isolate_data_info == nullptr) {
CreateProperties();
} else {
DeserializeProperties(indexes);
DeserializeProperties(isolate_data_info);
}
}

Expand Down Expand Up @@ -1528,16 +1605,6 @@ void AsyncHooks::Deserialize(Local<Context> context) {
info_ = nullptr;
}

std::ostream& operator<<(std::ostream& output,
const std::vector<SnapshotIndex>& v) {
output << "{ ";
for (const SnapshotIndex i : v) {
output << i << ", ";
}
output << " }";
return output;
}

std::ostream& operator<<(std::ostream& output,
const AsyncHooks::SerializeInfo& i) {
output << "{\n"
Expand Down Expand Up @@ -1749,19 +1816,6 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
should_abort_on_uncaught_toggle_.Serialize(ctx, creator);

size_t id = 0;
#define V(PropertyName, TypeName) \
do { \
Local<TypeName> field = PropertyName(); \
if (!field.IsEmpty()) { \
size_t index = creator->AddData(field); \
info.persistent_templates.push_back({#PropertyName, id, index}); \
} \
id++; \
} while (0);
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
#undef V

id = 0;
#define V(PropertyName, TypeName) \
do { \
Local<TypeName> field = PropertyName(); \
Expand All @@ -1778,17 +1832,6 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
return info;
}

std::ostream& operator<<(std::ostream& output,
const std::vector<PropInfo>& vec) {
output << "{\n";
for (const auto& info : vec) {
output << " { \"" << info.name << "\", " << std::to_string(info.id) << ", "
<< std::to_string(info.index) << " },\n";
}
output << "}";
return output;
}

std::ostream& operator<<(std::ostream& output,
const std::vector<std::string>& vec) {
output << "{\n";
Expand Down Expand Up @@ -1818,9 +1861,6 @@ std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
<< i.stream_base_state << ", // stream_base_state\n"
<< i.should_abort_on_uncaught_toggle
<< ", // should_abort_on_uncaught_toggle\n"
<< "// -- persistent_templates begins --\n"
<< i.persistent_templates << ",\n"
<< "// persistent_templates ends --\n"
<< "// -- persistent_values begins --\n"
<< i.persistent_values << ",\n"
<< "// -- persistent_values ends --\n"
Expand Down Expand Up @@ -1869,40 +1909,30 @@ void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
std::cerr << *info << "\n";
}

const std::vector<PropInfo>& templates = info->persistent_templates;
const std::vector<PropInfo>& values = info->persistent_values;
size_t i = 0; // index to the array
size_t id = 0;
#define SetProperty(PropertyName, TypeName, vector, type, from) \
#define V(PropertyName, TypeName) \
do { \
if (vector.size() > i && id == vector[i].id) { \
const PropInfo& d = vector[i]; \
if (values.size() > i && id == values[i].id) { \
const PropInfo& d = values[i]; \
DCHECK_EQ(d.name, #PropertyName); \
MaybeLocal<TypeName> maybe_field = \
from->GetDataFromSnapshotOnce<TypeName>(d.index); \
ctx->GetDataFromSnapshotOnce<TypeName>(d.index); \
Local<TypeName> field; \
if (!maybe_field.ToLocal(&field)) { \
fprintf(stderr, \
"Failed to deserialize environment " #type " " #PropertyName \
"Failed to deserialize environment value " #PropertyName \
"\n"); \
} \
set_##PropertyName(field); \
i++; \
} \
} while (0); \
id++;
#define V(PropertyName, TypeName) SetProperty(PropertyName, TypeName, \
templates, template, isolate_)
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V);
#undef V
id++; \
} while (0);

i = 0; // index to the array
id = 0;
const std::vector<PropInfo>& values = info->persistent_values;
#define V(PropertyName, TypeName) SetProperty(PropertyName, TypeName, \
values, value, ctx)
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V);
#undef V
#undef SetProperty

MaybeLocal<Context> maybe_ctx_from_snapshot =
ctx->GetDataFromSnapshotOnce<Context>(info->context);
Expand Down
Loading

0 comments on commit def00f8

Please sign in to comment.