#include "node_native_module_env.h" #include "env-inl.h" #include "node_external_reference.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::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); } 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 HasCachedBuiltins(const FunctionCallbackInfo& args) { args.GetReturnValue().Set( v8::Boolean::New(args.GetIsolate(), 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)