src: per-isolate eternal template properties

`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: https://github.com/nodejs/node/pull/43802
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
legendecas
2022-07-23 11:20:07 +08:00
parent 5fbf33ef86
commit 50d0cd5123
5 changed files with 163 additions and 100 deletions

View File

@@ -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)
@@ -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

View File

@@ -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,
@@ -251,7 +285,8 @@ 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)
@@ -259,13 +294,27 @@ std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
#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)));
return indexes;
for (size_t i = 0; i < AsyncWrap::PROVIDERS_LENGTH; 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 info;
}
void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
size_t i = 0;
HandleScope handle_scope(isolate_);
@@ -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"); \
@@ -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() {
@@ -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
@@ -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);
}
}
@@ -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"
@@ -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(); \
@@ -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";
@@ -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"
@@ -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);

View File

@@ -469,7 +469,7 @@ class NoArrayBufferZeroFillScope {
V(x_forwarded_string, "x-forwarded-for") \
V(zero_return_string, "ZERO_RETURN")
#define ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) \
#define PER_ISOLATE_TEMPLATE_PROPERTIES(V) \
V(async_wrap_ctor_template, v8::FunctionTemplate) \
V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
V(base_object_ctor_template, v8::FunctionTemplate) \
@@ -575,17 +575,32 @@ class NoArrayBufferZeroFillScope {
class Environment;
typedef size_t SnapshotIndex;
struct PropInfo {
std::string name; // name for debugging
size_t id; // In the list - in case there are any empty entries
SnapshotIndex index; // In the snapshot
};
struct IsolateDataSerializeInfo {
std::vector<SnapshotIndex> primitive_values;
std::vector<PropInfo> template_values;
friend std::ostream& operator<<(std::ostream& o,
const IsolateDataSerializeInfo& i);
};
class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
public:
IsolateData(v8::Isolate* isolate,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform = nullptr,
ArrayBufferAllocator* node_allocator = nullptr,
const std::vector<size_t>* indexes = nullptr);
const IsolateDataSerializeInfo* isolate_data_info = nullptr);
SET_MEMORY_INFO_NAME(IsolateData)
SET_SELF_SIZE(IsolateData)
void MemoryInfo(MemoryTracker* tracker) const override;
std::vector<size_t> Serialize(v8::SnapshotCreator* creator);
IsolateDataSerializeInfo Serialize(v8::SnapshotCreator* creator);
inline uv_loop_t* event_loop() const;
inline MultiIsolatePlatform* platform() const;
@@ -609,6 +624,13 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
#undef VY
#undef VS
#undef VP
#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> PropertyName() const; \
inline void set_##PropertyName(v8::Local<TypeName> value);
PER_ISOLATE_TEMPLATE_PROPERTIES(V)
#undef V
inline v8::Local<v8::String> async_wrap_provider(int index) const;
size_t max_young_gen_size = 1;
@@ -621,20 +643,24 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
IsolateData& operator=(IsolateData&&) = delete;
private:
void DeserializeProperties(const std::vector<size_t>* indexes);
void DeserializeProperties(const IsolateDataSerializeInfo* isolate_data_info);
void CreateProperties();
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define VT(PropertyName, TypeName) V(TypeName, PropertyName)
#define V(TypeName, PropertyName) \
v8::Eternal<TypeName> PropertyName ## _;
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
PER_ISOLATE_TEMPLATE_PROPERTIES(VT)
#undef V
#undef VY
#undef V
#undef VT
#undef VS
#undef VY
#undef VP
// Keep a list of all Persistent strings used for AsyncWrap Provider types.
std::array<v8::Eternal<v8::String>, AsyncWrap::PROVIDERS_LENGTH>
@@ -925,12 +951,6 @@ class CleanupHookCallback {
uint64_t insertion_order_counter_;
};
struct PropInfo {
std::string name; // name for debugging
size_t id; // In the list - in case there are any empty entries
SnapshotIndex index; // In the snapshot
};
typedef void (*DeserializeRequestCallback)(v8::Local<v8::Context> context,
v8::Local<v8::Object> holder,
int index,
@@ -955,7 +975,6 @@ struct EnvSerializeInfo {
AliasedBufferIndex stream_base_state;
AliasedBufferIndex should_abort_on_uncaught_toggle;
std::vector<PropInfo> persistent_templates;
std::vector<PropInfo> persistent_values;
SnapshotIndex context;
@@ -974,7 +993,7 @@ struct SnapshotData {
// building process.
v8::StartupData v8_snapshot_blob_data{nullptr, 0};
std::vector<size_t> isolate_data_indices;
IsolateDataSerializeInfo isolate_data_info;
// TODO(joyeecheung): there should be a vector of env_info once we snapshot
// the worker environments.
EnvSerializeInfo env_info;
@@ -1342,8 +1361,8 @@ class Environment : public MemoryRetainer {
#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> PropertyName() const; \
inline void set_ ## PropertyName(v8::Local<TypeName> value);
PER_ISOLATE_TEMPLATE_PROPERTIES(V)
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
#undef V
inline v8::Local<v8::Context> context() const;
@@ -1646,7 +1665,6 @@ class Environment : public MemoryRetainer {
#define V(PropertyName, TypeName) v8::Global<TypeName> PropertyName ## _;
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
#undef V
v8::Global<v8::Context> context_;

View File

@@ -89,8 +89,7 @@ NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
event_loop,
platform,
array_buffer_allocator_.get(),
snapshot_data == nullptr ? nullptr
: &(snapshot_data->isolate_data_indices));
snapshot_data == nullptr ? nullptr : &(snapshot_data->isolate_data_info));
IsolateSettings s;
SetIsolateMiscHandlers(isolate_, s);
if (snapshot_data == nullptr) {

View File

@@ -126,13 +126,10 @@ static const int v8_snapshot_blob_size = )"
{ v8_snapshot_blob_data, v8_snapshot_blob_size },
// -- v8_snapshot_blob_data ends --
// -- isolate_data_indices begins --
{
)";
WriteVector(&ss,
data->isolate_data_indices.data(),
data->isolate_data_indices.size());
ss << R"(},
)" << data->isolate_data_info
<< R"(
// -- isolate_data_indices ends --
,
// -- env_info begins --
)" << data->env_info
<< R"(
@@ -222,9 +219,6 @@ int SnapshotBuilder::Generate(SnapshotData* out,
}
});
out->isolate_data_indices =
main_instance->isolate_data()->Serialize(&creator);
// The default context with only things created by V8.
Local<Context> default_context = Context::New(isolate);
@@ -285,6 +279,8 @@ int SnapshotBuilder::Generate(SnapshotData* out,
}
// Serialize the native states
out->isolate_data_info =
main_instance->isolate_data()->Serialize(&creator);
out->env_info = env->Serialize(&creator);
#ifdef NODE_USE_NODE_CODE_CACHE