diff options
author | Joyee Cheung <joyeec9h3@gmail.com> | 2019-04-10 05:08:48 +0800 |
---|---|---|
committer | Joyee Cheung <joyeec9h3@gmail.com> | 2019-04-13 17:24:51 +0800 |
commit | dfd7e994258a36f3941c74295a8c037cb4850418 (patch) | |
tree | 03eaa022a99159912c97773a1b41952f3ee404b1 /src/node_native_module_env.cc | |
parent | 9b6b567bc4dd8f40bad12528eebf12dac8a8027f (diff) | |
download | android-node-v8-dfd7e994258a36f3941c74295a8c037cb4850418.tar.gz android-node-v8-dfd7e994258a36f3941c74295a8c037cb4850418.tar.bz2 android-node-v8-dfd7e994258a36f3941c74295a8c037cb4850418.zip |
src: make a Environment-independent proxy class for NativeModuleLoader
This patch splits `NativeModuleLoader` into two parts - a singleton
that only relies on v8 and `node::Mutex` and a proxy class for
the singleton (`NativeModuleEnv`) that provides limited access to
the singleton as well as C++ bindings for the Node.js binary.
`NativeModuleLoader` is then no longer aware of `Environment`.
PR-URL: https://github.com/nodejs/node/pull/27160
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Diffstat (limited to 'src/node_native_module_env.cc')
-rw-r--r-- | src/node_native_module_env.cc | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/src/node_native_module_env.cc b/src/node_native_module_env.cc new file mode 100644 index 0000000000..fc48436dc1 --- /dev/null +++ b/src/node_native_module_env.cc @@ -0,0 +1,229 @@ +#include "node_native_module_env.h" +#include "env-inl.h" + +namespace node { +namespace native_module { + +using v8::ArrayBuffer; +using v8::Context; +using v8::DEFAULT; +using v8::Function; +using v8::FunctionCallbackInfo; +using v8::IntegrityLevel; +using v8::Isolate; +using v8::Local; +using v8::Maybe; +using v8::MaybeLocal; +using v8::Name; +using v8::None; +using v8::Object; +using v8::PropertyCallbackInfo; +using v8::ScriptCompiler; +using v8::Set; +using v8::SideEffectType; +using v8::String; +using v8::Uint8Array; +using v8::Value; + +// TODO(joyeecheung): make these more general and put them into util.h +Local<Set> ToJsSet(Local<Context> context, const std::set<std::string>& in) { + Isolate* isolate = context->GetIsolate(); + Local<Set> out = Set::New(isolate); + for (auto const& x : in) { + out->Add(context, OneByteString(isolate, x.c_str(), x.size())) + .ToLocalChecked(); + } + return out; +} + +bool NativeModuleEnv::Exists(const char* id) { + return NativeModuleLoader::GetInstance()->Exists(id); +} + +Local<Object> NativeModuleEnv::GetSourceObject(Local<Context> context) { + return NativeModuleLoader::GetInstance()->GetSourceObject(context); +} + +Local<String> NativeModuleEnv::GetConfigString(Isolate* isolate) { + return NativeModuleLoader::GetInstance()->GetConfigString(isolate); +} + +void NativeModuleEnv::GetModuleCategories( + Local<Name> property, const PropertyCallbackInfo<Value>& info) { + Environment* env = Environment::GetCurrent(info); + Isolate* isolate = env->isolate(); + Local<Context> context = env->context(); + Local<Object> result = Object::New(isolate); + + // Copy from the per-process categories + std::set<std::string> cannot_be_required = + NativeModuleLoader::GetInstance()->GetCannotBeRequired(); + std::set<std::string> can_be_required = + NativeModuleLoader::GetInstance()->GetCanBeRequired(); + + if (!env->owns_process_state()) { + can_be_required.erase("trace_events"); + cannot_be_required.insert("trace_events"); + } + + result + ->Set(context, + OneByteString(isolate, "cannotBeRequired"), + ToJsSet(context, cannot_be_required)) + .FromJust(); + result + ->Set(context, + OneByteString(isolate, "canBeRequired"), + ToJsSet(context, can_be_required)) + .FromJust(); + info.GetReturnValue().Set(result); +} + +void NativeModuleEnv::GetCacheUsage(const FunctionCallbackInfo<Value>& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + Local<Context> context = env->context(); + Local<Object> result = Object::New(isolate); + result + ->Set(env->context(), + OneByteString(isolate, "compiledWithCache"), + ToJsSet(context, env->native_modules_with_cache)) + .FromJust(); + result + ->Set(env->context(), + OneByteString(isolate, "compiledWithoutCache"), + ToJsSet(context, env->native_modules_without_cache)) + .FromJust(); + args.GetReturnValue().Set(result); +} + +void NativeModuleEnv::ModuleIdsGetter(Local<Name> property, + const PropertyCallbackInfo<Value>& info) { + Isolate* isolate = info.GetIsolate(); + + std::vector<std::string> ids = + NativeModuleLoader::GetInstance()->GetModuleIds(); + info.GetReturnValue().Set( + ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked()); +} + +void NativeModuleEnv::ConfigStringGetter( + Local<Name> property, const PropertyCallbackInfo<Value>& 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<Value>& args) { + Environment* env = Environment::GetCurrent(args); + CHECK(args[0]->IsString()); + node::Utf8Value id_v(env->isolate(), args[0].As<String>()); + const char* id = *id_v; + NativeModuleLoader::Result result; + MaybeLocal<Function> maybe = + NativeModuleLoader::GetInstance()->CompileAsModule( + env->context(), id, &result); + RecordResult(id, result, env); + if (!maybe.IsEmpty()) { + args.GetReturnValue().Set(maybe.ToLocalChecked()); + } +} + +// Returns Local<Function> of the compiled module if return_code_cache +// is false (we are only compiling the function). +// Otherwise return a Local<Object> containing the cache. +MaybeLocal<Function> NativeModuleEnv::LookupAndCompile( + Local<Context> context, + const char* id, + std::vector<Local<String>>* parameters, + Environment* optional_env) { + NativeModuleLoader::Result result; + MaybeLocal<Function> maybe = + NativeModuleLoader::GetInstance()->LookupAndCompile( + context, id, parameters, &result); + if (optional_env != nullptr) { + RecordResult(id, result, optional_env); + } + return maybe; +} + +// This is supposed to be run only by the main thread in +// tools/generate_code_cache.js +void NativeModuleEnv::GetCodeCache(const FunctionCallbackInfo<Value>& args) { + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + CHECK(env->is_main_thread()); + + CHECK(args[0]->IsString()); + node::Utf8Value id_v(isolate, args[0].As<String>()); + const char* id = *id_v; + + ScriptCompiler::CachedData* cached_data = + NativeModuleLoader::GetInstance()->GetCodeCache(id); + if (cached_data != nullptr) { + Local<ArrayBuffer> buf = ArrayBuffer::New(isolate, cached_data->length); + memcpy(buf->GetContents().Data(), cached_data->data, cached_data->length); + args.GetReturnValue().Set(Uint8Array::New(buf, 0, cached_data->length)); + } +} + +// TODO(joyeecheung): It is somewhat confusing that Class::Initialize +// is used to initilaize 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<Object> target, + Local<Value> unused, + Local<Context> context, + void* priv) { + Environment* env = Environment::GetCurrent(context); + + target + ->SetAccessor(env->context(), + env->config_string(), + ConfigStringGetter, + nullptr, + MaybeLocal<Value>(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .Check(); + target + ->SetAccessor(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "moduleIds"), + ModuleIdsGetter, + nullptr, + MaybeLocal<Value>(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .Check(); + + target + ->SetAccessor(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "moduleCategories"), + GetModuleCategories, + nullptr, + env->as_callback_data(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .Check(); + + env->SetMethod(target, "getCacheUsage", NativeModuleEnv::GetCacheUsage); + env->SetMethod(target, "getCodeCache", NativeModuleEnv::GetCodeCache); + env->SetMethod(target, "compileFunction", NativeModuleEnv::CompileFunction); + // internalBinding('native_module') should be frozen + target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust(); +} + +} // namespace native_module +} // namespace node + +NODE_MODULE_CONTEXT_AWARE_INTERNAL( + native_module, node::native_module::NativeModuleEnv::Initialize) |