summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/internal/per_context.js64
-rw-r--r--src/node.cc19
-rw-r--r--src/node_native_module.cc107
-rw-r--r--src/node_native_module.h54
4 files changed, 144 insertions, 100 deletions
diff --git a/lib/internal/per_context.js b/lib/internal/per_context.js
index ddf874c7ea..87fc8d247e 100644
--- a/lib/internal/per_context.js
+++ b/lib/internal/per_context.js
@@ -1,44 +1,44 @@
+// arguments: global
+
'use strict';
// node::NewContext calls this script
-(function(global) {
- // https://github.com/nodejs/node/issues/14909
- if (global.Intl) delete global.Intl.v8BreakIterator;
+// https://github.com/nodejs/node/issues/14909
+if (global.Intl) delete global.Intl.v8BreakIterator;
- // https://github.com/nodejs/node/issues/21219
- // Adds Atomics.notify and warns on first usage of Atomics.wake
- // https://github.com/v8/v8/commit/c79206b363 adds Atomics.notify so
- // now we alias Atomics.wake to notify so that we can remove it
- // semver major without worrying about V8.
+// https://github.com/nodejs/node/issues/21219
+// Adds Atomics.notify and warns on first usage of Atomics.wake
+// https://github.com/v8/v8/commit/c79206b363 adds Atomics.notify so
+// now we alias Atomics.wake to notify so that we can remove it
+// semver major without worrying about V8.
- const AtomicsNotify = global.Atomics.notify;
- const ReflectApply = global.Reflect.apply;
+const AtomicsNotify = global.Atomics.notify;
+const ReflectApply = global.Reflect.apply;
- const warning = 'Atomics.wake will be removed in a future version, ' +
- 'use Atomics.notify instead.';
+const warning = 'Atomics.wake will be removed in a future version, ' +
+ 'use Atomics.notify instead.';
- let wakeWarned = false;
- function wake(typedArray, index, count) {
- if (!wakeWarned) {
- wakeWarned = true;
+let wakeWarned = false;
+function wake(typedArray, index, count) {
+ if (!wakeWarned) {
+ wakeWarned = true;
- if (global.process !== undefined) {
- global.process.emitWarning(warning, 'Atomics');
- } else {
- global.console.error(`Atomics: ${warning}`);
- }
+ if (global.process !== undefined) {
+ global.process.emitWarning(warning, 'Atomics');
+ } else {
+ global.console.error(`Atomics: ${warning}`);
}
-
- return ReflectApply(AtomicsNotify, this, arguments);
}
- global.Object.defineProperties(global.Atomics, {
- wake: {
- value: wake,
- writable: true,
- enumerable: false,
- configurable: true,
- },
- });
-}(this));
+ return ReflectApply(AtomicsNotify, this, arguments);
+}
+
+global.Object.defineProperties(global.Atomics, {
+ wake: {
+ value: wake,
+ writable: true,
+ enumerable: false,
+ configurable: true,
+ },
+});
diff --git a/src/node.cc b/src/node.cc
index 425c1f875d..e01baf9726 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -162,7 +162,6 @@ using v8::ObjectTemplate;
using v8::PropertyAttribute;
using v8::ReadOnly;
using v8::Script;
-using v8::ScriptCompiler;
using v8::ScriptOrigin;
using v8::SealHandleScope;
using v8::SideEffectType;
@@ -2500,14 +2499,16 @@ Local<Context> NewContext(Isolate* isolate,
// Run lib/internal/per_context.js
Context::Scope context_scope(context);
- // TODO(joyeecheung): use NativeModuleLoader::Compile
- Local<String> per_context =
- per_process_loader.GetSource(isolate, "internal/per_context");
- ScriptCompiler::Source per_context_src(per_context, nullptr);
- Local<Script> s = ScriptCompiler::Compile(
- context,
- &per_context_src).ToLocalChecked();
- s->Run(context).ToLocalChecked();
+ std::vector<Local<String>> parameters = {
+ FIXED_ONE_BYTE_STRING(isolate, "global")};
+ std::vector<Local<Value>> arguments = {context->Global()};
+ MaybeLocal<Value> result = per_process_loader.CompileAndCall(
+ context, "internal/per_context", &parameters, &arguments, nullptr);
+ if (result.IsEmpty()) {
+ // Execution failed during context creation.
+ // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
+ return Local<Context>();
+ }
}
return context;
diff --git a/src/node_native_module.cc b/src/node_native_module.cc
index 11136a244c..77763229ce 100644
--- a/src/node_native_module.cc
+++ b/src/node_native_module.cc
@@ -103,29 +103,54 @@ void NativeModuleLoader::CompileCodeCache(
// TODO(joyeecheung): allow compiling cache for bootstrapper by
// switching on id
- Local<Value> result = CompileAsModule(env, *id, true);
+ MaybeLocal<Value> result =
+ CompileAsModule(env, *id, CompilationResultType::kCodeCache);
if (!result.IsEmpty()) {
- args.GetReturnValue().Set(result);
+ args.GetReturnValue().Set(result.ToLocalChecked());
}
}
void NativeModuleLoader::CompileFunction(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
-
CHECK(args[0]->IsString());
node::Utf8Value id(env->isolate(), args[0].As<String>());
- Local<Value> result = CompileAsModule(env, *id, false);
+
+ MaybeLocal<Value> result =
+ CompileAsModule(env, *id, CompilationResultType::kFunction);
if (!result.IsEmpty()) {
- args.GetReturnValue().Set(result);
+ args.GetReturnValue().Set(result.ToLocalChecked());
}
}
-Local<Value> NativeModuleLoader::CompileAsModule(Environment* env,
- const char* id,
- bool produce_code_cache) {
+// TODO(joyeecheung): it should be possible to generate the argument names
+// from some special comments for the bootstrapper case.
+MaybeLocal<Value> NativeModuleLoader::CompileAndCall(
+ Local<Context> context,
+ const char* id,
+ std::vector<Local<String>>* parameters,
+ std::vector<Local<Value>>* arguments,
+ Environment* optional_env) {
+ Isolate* isolate = context->GetIsolate();
+ MaybeLocal<Value> compiled = per_process_loader.LookupAndCompile(
+ context, id, parameters, CompilationResultType::kFunction, nullptr);
+ if (compiled.IsEmpty()) {
+ return compiled;
+ }
+ Local<Function> fn = compiled.ToLocalChecked().As<Function>();
+ return fn->Call(
+ context, v8::Null(isolate), arguments->size(), arguments->data());
+}
+
+MaybeLocal<Value> NativeModuleLoader::CompileAsModule(
+ Environment* env, const char* id, CompilationResultType result) {
+ std::vector<Local<String>> parameters = {env->exports_string(),
+ env->require_string(),
+ env->module_string(),
+ env->process_string(),
+ env->internal_binding_string()};
return per_process_loader.LookupAndCompile(
- env->context(), id, produce_code_cache, env);
+ env->context(), id, &parameters, result, env);
}
// Currently V8 only checks that the length of the source code is the
@@ -183,15 +208,18 @@ ScriptCompiler::CachedData* NativeModuleLoader::GetCachedData(
return new ScriptCompiler::CachedData(code_cache_value, code_cache_length);
}
-// Returns Local<Function> of the compiled module if produce_code_cache
+// 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.
-Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
- const char* id,
- bool produce_code_cache,
- Environment* optional_env) {
+MaybeLocal<Value> NativeModuleLoader::LookupAndCompile(
+ Local<Context> context,
+ const char* id,
+ std::vector<Local<String>>* parameters,
+ CompilationResultType result_type,
+ Environment* optional_env) {
Isolate* isolate = context->GetIsolate();
EscapableHandleScope scope(isolate);
+ Local<Value> ret; // Used to convert to MaybeLocal before return
Local<String> source = GetSource(isolate, id);
@@ -209,7 +237,7 @@ Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
// built with them.
// 2. If we are generating code cache for tools/general_code_cache.js, we
// are not going to use any cache ourselves.
- if (has_code_cache_ && !produce_code_cache) {
+ if (has_code_cache_ && result_type == CompilationResultType::kFunction) {
cached_data = GetCachedData(id);
if (cached_data != nullptr) {
use_cache = true;
@@ -219,7 +247,7 @@ Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
ScriptCompiler::Source script_source(source, origin, cached_data);
ScriptCompiler::CompileOptions options;
- if (produce_code_cache) {
+ if (result_type == CompilationResultType::kCodeCache) {
options = ScriptCompiler::kEagerCompile;
} else if (use_cache) {
options = ScriptCompiler::kConsumeCodeCache;
@@ -227,42 +255,25 @@ Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
options = ScriptCompiler::kNoCompileOptions;
}
- MaybeLocal<Function> maybe_fun;
- // Currently we assume if Environment is ready, then we must be compiling
- // native modules instead of bootstrappers.
- if (optional_env != nullptr) {
- Local<String> parameters[] = {optional_env->exports_string(),
- optional_env->require_string(),
- optional_env->module_string(),
- optional_env->process_string(),
- optional_env->internal_binding_string()};
- maybe_fun = ScriptCompiler::CompileFunctionInContext(context,
- &script_source,
- arraysize(parameters),
- parameters,
- 0,
- nullptr,
- options);
- } else {
- // Until we migrate bootstrappers compilations here this is unreachable
- // TODO(joyeecheung): it should be possible to generate the argument names
- // from some special comments for the bootstrapper case.
- // Note that for bootstrappers we may not be able to get the argument
- // names as env->some_string() because we might be compiling before
- // those strings are initialized.
- UNREACHABLE();
- }
+ MaybeLocal<Function> maybe_fun =
+ ScriptCompiler::CompileFunctionInContext(context,
+ &script_source,
+ parameters->size(),
+ parameters->data(),
+ 0,
+ nullptr,
+ options);
- Local<Function> fun;
// This could fail when there are early errors in the native modules,
// e.g. the syntax errors
- if (maybe_fun.IsEmpty() || !maybe_fun.ToLocal(&fun)) {
+ if (maybe_fun.IsEmpty()) {
// In the case of early errors, v8 is already capable of
// decorating the stack for us - note that we use CompileFunctionInContext
// so there is no need to worry about wrappers.
- return scope.Escape(Local<Value>());
+ return MaybeLocal<Value>();
}
+ Local<Function> fun = maybe_fun.ToLocalChecked();
if (use_cache) {
if (optional_env != nullptr) {
// This could happen when Node is run with any v8 flag, but
@@ -279,7 +290,7 @@ Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
}
}
- if (produce_code_cache) {
+ if (result_type == CompilationResultType::kCodeCache) {
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
ScriptCompiler::CreateCodeCacheForFunction(fun));
CHECK_NE(cached_data, nullptr);
@@ -296,10 +307,12 @@ Local<Value> NativeModuleLoader::LookupAndCompile(Local<Context> context,
copied.release(),
cached_data_length,
ArrayBufferCreationMode::kInternalized);
- return scope.Escape(Uint8Array::New(buf, 0, cached_data_length));
+ ret = Uint8Array::New(buf, 0, cached_data_length);
} else {
- return scope.Escape(fun);
+ ret = fun;
}
+
+ return scope.Escape(ret);
}
void NativeModuleLoader::Initialize(Local<Object> target,
diff --git a/src/node_native_module.h b/src/node_native_module.h
index ad9343f199..76725ec0f2 100644
--- a/src/node_native_module.h
+++ b/src/node_native_module.h
@@ -16,10 +16,24 @@ namespace native_module {
using NativeModuleRecordMap = std::map<std::string, UnionBytes>;
using NativeModuleHashMap = std::map<std::string, std::string>;
-// The native (C++) side of the native module compilation.
-// This class should not depend on Environment
+// The native (C++) side of the NativeModule in JS land, which
+// 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 a particular isolate, context, or
+// environment. Rather it should take them as arguments when necessary.
+// The instances of this class are per-process.
class NativeModuleLoader {
public:
+ // kCodeCache indicates that the compilation result should be returned
+ // as a Uint8Array, whereas kFunction indicates that the result should
+ // be returned as a Function.
+ // TODO(joyeecheung): it's possible to always produce code cache
+ // on the main thread and consume them in worker threads, or just
+ // share the cache among all the threads, although
+ // we need to decide whether to do that even when workers are not used.
+ enum class CompilationResultType { kCodeCache, kFunction };
+
NativeModuleLoader();
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
@@ -27,6 +41,18 @@ class NativeModuleLoader {
v8::Local<v8::Object> GetSourceObject(v8::Local<v8::Context> context) const;
v8::Local<v8::String> GetSource(v8::Isolate* isolate, const char* id) const;
+ // Run a script with JS source bundled inside the binary as if it's wrapped
+ // in a function called with a null receiver and arguments specified in C++.
+ // The returned value is empty if an exception is encountered.
+ // JS code run with this method can assume that their top-level
+ // declarations won't affect the global scope.
+ v8::MaybeLocal<v8::Value> CompileAndCall(
+ v8::Local<v8::Context> context,
+ const char* id,
+ std::vector<v8::Local<v8::String>>* parameters,
+ std::vector<v8::Local<v8::Value>>* arguments,
+ Environment* optional_env);
+
private:
static void GetCacheUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
// For legacy process.binding('natives') which is mutable, and for
@@ -48,17 +74,21 @@ class NativeModuleLoader {
void LoadCodeCacheHash(); // Loads data into code_cache_hash_
v8::ScriptCompiler::CachedData* GetCachedData(const char* id) const;
- static v8::Local<v8::Value> CompileAsModule(Environment* env,
- const char* id,
- bool produce_code_cache);
- // TODO(joyeecheung): make this public and reuse it to compile bootstrappers.
+
+ // Compile a script as a NativeModule that can be loaded via
+ // NativeModule.p.require in JS land.
+ static v8::MaybeLocal<v8::Value> CompileAsModule(
+ Environment* env, const char* id, CompilationResultType result_type);
+
// For bootstrappers optional_env may be a nullptr.
- // This method magically knows what parameter it should pass to
- // the function to be compiled.
- v8::Local<v8::Value> LookupAndCompile(v8::Local<v8::Context> context,
- const char* id,
- bool produce_code_cache,
- Environment* optional_env);
+ // If an exception is encountered (e.g. source code contains
+ // syntax error), the returned value is empty.
+ v8::MaybeLocal<v8::Value> LookupAndCompile(
+ v8::Local<v8::Context> context,
+ const char* id,
+ std::vector<v8::Local<v8::String>>* parameters,
+ CompilationResultType result_type,
+ Environment* optional_env);
bool has_code_cache_ = false;
NativeModuleRecordMap source_;