summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGus Caplan <me@gus.host>2018-01-13 23:35:51 -0800
committerTimothy Gu <timothygu99@gmail.com>2018-01-30 17:00:57 -0800
commit0993fbe5b213d0fe746c3162bcda85f6c66bb552 (patch)
treef0a1ffef2ab24f1da963a23a43f3dd58eed5bba0 /src
parent2033a9f4362ee46b0fbddf9caf9cf6238391561e (diff)
downloadandroid-node-v8-0993fbe5b213d0fe746c3162bcda85f6c66bb552.tar.gz
android-node-v8-0993fbe5b213d0fe746c3162bcda85f6c66bb552.tar.bz2
android-node-v8-0993fbe5b213d0fe746c3162bcda85f6c66bb552.zip
vm: add modules
Adds vm.Module, which wraps around ModuleWrap to provide an interface for developers to work with modules in a more reflective manner. Co-authored-by: Timothy Gu <timothygu99@gmail.com> PR-URL: https://github.com/nodejs/node/pull/17560 Reviewed-By: Michaƫl Zasso <targos@protonmail.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/module_wrap.cc182
-rw-r--r--src/module_wrap.h8
-rw-r--r--src/node.cc10
-rw-r--r--src/node_config.cc3
-rw-r--r--src/node_internals.h5
5 files changed, 174 insertions, 34 deletions
diff --git a/src/module_wrap.cc b/src/module_wrap.cc
index b8970d4fb3..ba07fcdc79 100644
--- a/src/module_wrap.cc
+++ b/src/module_wrap.cc
@@ -7,12 +7,15 @@
#include "node_url.h"
#include "util-inl.h"
#include "node_internals.h"
+#include "node_contextify.h"
+#include "node_watchdog.h"
namespace node {
namespace loader {
using node::url::URL;
using node::url::URL_FLAGS_FAILED;
+using v8::Array;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
@@ -58,6 +61,7 @@ ModuleWrap::~ModuleWrap() {
}
module_.Reset();
+ context_.Reset();
}
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
@@ -70,12 +74,6 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
return;
}
- if (args.Length() != 2) {
- env->ThrowError("constructor must have exactly 2 arguments "
- "(string, string)");
- return;
- }
-
if (!args[0]->IsString()) {
env->ThrowError("first argument is not a string");
return;
@@ -90,20 +88,39 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
Local<String> url = args[1].As<String>();
+ Local<Object> that = args.This();
+
+ Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
+ TryCatch try_catch(isolate);
+
+ Local<Value> options = args[2];
+ MaybeLocal<Integer> line_offset = contextify::GetLineOffsetArg(env, options);
+ MaybeLocal<Integer> column_offset =
+ contextify::GetColumnOffsetArg(env, options);
+ MaybeLocal<Context> maybe_context = contextify::GetContextArg(env, options);
+
+
+ if (try_catch.HasCaught()) {
+ no_abort_scope.Close();
+ try_catch.ReThrow();
+ return;
+ }
+
+ Local<Context> context = maybe_context.FromMaybe(that->CreationContext());
Local<Module> module;
// compile
{
ScriptOrigin origin(url,
- Integer::New(isolate, 0), // line offset
- Integer::New(isolate, 0), // column offset
+ line_offset.ToLocalChecked(), // line offset
+ column_offset.ToLocalChecked(), // column offset
False(isolate), // is cross origin
Local<Integer>(), // script id
Local<Value>(), // source map URL
False(isolate), // is opaque (?)
False(isolate), // is WASM
True(isolate)); // is ES6 module
- TryCatch try_catch(isolate);
+ Context::Scope context_scope(context);
ScriptCompiler::Source source(source_text, origin);
if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
CHECK(try_catch.HasCaught());
@@ -116,8 +133,6 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
}
}
- Local<Object> that = args.This();
- Local<Context> context = that->CreationContext();
Local<String> url_str = FIXED_ONE_BYTE_STRING(isolate, "url");
if (!that->Set(context, url_str, url).FromMaybe(false)) {
@@ -125,6 +140,7 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
}
ModuleWrap* obj = new ModuleWrap(env, that, module, url);
+ obj->context_.Reset(isolate, context);
env->module_map.emplace(module->GetIdentityHash(), obj);
Wrap(that, obj);
@@ -141,15 +157,19 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
return;
}
- Local<Function> resolver_arg = args[0].As<Function>();
-
Local<Object> that = args.This();
- ModuleWrap* obj = Unwrap<ModuleWrap>(that);
- CHECK_NE(obj, nullptr);
- Local<Context> mod_context = that->CreationContext();
- if (obj->linked_) return;
+
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, that);
+
+ if (obj->linked_)
+ return;
obj->linked_ = true;
- Local<Module> module(obj->module_.Get(isolate));
+
+ Local<Function> resolver_arg = args[0].As<Function>();
+
+ Local<Context> mod_context = obj->context_.Get(isolate);
+ Local<Module> module = obj->module_.Get(isolate);
// call the dependency resolve callbacks
for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
@@ -181,11 +201,9 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
- Local<Object> that = args.This();
- Local<Context> context = that->CreationContext();
-
- ModuleWrap* obj = Unwrap<ModuleWrap>(that);
- CHECK_NE(obj, nullptr);
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
+ Local<Context> context = obj->context_.Get(isolate);
Local<Module> module = obj->module_.Get(isolate);
TryCatch try_catch(isolate);
Maybe<bool> ok =
@@ -208,14 +226,60 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
}
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
- Local<Object> that = args.This();
- Local<Context> context = that->CreationContext();
- ModuleWrap* obj = Unwrap<ModuleWrap>(that);
- CHECK_NE(obj, nullptr);
- MaybeLocal<Value> result = obj->module_.Get(isolate)->Evaluate(context);
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
+ Local<Context> context = obj->context_.Get(isolate);
+ Local<Module> module = obj->module_.Get(isolate);
- if (result.IsEmpty()) {
+ Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
+ TryCatch try_catch(isolate);
+ Maybe<int64_t> maybe_timeout =
+ contextify::GetTimeoutArg(env, args[0]);
+ Maybe<bool> maybe_break_on_sigint =
+ contextify::GetBreakOnSigintArg(env, args[0]);
+
+ if (try_catch.HasCaught()) {
+ no_abort_scope.Close();
+ try_catch.ReThrow();
+ return;
+ }
+
+ int64_t timeout = maybe_timeout.ToChecked();
+ bool break_on_sigint = maybe_break_on_sigint.ToChecked();
+
+ bool timed_out = false;
+ bool received_signal = false;
+ MaybeLocal<Value> result;
+ if (break_on_sigint && timeout != -1) {
+ Watchdog wd(isolate, timeout, &timed_out);
+ SigintWatchdog swd(isolate, &received_signal);
+ result = module->Evaluate(context);
+ } else if (break_on_sigint) {
+ SigintWatchdog swd(isolate, &received_signal);
+ result = module->Evaluate(context);
+ } else if (timeout != -1) {
+ Watchdog wd(isolate, timeout, &timed_out);
+ result = module->Evaluate(context);
+ } else {
+ result = module->Evaluate(context);
+ }
+
+ if (timed_out || received_signal) {
+ // It is possible that execution was terminated by another timeout in
+ // which this timeout is nested, so check whether one of the watchdogs
+ // from this invocation is responsible for termination.
+ if (timed_out) {
+ env->ThrowError("Script execution timed out.");
+ } else if (received_signal) {
+ env->ThrowError("Script execution interrupted.");
+ }
+ env->isolate()->CancelTerminateExecution();
+ }
+
+ if (try_catch.HasCaught()) {
+ try_catch.ReThrow();
return;
}
@@ -225,9 +289,8 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
- Local<Object> that = args.This();
- ModuleWrap* obj = Unwrap<ModuleWrap>(that);
- CHECK_NE(obj, nullptr);
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
Local<Module> module = obj->module_.Get(isolate);
@@ -245,6 +308,44 @@ void ModuleWrap::Namespace(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(result);
}
+void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
+
+ Local<Module> module = obj->module_.Get(isolate);
+
+ args.GetReturnValue().Set(module->GetStatus());
+}
+
+void ModuleWrap::GetStaticDependencySpecifiers(
+ const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
+
+ Local<Module> module = obj->module_.Get(env->isolate());
+
+ int count = module->GetModuleRequestsLength();
+
+ Local<Array> specifiers = Array::New(env->isolate(), count);
+
+ for (int i = 0; i < count; i++)
+ specifiers->Set(env->context(), i, module->GetModuleRequest(i)).FromJust();
+
+ args.GetReturnValue().Set(specifiers);
+}
+
+void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ ModuleWrap* obj;
+ ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
+
+ Local<Module> module = obj->module_.Get(isolate);
+
+ args.GetReturnValue().Set(module->GetException());
+}
+
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
Local<String> specifier,
Local<Module> referrer) {
@@ -636,12 +737,29 @@ void ModuleWrap::Initialize(Local<Object> target,
env->SetProtoMethod(tpl, "instantiate", Instantiate);
env->SetProtoMethod(tpl, "evaluate", Evaluate);
env->SetProtoMethod(tpl, "namespace", Namespace);
+ env->SetProtoMethod(tpl, "getStatus", GetStatus);
+ env->SetProtoMethod(tpl, "getError", GetError);
+ env->SetProtoMethod(tpl, "getStaticDependencySpecifiers",
+ GetStaticDependencySpecifiers);
target->Set(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"), tpl->GetFunction());
env->SetMethod(target, "resolve", node::loader::ModuleWrap::Resolve);
env->SetMethod(target,
"setImportModuleDynamicallyCallback",
node::loader::ModuleWrap::SetImportModuleDynamicallyCallback);
+
+#define V(name) \
+ target->Set(context, \
+ FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
+ Integer::New(env->isolate(), Module::Status::name)) \
+ .FromJust()
+ V(kUninstantiated);
+ V(kInstantiating);
+ V(kInstantiated);
+ V(kEvaluating);
+ V(kEvaluated);
+ V(kErrored);
+#undef V
}
} // namespace loader
diff --git a/src/module_wrap.h b/src/module_wrap.h
index ec4d6bf577..bedf665165 100644
--- a/src/module_wrap.h
+++ b/src/module_wrap.h
@@ -36,8 +36,11 @@ class ModuleWrap : public BaseObject {
static void Instantiate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Evaluate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Namespace(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void GetUrl(v8::Local<v8::String> property,
- const v8::PropertyCallbackInfo<v8::Value>& info);
+ static void GetStatus(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void GetError(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void GetStaticDependencySpecifiers(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+
static void Resolve(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetImportModuleDynamicallyCallback(
const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -50,6 +53,7 @@ class ModuleWrap : public BaseObject {
v8::Persistent<v8::String> url_;
bool linked_ = false;
std::unordered_map<std::string, v8::Persistent<v8::Promise>> resolve_cache_;
+ v8::Persistent<v8::Context> context_;
};
} // namespace loader
diff --git a/src/node.cc b/src/node.cc
index 2e1d08f5b5..c82bd73348 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -240,6 +240,11 @@ bool config_preserve_symlinks = false;
// that is used by lib/module.js
bool config_experimental_modules = false;
+// Set in node.cc by ParseArgs when --experimental-vm-modules is used.
+// Used in node_config.cc to set a constant on process.binding('config')
+// that is used by lib/vm.js
+bool config_experimental_vm_modules = false;
+
// Set in node.cc by ParseArgs when --loader is used.
// Used in node_config.cc to set a constant on process.binding('config')
// that is used by lib/internal/bootstrap_node.js
@@ -3424,6 +3429,8 @@ static void PrintHelp() {
" --preserve-symlinks preserve symbolic links when resolving\n"
" --experimental-modules experimental ES Module support\n"
" and caching modules\n"
+ " --experimental-vm-modules experimental ES Module support\n"
+ " in vm module\n"
#endif
"\n"
"Environment variables:\n"
@@ -3503,6 +3510,7 @@ static void CheckIfAllowedInEnv(const char* exe, bool is_env,
"--napi-modules",
"--expose-http2", // keep as a non-op through v9.x
"--experimental-modules",
+ "--experimental-vm-modules",
"--loader",
"--trace-warnings",
"--redirect-warnings",
@@ -3670,6 +3678,8 @@ static void ParseArgs(int* argc,
config_preserve_symlinks = true;
} else if (strcmp(arg, "--experimental-modules") == 0) {
config_experimental_modules = true;
+ } else if (strcmp(arg, "--experimental-vm-modules") == 0) {
+ config_experimental_vm_modules = true;
} else if (strcmp(arg, "--loader") == 0) {
const char* module = argv[index + 1];
if (!config_experimental_modules) {
diff --git a/src/node_config.cc b/src/node_config.cc
index 2e9ad2ed13..cac551ad2c 100644
--- a/src/node_config.cc
+++ b/src/node_config.cc
@@ -82,6 +82,9 @@ static void InitConfig(Local<Object> target,
}
}
+ if (config_experimental_vm_modules)
+ READONLY_BOOLEAN_PROPERTY("experimentalVMModules");
+
if (config_pending_deprecation)
READONLY_BOOLEAN_PROPERTY("pendingDeprecation");
diff --git a/src/node_internals.h b/src/node_internals.h
index 0001d15172..b3e1f5cd9f 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -172,6 +172,11 @@ extern bool config_preserve_symlinks;
// that is used by lib/module.js
extern bool config_experimental_modules;
+// Set in node.cc by ParseArgs when --experimental-vm-modules is used.
+// Used in node_config.cc to set a constant on process.binding('config')
+// that is used by lib/vm.js
+extern bool config_experimental_vm_modules;
+
// Set in node.cc by ParseArgs when --loader is used.
// Used in node_config.cc to set a constant on process.binding('config')
// that is used by lib/internal/bootstrap_node.js