From def00f8df53c7366d9fe045b7870f5249b38162e Mon Sep 17 00:00:00 2001 From: legendecas Date: Sat, 23 Jul 2022 11:20:07 +0800 Subject: [PATCH] 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 Reviewed-By: Joyee Cheung --- src/env-inl.h | 34 ++++++-- src/env.cc | 162 ++++++++++++++++++++++---------------- src/env.h | 48 +++++++---- src/node_main_instance.cc | 3 +- src/node_snapshotable.cc | 14 ++-- 5 files changed, 162 insertions(+), 99 deletions(-) diff --git a/src/env-inl.h b/src/env-inl.h index 084cb9f83c51af..e2da40141d7740 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -876,6 +876,16 @@ void Environment::set_process_exit_handler( #undef VY #undef VP +#define V(PropertyName, TypeName) \ + inline v8::Local IsolateData::PropertyName() const { \ + return PropertyName##_.Get(isolate_); \ + } \ + inline void IsolateData::set_##PropertyName(v8::Local 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 Environment::PropertyName() const { \ - return PersistentToLocal::Strong(PropertyName ## _); \ - } \ - inline void Environment::set_ ## PropertyName(v8::Local value) { \ - PropertyName ## _.Reset(isolate(), value); \ +#define V(PropertyName, TypeName) \ + inline v8::Local Environment::PropertyName() const { \ + return isolate_data()->PropertyName(); \ + } \ + inline void Environment::set_##PropertyName(v8::Local 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 Environment::PropertyName() const { \ + return PersistentToLocal::Strong(PropertyName##_); \ + } \ + inline void Environment::set_##PropertyName(v8::Local value) { \ + PropertyName##_.Reset(isolate(), value); \ } - ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) #undef V diff --git a/src/env.cc b/src/env.cc index e4a708ec1de645..e775474306b746 100644 --- a/src/env.cc +++ b/src/env.cc @@ -238,9 +238,43 @@ AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope( : DefaultTriggerAsyncIdScope(async_wrap->env(), async_wrap->get_async_id()) {} -std::vector IsolateData::Serialize(SnapshotCreator* creator) { +std::ostream& operator<<(std::ostream& output, + const std::vector& v) { + output << "{ "; + for (const SnapshotIndex i : v) { + output << i << ", "; + } + output << " }"; + return output; +} + +std::ostream& operator<<(std::ostream& output, + const std::vector& 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 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 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 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))); + info.primitive_values.push_back(creator->AddData(async_wrap_provider(i))); + + size_t id = 0; +#define V(PropertyName, TypeName) \ + do { \ + Local 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* 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* indexes) { #define V(TypeName, PropertyName) \ do { \ MaybeLocal maybe_field = \ - isolate_->GetDataFromSnapshotOnce((*indexes)[i++]); \ + isolate_->GetDataFromSnapshotOnce( \ + info->primitive_values[i++]); \ Local field; \ if (!maybe_field.ToLocal(&field)) { \ fprintf(stderr, "Failed to deserialize " #PropertyName "\n"); \ @@ -292,13 +342,38 @@ void IsolateData::DeserializeProperties(const std::vector* indexes) { for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) { MaybeLocal maybe_field = - isolate_->GetDataFromSnapshotOnce((*indexes)[i++]); + isolate_->GetDataFromSnapshotOnce(info->primitive_values[i++]); Local 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& 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 maybe_field = \ + isolate_->GetDataFromSnapshotOnce(d.index); \ + Local 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* 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) { info_ = nullptr; } -std::ostream& operator<<(std::ostream& output, - const std::vector& 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 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 field = PropertyName(); \ @@ -1778,17 +1832,6 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) { return info; } -std::ostream& operator<<(std::ostream& output, - const std::vector& 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& 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& templates = info->persistent_templates; + const std::vector& 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 maybe_field = \ - from->GetDataFromSnapshotOnce(d.index); \ + ctx->GetDataFromSnapshotOnce(d.index); \ Local 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& values = info->persistent_values; -#define V(PropertyName, TypeName) SetProperty(PropertyName, TypeName, \ - values, value, ctx) ENVIRONMENT_STRONG_PERSISTENT_VALUES(V); #undef V -#undef SetProperty MaybeLocal maybe_ctx_from_snapshot = ctx->GetDataFromSnapshotOnce(info->context); diff --git a/src/env.h b/src/env.h index 04528583cb47f4..047dfd2870b89a 100644 --- a/src/env.h +++ b/src/env.h @@ -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 primitive_values; + std::vector 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* 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 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 PropertyName() const; \ + inline void set_##PropertyName(v8::Local value); + PER_ISOLATE_TEMPLATE_PROPERTIES(V) +#undef V + inline v8::Local 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* 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 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, 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 context, v8::Local holder, int index, @@ -955,7 +975,6 @@ struct EnvSerializeInfo { AliasedBufferIndex stream_base_state; AliasedBufferIndex should_abort_on_uncaught_toggle; - std::vector persistent_templates; std::vector persistent_values; SnapshotIndex context; @@ -974,7 +993,7 @@ struct SnapshotData { // building process. v8::StartupData v8_snapshot_blob_data{nullptr, 0}; - std::vector 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 PropertyName() const; \ inline void set_ ## PropertyName(v8::Local value); + PER_ISOLATE_TEMPLATE_PROPERTIES(V) ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) - ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) #undef V inline v8::Local context() const; @@ -1646,7 +1665,6 @@ class Environment : public MemoryRetainer { #define V(PropertyName, TypeName) v8::Global PropertyName ## _; ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) - ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) #undef V v8::Global context_; diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 7e89cfc51f5e4b..1287e795de5bbc 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -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) { diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 27a26bb07954d8..9e88c2157d272c 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -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 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