From 9f9d00ccbba12278569821c0fd355ae188cb6f12 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 14 Jul 2022 00:13:33 +0800 Subject: [PATCH] src: merge NativeModuleEnv into NativeModuleLoader Now that we include the code cache into the embedded snapshot, there is no point in splitting an Environment-independent NativeModuleLoader out of NativeModuleEnv. Merge the two classes for simplicity. PR-URL: https://github.com/nodejs/node/pull/43824 Refs: https://github.com/nodejs/node/issues/31074 Reviewed-By: Chengzhong Wu --- node.gyp | 2 - src/api/environment.cc | 9 +- src/node.cc | 9 +- src/node_binding.cc | 7 +- src/node_config.cc | 2 +- src/node_main_instance.cc | 2 +- src/node_native_module.cc | 304 ++++++++++++++++++++++++++++++-- src/node_native_module.h | 57 ++++-- src/node_native_module_env.cc | 319 ---------------------------------- src/node_native_module_env.h | 71 -------- src/node_snapshotable.cc | 6 +- 11 files changed, 357 insertions(+), 431 deletions(-) delete mode 100644 src/node_native_module_env.cc delete mode 100644 src/node_native_module_env.h diff --git a/node.gyp b/node.gyp index 09dd9650faf729..e8227bb22a39fe 100644 --- a/node.gyp +++ b/node.gyp @@ -516,7 +516,6 @@ 'src/node_messaging.cc', 'src/node_metadata.cc', 'src/node_native_module.cc', - 'src/node_native_module_env.cc', 'src/node_options.cc', 'src/node_os.cc', 'src/node_perf.cc', @@ -621,7 +620,6 @@ 'src/node_metadata.h', 'src/node_mutex.h', 'src/node_native_module.h', - 'src/node_native_module_env.h', 'src/node_object_wrap.h', 'src/node_options.h', 'src/node_options-inl.h', diff --git a/src/api/environment.cc b/src/api/environment.cc index e030e6063ac93e..c0b5f539451696 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -2,7 +2,7 @@ #include "node_context_data.h" #include "node_errors.h" #include "node_internals.h" -#include "node_native_module_env.h" +#include "node_native_module.h" #include "node_options-inl.h" #include "node_platform.h" #include "node_v8_platform-inl.h" @@ -442,9 +442,8 @@ MaybeLocal LoadEnvironment( // TODO(addaleax): Avoid having a global table for all scripts. std::string name = "embedder_main_" + std::to_string(env->thread_id()); - native_module::NativeModuleEnv::Add( - name.c_str(), - UnionBytes(**main_utf16, main_utf16->length())); + native_module::NativeModuleLoader::Add( + name.c_str(), UnionBytes(**main_utf16, main_utf16->length())); env->set_main_utf16(std::move(main_utf16)); std::vector> params = { env->process_string(), @@ -698,7 +697,7 @@ Maybe InitializePrimordials(Local context) { global_string, exports_string, primordials_string}; Local arguments[] = {context->Global(), exports, primordials}; MaybeLocal maybe_fn = - native_module::NativeModuleEnv::LookupAndCompile( + native_module::NativeModuleLoader::LookupAndCompile( context, *module, ¶meters, nullptr); Local fn; if (!maybe_fn.ToLocal(&fn)) { diff --git a/src/node.cc b/src/node.cc index b54abb3af80d4d..40a0decc3f2bf1 100644 --- a/src/node.cc +++ b/src/node.cc @@ -32,7 +32,7 @@ #include "node_internals.h" #include "node_main_instance.h" #include "node_metadata.h" -#include "node_native_module_env.h" +#include "node_native_module.h" #include "node_options-inl.h" #include "node_perf.h" #include "node_process-inl.h" @@ -125,7 +125,7 @@ namespace node { -using native_module::NativeModuleEnv; +using native_module::NativeModuleLoader; using v8::EscapableHandleScope; using v8::Function; @@ -178,7 +178,7 @@ MaybeLocal ExecuteBootstrapper(Environment* env, std::vector>* arguments) { EscapableHandleScope scope(env->isolate()); MaybeLocal maybe_fn = - NativeModuleEnv::LookupAndCompile(env->context(), id, parameters, env); + NativeModuleLoader::LookupAndCompile(env->context(), id, parameters, env); Local fn; if (!maybe_fn.ToLocal(&fn)) { @@ -1196,8 +1196,7 @@ int Start(int argc, char** argv) { uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME); if (snapshot_data != nullptr) { - native_module::NativeModuleEnv::RefreshCodeCache( - snapshot_data->code_cache); + NativeModuleLoader::RefreshCodeCache(snapshot_data->code_cache); } NodeMainInstance main_instance(snapshot_data, uv_default_loop(), diff --git a/src/node_binding.cc b/src/node_binding.cc index 2991ee34746e0f..de9ed507889997 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -3,7 +3,7 @@ #include "env-inl.h" #include "node_errors.h" #include "node_external_reference.h" -#include "node_native_module_env.h" +#include "node_native_module.h" #include "util.h" #include @@ -598,13 +598,14 @@ void GetInternalBinding(const FunctionCallbackInfo& args) { exports->SetPrototype(env->context(), Null(env->isolate())).FromJust()); DefineConstants(env->isolate(), exports); } else if (!strcmp(*module_v, "natives")) { - exports = native_module::NativeModuleEnv::GetSourceObject(env->context()); + exports = + native_module::NativeModuleLoader::GetSourceObject(env->context()); // Legacy feature: process.binding('natives').config contains stringified // config.gypi CHECK(exports ->Set(env->context(), env->config_string(), - native_module::NativeModuleEnv::GetConfigString( + native_module::NativeModuleLoader::GetConfigString( env->isolate())) .FromJust()); } else { diff --git a/src/node_config.cc b/src/node_config.cc index 176daa88b0fab1..3aa6fecfb42f1d 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -2,7 +2,7 @@ #include "memory_tracker.h" #include "node.h" #include "node_i18n.h" -#include "node_native_module_env.h" +#include "node_native_module.h" #include "node_options.h" #include "util-inl.h" diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index ad4f6a7d95fb32..7e89cfc51f5e4b 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -6,7 +6,7 @@ #include "debug_utils-inl.h" #include "node_external_reference.h" #include "node_internals.h" -#include "node_native_module_env.h" +#include "node_native_module.h" #include "node_options-inl.h" #include "node_snapshot_builder.h" #include "node_snapshotable.h" diff --git a/src/node_native_module.cc b/src/node_native_module.cc index cea80e36b7287d..38af67c8955fd7 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -1,5 +1,7 @@ #include "node_native_module.h" #include "debug_utils-inl.h" +#include "env-inl.h" +#include "node_external_reference.h" #include "node_internals.h" #include "util-inl.h" @@ -7,19 +9,29 @@ namespace node { namespace native_module { using v8::Context; +using v8::DEFAULT; using v8::EscapableHandleScope; using v8::Function; +using v8::FunctionCallbackInfo; +using v8::IntegrityLevel; using v8::Isolate; using v8::Local; using v8::MaybeLocal; +using v8::Name; +using v8::None; using v8::Object; +using v8::PropertyCallbackInfo; using v8::ScriptCompiler; using v8::ScriptOrigin; +using v8::Set; +using v8::SideEffectType; using v8::String; +using v8::Value; NativeModuleLoader NativeModuleLoader::instance_; -NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) { +NativeModuleLoader::NativeModuleLoader() + : config_(GetConfig()), has_code_cache_(false) { LoadJavaScriptSource(); } @@ -28,21 +40,20 @@ NativeModuleLoader* NativeModuleLoader::GetInstance() { } bool NativeModuleLoader::Exists(const char* id) { - return source_.find(id) != source_.end(); + auto& source = GetInstance()->source_; + return source.find(id) != source.end(); } bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) { - if (Exists(id)) { - return false; - } - source_.emplace(id, source); - return true; + auto result = GetInstance()->source_.emplace(id, source); + return result.second; } Local NativeModuleLoader::GetSourceObject(Local context) { Isolate* isolate = context->GetIsolate(); Local out = Object::New(isolate); - for (auto const& x : source_) { + auto& source = GetInstance()->source_; + for (auto const& x : source) { Local key = OneByteString(isolate, x.first.c_str(), x.first.size()); out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust(); } @@ -50,7 +61,7 @@ Local NativeModuleLoader::GetSourceObject(Local context) { } Local NativeModuleLoader::GetConfigString(Isolate* isolate) { - return config_.ToStringChecked(isolate); + return GetInstance()->config_.ToStringChecked(isolate); } std::vector NativeModuleLoader::GetModuleIds() { @@ -185,7 +196,7 @@ MaybeLocal NativeModuleLoader::CompileAsModule( FIXED_ONE_BYTE_STRING(isolate, "process"), FIXED_ONE_BYTE_STRING(isolate, "internalBinding"), FIXED_ONE_BYTE_STRING(isolate, "primordials")}; - return LookupAndCompile(context, id, ¶meters, result); + return LookupAndCompileInternal(context, id, ¶meters, result); } #ifdef NODE_BUILTIN_MODULES_PATH @@ -239,7 +250,7 @@ MaybeLocal NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate, // Returns Local of the compiled module if return_code_cache // is false (we are only compiling the function). // Otherwise return a Local containing the cache. -MaybeLocal NativeModuleLoader::LookupAndCompile( +MaybeLocal NativeModuleLoader::LookupAndCompileInternal( Local context, const char* id, std::vector>* parameters, @@ -343,5 +354,276 @@ MaybeLocal NativeModuleLoader::LookupAndCompile( return scope.Escape(fun); } +// Returns Local of the compiled module if return_code_cache +// is false (we are only compiling the function). +// Otherwise return a Local containing the cache. +MaybeLocal NativeModuleLoader::LookupAndCompile( + Local context, + const char* id, + std::vector>* parameters, + Environment* optional_env) { + Result result; + MaybeLocal maybe = + GetInstance()->LookupAndCompileInternal(context, id, parameters, &result); + if (optional_env != nullptr) { + RecordResult(id, result, optional_env); + } + return maybe; +} + +bool NativeModuleLoader::CompileAllModules(Local context) { + NativeModuleLoader* loader = GetInstance(); + std::vector ids = loader->GetModuleIds(); + bool all_succeeded = true; + for (const auto& id : ids) { + // TODO(joyeecheung): compile non-module scripts here too. + if (!loader->CanBeRequired(id.c_str())) { + continue; + } + v8::TryCatch bootstrapCatch(context->GetIsolate()); + Result result; + USE(loader->CompileAsModule(context, id.c_str(), &result)); + if (bootstrapCatch.HasCaught()) { + per_process::Debug(DebugCategory::CODE_CACHE, + "Failed to compile code cache for %s\n", + id.c_str()); + all_succeeded = false; + PrintCaughtException(context->GetIsolate(), context, bootstrapCatch); + } + } + return all_succeeded; +} + +void NativeModuleLoader::CopyCodeCache(std::vector* out) { + NativeModuleLoader* loader = GetInstance(); + Mutex::ScopedLock lock(loader->code_cache_mutex()); + auto in = loader->code_cache(); + for (auto const& item : *in) { + out->push_back( + {item.first, + {item.second->data, item.second->data + item.second->length}}); + } +} + +void NativeModuleLoader::RefreshCodeCache( + const std::vector& in) { + NativeModuleLoader* loader = GetInstance(); + Mutex::ScopedLock lock(loader->code_cache_mutex()); + auto out = loader->code_cache(); + for (auto const& item : in) { + size_t length = item.data.size(); + uint8_t* buffer = new uint8_t[length]; + memcpy(buffer, item.data.data(), length); + auto new_cache = std::make_unique( + buffer, length, v8::ScriptCompiler::CachedData::BufferOwned); + auto cache_it = out->find(item.id); + if (cache_it != out->end()) { + // Release the old cache and replace it with the new copy. + cache_it->second.reset(new_cache.release()); + } else { + out->emplace(item.id, new_cache.release()); + } + } + loader->has_code_cache_ = true; +} + +void NativeModuleLoader::GetModuleCategories( + Local property, const PropertyCallbackInfo& info) { + Environment* env = Environment::GetCurrent(info); + Isolate* isolate = env->isolate(); + Local context = env->context(); + Local result = Object::New(isolate); + + // Copy from the per-process categories + std::set cannot_be_required = + GetInstance()->GetCannotBeRequired(); + std::set can_be_required = GetInstance()->GetCanBeRequired(); + + if (!env->owns_process_state()) { + can_be_required.erase("trace_events"); + cannot_be_required.insert("trace_events"); + } + + Local cannot_be_required_js; + Local can_be_required_js; + + if (!ToV8Value(context, cannot_be_required).ToLocal(&cannot_be_required_js)) + return; + if (result + ->Set(context, + OneByteString(isolate, "cannotBeRequired"), + cannot_be_required_js) + .IsNothing()) + return; + if (!ToV8Value(context, can_be_required).ToLocal(&can_be_required_js)) return; + if (result + ->Set(context, + OneByteString(isolate, "canBeRequired"), + can_be_required_js) + .IsNothing()) { + return; + } + info.GetReturnValue().Set(result); +} + +void NativeModuleLoader::GetCacheUsage( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + Local context = env->context(); + Local result = Object::New(isolate); + + Local native_modules_with_cache_js; + Local native_modules_without_cache_js; + Local native_modules_in_snapshot_js; + if (!ToV8Value(context, env->native_modules_with_cache) + .ToLocal(&native_modules_with_cache_js)) { + return; + } + if (result + ->Set(env->context(), + OneByteString(isolate, "compiledWithCache"), + native_modules_with_cache_js) + .IsNothing()) { + return; + } + + if (!ToV8Value(context, env->native_modules_without_cache) + .ToLocal(&native_modules_without_cache_js)) { + return; + } + if (result + ->Set(env->context(), + OneByteString(isolate, "compiledWithoutCache"), + native_modules_without_cache_js) + .IsNothing()) { + return; + } + + if (!ToV8Value(context, env->native_modules_in_snapshot) + .ToLocal(&native_modules_without_cache_js)) { + return; + } + if (result + ->Set(env->context(), + OneByteString(isolate, "compiledInSnapshot"), + native_modules_without_cache_js) + .IsNothing()) { + return; + } + + args.GetReturnValue().Set(result); +} + +void NativeModuleLoader::ModuleIdsGetter( + Local property, const PropertyCallbackInfo& info) { + Isolate* isolate = info.GetIsolate(); + + std::vector ids = GetInstance()->GetModuleIds(); + info.GetReturnValue().Set( + ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked()); +} + +void NativeModuleLoader::ConfigStringGetter( + Local property, const PropertyCallbackInfo& info) { + info.GetReturnValue().Set(GetConfigString(info.GetIsolate())); +} + +void NativeModuleLoader::RecordResult(const char* id, + NativeModuleLoader::Result result, + Environment* env) { + if (result == NativeModuleLoader::Result::kWithCache) { + env->native_modules_with_cache.insert(id); + } else { + env->native_modules_without_cache.insert(id); + } +} +void NativeModuleLoader::CompileFunction( + const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsString()); + node::Utf8Value id_v(env->isolate(), args[0].As()); + const char* id = *id_v; + NativeModuleLoader::Result result; + MaybeLocal maybe = + GetInstance()->CompileAsModule(env->context(), id, &result); + RecordResult(id, result, env); + Local fn; + if (maybe.ToLocal(&fn)) { + args.GetReturnValue().Set(fn); + } +} + +void NativeModuleLoader::HasCachedBuiltins( + const FunctionCallbackInfo& args) { + args.GetReturnValue().Set( + v8::Boolean::New(args.GetIsolate(), GetInstance()->has_code_cache_)); +} + +// TODO(joyeecheung): It is somewhat confusing that Class::Initialize +// is used to initialize to the binding, but it is the current convention. +// Rename this across the code base to something that makes more sense. +void NativeModuleLoader::Initialize(Local target, + Local unused, + Local context, + void* priv) { + Environment* env = Environment::GetCurrent(context); + + target + ->SetAccessor(env->context(), + env->config_string(), + ConfigStringGetter, + nullptr, + MaybeLocal(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .Check(); + target + ->SetAccessor(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "moduleIds"), + ModuleIdsGetter, + nullptr, + MaybeLocal(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .Check(); + + target + ->SetAccessor(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "moduleCategories"), + GetModuleCategories, + nullptr, + Local(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .Check(); + + env->SetMethod(target, "getCacheUsage", NativeModuleLoader::GetCacheUsage); + env->SetMethod( + target, "compileFunction", NativeModuleLoader::CompileFunction); + env->SetMethod(target, "hasCachedBuiltins", HasCachedBuiltins); + // internalBinding('native_module') should be frozen + target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust(); +} + +void NativeModuleLoader::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(ConfigStringGetter); + registry->Register(ModuleIdsGetter); + registry->Register(GetModuleCategories); + registry->Register(GetCacheUsage); + registry->Register(CompileFunction); + registry->Register(HasCachedBuiltins); +} + } // namespace native_module } // namespace node + +NODE_MODULE_CONTEXT_AWARE_INTERNAL( + native_module, node::native_module::NativeModuleLoader::Initialize) +NODE_MODULE_EXTERNAL_REFERENCE( + native_module, + node::native_module::NativeModuleLoader::RegisterExternalReferences) diff --git a/src/node_native_module.h b/src/node_native_module.h index 1bbb400586e070..3c797a5d35b17e 100644 --- a/src/node_native_module.h +++ b/src/node_native_module.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "node_mutex.h" #include "node_union_bytes.h" #include "v8.h" @@ -16,6 +17,7 @@ class PerProcessTest; namespace node { class SnapshotBuilder; +class ExternalReferenceRegistry; namespace native_module { using NativeModuleRecordMap = std::map; @@ -32,17 +34,35 @@ struct CodeCacheInfo { // handles compilation and caching of builtin modules (NativeModule) // and bootstrappers, whose source are bundled into the binary // as static data. -// This class should not depend on any Environment, or depend on access to -// the its own singleton - that should be encapsulated in NativeModuleEnv -// instead. class NODE_EXTERN_PRIVATE NativeModuleLoader { public: NativeModuleLoader(const NativeModuleLoader&) = delete; NativeModuleLoader& operator=(const NativeModuleLoader&) = delete; + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); + static void Initialize(v8::Local target, + v8::Local unused, + v8::Local context, + void* priv); + + static v8::MaybeLocal LookupAndCompile( + v8::Local context, + const char* id, + std::vector>* parameters, + Environment* optional_env); + + static v8::Local GetSourceObject(v8::Local context); + // Returns config.gypi as a JSON string + static v8::Local GetConfigString(v8::Isolate* isolate); + static bool Exists(const char* id); + static bool Add(const char* id, const UnionBytes& source); + + static bool CompileAllModules(v8::Local context); + static void RefreshCodeCache(const std::vector& in); + static void CopyCodeCache(std::vector* out); + private: // Only allow access from friends. - friend class NativeModuleEnv; friend class CodeCacheBuilder; NativeModuleLoader(); @@ -52,11 +72,6 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { void LoadJavaScriptSource(); // Loads data into source_ UnionBytes GetConfig(); // Return data for config.gypi - bool Exists(const char* id); - bool Add(const char* id, const UnionBytes& source); - - v8::Local GetSourceObject(v8::Local context); - v8::Local GetConfigString(v8::Isolate* isolate); std::vector GetModuleIds(); struct ModuleCategories { @@ -80,7 +95,7 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { const char* id); // If an exception is encountered (e.g. source code contains // syntax error), the returned value is empty. - v8::MaybeLocal LookupAndCompile( + v8::MaybeLocal LookupAndCompileInternal( v8::Local context, const char* id, std::vector>* parameters, @@ -89,6 +104,26 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { const char* id, Result* result); + static void RecordResult(const char* id, + NativeModuleLoader::Result result, + Environment* env); + static void GetModuleCategories( + v8::Local property, + const v8::PropertyCallbackInfo& info); + static void GetCacheUsage(const v8::FunctionCallbackInfo& args); + // Passing ids of builtin module source code into JS land as + // internalBinding('native_module').moduleIds + static void ModuleIdsGetter(v8::Local property, + const v8::PropertyCallbackInfo& info); + // Passing config.gypi into JS land as internalBinding('native_module').config + static void ConfigStringGetter( + v8::Local property, + const v8::PropertyCallbackInfo& info); + // Compile a specific native module as a function + static void CompileFunction(const v8::FunctionCallbackInfo& args); + static void HasCachedBuiltins( + const v8::FunctionCallbackInfo& args); + static NativeModuleLoader instance_; ModuleCategories module_categories_; NativeModuleRecordMap source_; @@ -98,6 +133,8 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { // Used to synchronize access to the code cache map Mutex code_cache_mutex_; + bool has_code_cache_; + friend class ::PerProcessTest; }; } // namespace native_module diff --git a/src/node_native_module_env.cc b/src/node_native_module_env.cc deleted file mode 100644 index 05513b89f8f188..00000000000000 --- a/src/node_native_module_env.cc +++ /dev/null @@ -1,319 +0,0 @@ -#include - -#include "debug_utils-inl.h" -#include "env-inl.h" -#include "node_external_reference.h" -#include "node_native_module_env.h" - -namespace node { -namespace native_module { - -using v8::Context; -using v8::DEFAULT; -using v8::Function; -using v8::FunctionCallbackInfo; -using v8::IntegrityLevel; -using v8::Isolate; -using v8::Local; -using v8::MaybeLocal; -using v8::Name; -using v8::None; -using v8::Object; -using v8::PropertyCallbackInfo; -using v8::Set; -using v8::SideEffectType; -using v8::String; -using v8::Value; - -bool NativeModuleEnv::has_code_cache_ = false; - -bool NativeModuleEnv::Add(const char* id, const UnionBytes& source) { - return NativeModuleLoader::GetInstance()->Add(id, source); -} - -bool NativeModuleEnv::Exists(const char* id) { - return NativeModuleLoader::GetInstance()->Exists(id); -} - -Local NativeModuleEnv::GetSourceObject(Local context) { - return NativeModuleLoader::GetInstance()->GetSourceObject(context); -} - -Local NativeModuleEnv::GetConfigString(Isolate* isolate) { - return NativeModuleLoader::GetInstance()->GetConfigString(isolate); -} - -bool NativeModuleEnv::CompileAllModules(Local context) { - NativeModuleLoader* loader = NativeModuleLoader::GetInstance(); - std::vector ids = loader->GetModuleIds(); - bool all_succeeded = true; - for (const auto& id : ids) { - // TODO(joyeecheung): compile non-module scripts here too. - if (!loader->CanBeRequired(id.c_str())) { - continue; - } - v8::TryCatch bootstrapCatch(context->GetIsolate()); - native_module::NativeModuleLoader::Result result; - USE(loader->CompileAsModule(context, id.c_str(), &result)); - if (bootstrapCatch.HasCaught()) { - per_process::Debug(DebugCategory::CODE_CACHE, - "Failed to compile code cache for %s\n", - id.c_str()); - all_succeeded = false; - PrintCaughtException(context->GetIsolate(), context, bootstrapCatch); - } - } - return all_succeeded; -} - -void NativeModuleEnv::CopyCodeCache(std::vector* out) { - NativeModuleLoader* loader = NativeModuleLoader::GetInstance(); - Mutex::ScopedLock lock(loader->code_cache_mutex()); - auto in = loader->code_cache(); - for (auto const& item : *in) { - out->push_back( - {item.first, - {item.second->data, item.second->data + item.second->length}}); - } -} - -void NativeModuleEnv::RefreshCodeCache(const std::vector& in) { - NativeModuleLoader* loader = NativeModuleLoader::GetInstance(); - Mutex::ScopedLock lock(loader->code_cache_mutex()); - auto out = loader->code_cache(); - for (auto const& item : in) { - size_t length = item.data.size(); - uint8_t* buffer = new uint8_t[length]; - memcpy(buffer, item.data.data(), length); - auto new_cache = std::make_unique( - buffer, length, v8::ScriptCompiler::CachedData::BufferOwned); - auto cache_it = out->find(item.id); - if (cache_it != out->end()) { - // Release the old cache and replace it with the new copy. - cache_it->second.reset(new_cache.release()); - } else { - out->emplace(item.id, new_cache.release()); - } - } - NativeModuleEnv::has_code_cache_ = true; -} - -void NativeModuleEnv::GetModuleCategories( - Local property, const PropertyCallbackInfo& info) { - Environment* env = Environment::GetCurrent(info); - Isolate* isolate = env->isolate(); - Local context = env->context(); - Local result = Object::New(isolate); - - // Copy from the per-process categories - std::set cannot_be_required = - NativeModuleLoader::GetInstance()->GetCannotBeRequired(); - std::set can_be_required = - NativeModuleLoader::GetInstance()->GetCanBeRequired(); - - if (!env->owns_process_state()) { - can_be_required.erase("trace_events"); - cannot_be_required.insert("trace_events"); - } - - Local cannot_be_required_js; - Local can_be_required_js; - - if (!ToV8Value(context, cannot_be_required).ToLocal(&cannot_be_required_js)) - return; - if (result - ->Set(context, - OneByteString(isolate, "cannotBeRequired"), - cannot_be_required_js) - .IsNothing()) - return; - if (!ToV8Value(context, can_be_required).ToLocal(&can_be_required_js)) - return; - if (result - ->Set(context, - OneByteString(isolate, "canBeRequired"), - can_be_required_js) - .IsNothing()) { - return; - } - info.GetReturnValue().Set(result); -} - -void NativeModuleEnv::GetCacheUsage(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - Isolate* isolate = env->isolate(); - Local context = env->context(); - Local result = Object::New(isolate); - - Local native_modules_with_cache_js; - Local native_modules_without_cache_js; - Local native_modules_in_snapshot_js; - if (!ToV8Value(context, env->native_modules_with_cache) - .ToLocal(&native_modules_with_cache_js)) { - return; - } - if (result - ->Set(env->context(), - OneByteString(isolate, "compiledWithCache"), - native_modules_with_cache_js) - .IsNothing()) { - return; - } - - if (!ToV8Value(context, env->native_modules_without_cache) - .ToLocal(&native_modules_without_cache_js)) { - return; - } - if (result - ->Set(env->context(), - OneByteString(isolate, "compiledWithoutCache"), - native_modules_without_cache_js) - .IsNothing()) { - return; - } - - if (!ToV8Value(context, env->native_modules_in_snapshot) - .ToLocal(&native_modules_without_cache_js)) { - return; - } - if (result - ->Set(env->context(), - OneByteString(isolate, "compiledInSnapshot"), - native_modules_without_cache_js) - .IsNothing()) { - return; - } - - args.GetReturnValue().Set(result); -} - -void NativeModuleEnv::ModuleIdsGetter(Local property, - const PropertyCallbackInfo& info) { - Isolate* isolate = info.GetIsolate(); - - std::vector ids = - NativeModuleLoader::GetInstance()->GetModuleIds(); - info.GetReturnValue().Set( - ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked()); -} - -void NativeModuleEnv::ConfigStringGetter( - Local property, const PropertyCallbackInfo& info) { - info.GetReturnValue().Set(GetConfigString(info.GetIsolate())); -} - -void NativeModuleEnv::RecordResult(const char* id, - NativeModuleLoader::Result result, - Environment* env) { - if (result == NativeModuleLoader::Result::kWithCache) { - env->native_modules_with_cache.insert(id); - } else { - env->native_modules_without_cache.insert(id); - } -} -void NativeModuleEnv::CompileFunction(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - CHECK(args[0]->IsString()); - node::Utf8Value id_v(env->isolate(), args[0].As()); - const char* id = *id_v; - NativeModuleLoader::Result result; - MaybeLocal maybe = - NativeModuleLoader::GetInstance()->CompileAsModule( - env->context(), id, &result); - RecordResult(id, result, env); - Local fn; - if (maybe.ToLocal(&fn)) { - args.GetReturnValue().Set(fn); - } -} - -// Returns Local of the compiled module if return_code_cache -// is false (we are only compiling the function). -// Otherwise return a Local containing the cache. -MaybeLocal NativeModuleEnv::LookupAndCompile( - Local context, - const char* id, - std::vector>* parameters, - Environment* optional_env) { - NativeModuleLoader::Result result; - MaybeLocal maybe = - NativeModuleLoader::GetInstance()->LookupAndCompile( - context, id, parameters, &result); - if (optional_env != nullptr) { - RecordResult(id, result, optional_env); - } - return maybe; -} - -void NativeModuleEnv::HasCachedBuiltins( - const FunctionCallbackInfo& args) { - args.GetReturnValue().Set( - v8::Boolean::New(args.GetIsolate(), NativeModuleEnv::has_code_cache_)); -} - -// TODO(joyeecheung): It is somewhat confusing that Class::Initialize -// is used to initialize to the binding, but it is the current convention. -// Rename this across the code base to something that makes more sense. -void NativeModuleEnv::Initialize(Local target, - Local unused, - Local context, - void* priv) { - Environment* env = Environment::GetCurrent(context); - - target - ->SetAccessor(env->context(), - env->config_string(), - ConfigStringGetter, - nullptr, - MaybeLocal(), - DEFAULT, - None, - SideEffectType::kHasNoSideEffect) - .Check(); - target - ->SetAccessor(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "moduleIds"), - ModuleIdsGetter, - nullptr, - MaybeLocal(), - DEFAULT, - None, - SideEffectType::kHasNoSideEffect) - .Check(); - - target - ->SetAccessor(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "moduleCategories"), - GetModuleCategories, - nullptr, - Local(), - DEFAULT, - None, - SideEffectType::kHasNoSideEffect) - .Check(); - - env->SetMethod(target, "getCacheUsage", NativeModuleEnv::GetCacheUsage); - env->SetMethod(target, "compileFunction", NativeModuleEnv::CompileFunction); - env->SetMethod(target, "hasCachedBuiltins", HasCachedBuiltins); - // internalBinding('native_module') should be frozen - target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust(); -} - -void NativeModuleEnv::RegisterExternalReferences( - ExternalReferenceRegistry* registry) { - registry->Register(ConfigStringGetter); - registry->Register(ModuleIdsGetter); - registry->Register(GetModuleCategories); - registry->Register(GetCacheUsage); - registry->Register(CompileFunction); - registry->Register(HasCachedBuiltins); -} - -} // namespace native_module -} // namespace node - -NODE_MODULE_CONTEXT_AWARE_INTERNAL( - native_module, node::native_module::NativeModuleEnv::Initialize) -NODE_MODULE_EXTERNAL_REFERENCE( - native_module, - node::native_module::NativeModuleEnv::RegisterExternalReferences) diff --git a/src/node_native_module_env.h b/src/node_native_module_env.h deleted file mode 100644 index adcfc7b6fb4954..00000000000000 --- a/src/node_native_module_env.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef SRC_NODE_NATIVE_MODULE_ENV_H_ -#define SRC_NODE_NATIVE_MODULE_ENV_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include -#include "node_native_module.h" - -namespace node { -class Environment; -class ExternalReferenceRegistry; -namespace native_module { - -// TODO(joyeecheung): since it's safer to make the code cache part of the -// embedded snapshot, there is no need to separate NativeModuleEnv and -// NativeModuleLoader. Merge the two. -class NativeModuleEnv { - public: - static void RegisterExternalReferences(ExternalReferenceRegistry* registry); - static void Initialize(v8::Local target, - v8::Local unused, - v8::Local context, - void* priv); - - static v8::MaybeLocal LookupAndCompile( - v8::Local context, - const char* id, - std::vector>* parameters, - Environment* optional_env); - - static v8::Local GetSourceObject(v8::Local context); - // Returns config.gypi as a JSON string - static v8::Local GetConfigString(v8::Isolate* isolate); - static bool Exists(const char* id); - static bool Add(const char* id, const UnionBytes& source); - - static bool CompileAllModules(v8::Local context); - static void RefreshCodeCache(const std::vector& in); - static void CopyCodeCache(std::vector* out); - - private: - static void RecordResult(const char* id, - NativeModuleLoader::Result result, - Environment* env); - static void GetModuleCategories( - v8::Local property, - const v8::PropertyCallbackInfo& info); - static void GetCacheUsage(const v8::FunctionCallbackInfo& args); - // Passing ids of builtin module source code into JS land as - // internalBinding('native_module').moduleIds - static void ModuleIdsGetter(v8::Local property, - const v8::PropertyCallbackInfo& info); - // Passing config.gypi into JS land as internalBinding('native_module').config - static void ConfigStringGetter( - v8::Local property, - const v8::PropertyCallbackInfo& info); - // Compile a specific native module as a function - static void CompileFunction(const v8::FunctionCallbackInfo& args); - static void HasCachedBuiltins( - const v8::FunctionCallbackInfo& args); - - static bool has_code_cache_; -}; - -} // namespace native_module - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_NODE_NATIVE_MODULE_ENV_H_ diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 7375c8cdecf286..27a26bb07954d8 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -11,7 +11,7 @@ #include "node_file.h" #include "node_internals.h" #include "node_main_instance.h" -#include "node_native_module_env.h" +#include "node_native_module.h" #include "node_process.h" #include "node_snapshot_builder.h" #include "node_v8.h" @@ -289,10 +289,10 @@ int SnapshotBuilder::Generate(SnapshotData* out, #ifdef NODE_USE_NODE_CODE_CACHE // Regenerate all the code cache. - if (!native_module::NativeModuleEnv::CompileAllModules(main_context)) { + if (!native_module::NativeModuleLoader::CompileAllModules(main_context)) { return UNCAUGHT_EXCEPTION_ERROR; } - native_module::NativeModuleEnv::CopyCodeCache(&(out->code_cache)); + native_module::NativeModuleLoader::CopyCodeCache(&(out->code_cache)); for (const auto& item : out->code_cache) { std::string size_str = FormatSize(item.data.size()); per_process::Debug(DebugCategory::MKSNAPSHOT,