summaryrefslogtreecommitdiff
path: root/src/node_native_module_env.cc
diff options
context:
space:
mode:
authorJoyee Cheung <joyeec9h3@gmail.com>2019-04-10 05:08:48 +0800
committerJoyee Cheung <joyeec9h3@gmail.com>2019-04-13 17:24:51 +0800
commitdfd7e994258a36f3941c74295a8c037cb4850418 (patch)
tree03eaa022a99159912c97773a1b41952f3ee404b1 /src/node_native_module_env.cc
parent9b6b567bc4dd8f40bad12528eebf12dac8a8027f (diff)
downloadandroid-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.cc229
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)