summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/env.cc13
-rw-r--r--src/env.h26
-rw-r--r--src/node.cc216
-rw-r--r--src/node_internals.h5
-rw-r--r--src/node_native_module.cc20
-rw-r--r--src/node_native_module.h24
-rw-r--r--src/node_worker.cc12
7 files changed, 192 insertions, 124 deletions
diff --git a/src/env.cc b/src/env.cc
index 78ed42f89a..8ecab92df7 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -332,9 +332,20 @@ void Environment::Start(bool start_profiler_idle_notifier) {
uv_key_set(&thread_local_env, this);
}
-MaybeLocal<Object> Environment::CreateProcessObject(
+MaybeLocal<Object> Environment::ProcessCliArgs(
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args) {
+ if (args.size() > 1) {
+ std::string first_arg = args[1];
+ if (first_arg == "inspect") {
+ execution_mode_ = ExecutionMode::kInspect;
+ } else if (first_arg == "debug") {
+ execution_mode_ = ExecutionMode::kDebug;
+ } else if (first_arg != "-") {
+ execution_mode_ = ExecutionMode::kRunMainModule;
+ }
+ }
+
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACING_CATEGORY_NODE1(environment)) != 0) {
auto traced_value = tracing::TracedValue::Create();
diff --git a/src/env.h b/src/env.h
index 2fab688fc8..139694104e 100644
--- a/src/env.h
+++ b/src/env.h
@@ -315,7 +315,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(write_host_object_string, "_writeHostObject") \
V(write_queue_size_string, "writeQueueSize") \
V(x_forwarded_string, "x-forwarded-for") \
- V(zero_return_string, "ZERO_RETURN") \
+ V(zero_return_string, "ZERO_RETURN")
#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
V(as_external, v8::External) \
@@ -355,11 +355,13 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(http2session_on_stream_trailers_function, v8::Function) \
V(http2settings_constructor_template, v8::ObjectTemplate) \
V(http2stream_constructor_template, v8::ObjectTemplate) \
+ V(internal_binding_loader, v8::Function) \
V(immediate_callback_function, v8::Function) \
V(inspector_console_extension_installer, v8::Function) \
V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \
V(message_port, v8::Object) \
V(message_port_constructor_template, v8::FunctionTemplate) \
+ V(native_module_require, v8::Function) \
V(performance_entry_callback, v8::Function) \
V(performance_entry_template, v8::Function) \
V(pipe_constructor_template, v8::FunctionTemplate) \
@@ -371,7 +373,6 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(script_data_constructor_function, v8::Function) \
V(secure_context_constructor_template, v8::FunctionTemplate) \
V(shutdown_wrap_template, v8::ObjectTemplate) \
- V(start_execution_function, v8::Function) \
V(tcp_constructor_template, v8::FunctionTemplate) \
V(tick_callback_function, v8::Function) \
V(timers_callback_function, v8::Function) \
@@ -611,7 +612,7 @@ class Environment {
~Environment();
void Start(bool start_profiler_idle_notifier);
- v8::MaybeLocal<v8::Object> CreateProcessObject(
+ v8::MaybeLocal<v8::Object> ProcessCliArgs(
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args);
@@ -928,6 +929,24 @@ class Environment {
inline std::shared_ptr<EnvironmentOptions> options();
inline std::shared_ptr<HostPort> inspector_host_port();
+ enum class ExecutionMode {
+ kDefault,
+ kInspect, // node inspect
+ kDebug, // node debug
+ kPrintHelp, // node --help
+ kPrintBashCompletion, // node --completion-bash
+ kProfProcess, // node --prof-process
+ kEvalString, // node --eval without --interactive
+ kCheckSyntax, // node --check (incompatible with --eval)
+ kRepl,
+ kEvalStdin,
+ kRunMainModule
+ };
+
+ inline ExecutionMode execution_mode() { return execution_mode_; }
+
+ inline void set_execution_mode(ExecutionMode mode) { execution_mode_ = mode; }
+
private:
inline void CreateImmediate(native_immediate_callback cb,
void* data,
@@ -937,6 +956,7 @@ class Environment {
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg);
+ ExecutionMode execution_mode_ = ExecutionMode::kDefault;
std::list<binding::DLib> loaded_addons_;
v8::Isolate* const isolate_;
IsolateData* const isolate_data_;
diff --git a/src/node.cc b/src/node.cc
index 881ace6e42..e67b16af83 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -100,6 +100,7 @@
#if defined(_MSC_VER)
#include <direct.h>
#include <io.h>
+#define STDIN_FILENO 0
#else
#include <pthread.h>
#include <sys/resource.h> // getrlimit, setrlimit
@@ -114,6 +115,7 @@ using v8::Array;
using v8::Boolean;
using v8::Context;
using v8::DEFAULT;
+using v8::EscapableHandleScope;
using v8::Exception;
using v8::Function;
using v8::FunctionCallbackInfo;
@@ -605,8 +607,20 @@ static MaybeLocal<Value> ExecuteBootstrapper(
const char* id,
std::vector<Local<String>>* parameters,
std::vector<Local<Value>>* arguments) {
- MaybeLocal<Value> ret = per_process::native_module_loader.CompileAndCall(
- env->context(), id, parameters, arguments, env);
+ EscapableHandleScope scope(env->isolate());
+ MaybeLocal<Function> maybe_fn =
+ per_process::native_module_loader.LookupAndCompile(
+ env->context(), id, parameters, env);
+
+ if (maybe_fn.IsEmpty()) {
+ return MaybeLocal<Value>();
+ }
+
+ Local<Function> fn = maybe_fn.ToLocalChecked();
+ MaybeLocal<Value> result = fn->Call(env->context(),
+ Undefined(env->isolate()),
+ arguments->size(),
+ arguments->data());
// If there was an error during bootstrap then it was either handled by the
// FatalException handler or it's unrecoverable (e.g. max call stack
@@ -615,44 +629,17 @@ static MaybeLocal<Value> ExecuteBootstrapper(
// There are only two ways to have a stack size > 1: 1) the user manually
// called MakeCallback or 2) user awaited during bootstrap, which triggered
// _tickCallback().
- if (ret.IsEmpty()) {
+ if (result.IsEmpty()) {
env->async_hooks()->clear_async_id_stack();
}
- return ret;
-}
-
-void LoadEnvironment(Environment* env) {
- RunBootstrapping(env);
-
- // To allow people to extend Node in different ways, this hook allows
- // one to drop a file lib/_third_party_main.js into the build
- // directory which will be executed instead of Node's normal loading.
- if (per_process::native_module_loader.Exists("_third_party_main")) {
- StartExecution(env, "_third_party_main");
- } else {
- // TODO(joyeecheung): create different scripts for different
- // execution modes:
- // - `main_thread_main.js` when env->is_main_thread()
- // - `worker_thread_main.js` when !env->is_main_thread()
- // - `run_third_party_main.js` for `_third_party_main`
- // - `inspect_main.js` for `node inspect`
- // - `mkcodecache_main.js` for the code cache generator
- // - `print_help_main.js` for --help
- // - `bash_completion_main.js` for --completion-bash
- // - `internal/v8_prof_processor` for --prof-process
- // And leave bootstrap/node.js dedicated to the setup of the environment.
- // We may want to move this switch out of LoadEnvironment, especially for
- // the per-process options.
- StartExecution(env, nullptr);
- }
+ return scope.EscapeMaybe(result);
}
-void RunBootstrapping(Environment* env) {
+MaybeLocal<Value> RunBootstrapping(Environment* env) {
CHECK(!env->has_run_bootstrapping_code());
- env->set_has_run_bootstrapping_code(true);
- HandleScope handle_scope(env->isolate());
+ EscapableHandleScope scope(env->isolate());
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
@@ -702,14 +689,24 @@ void RunBootstrapping(Environment* env) {
Boolean::New(isolate,
env->options()->expose_internals)};
- MaybeLocal<Value> loader_exports;
// Bootstrap internal loaders
- loader_exports = ExecuteBootstrapper(
+ MaybeLocal<Value> loader_exports = ExecuteBootstrapper(
env, "internal/bootstrap/loaders", &loaders_params, &loaders_args);
if (loader_exports.IsEmpty()) {
- return;
+ return MaybeLocal<Value>();
}
+ Local<Object> loader_exports_obj =
+ loader_exports.ToLocalChecked().As<Object>();
+ Local<Value> internal_binding_loader =
+ loader_exports_obj->Get(context, env->internal_binding_string())
+ .ToLocalChecked();
+ env->set_internal_binding_loader(internal_binding_loader.As<Function>());
+
+ Local<Value> require =
+ loader_exports_obj->Get(context, env->require_string()).ToLocalChecked();
+ env->set_native_module_require(require.As<Function>());
+
// process, loaderExports, isMainThread
std::vector<Local<String>> node_params = {
env->process_string(),
@@ -717,43 +714,107 @@ void RunBootstrapping(Environment* env) {
FIXED_ONE_BYTE_STRING(isolate, "isMainThread")};
std::vector<Local<Value>> node_args = {
process,
- loader_exports.ToLocalChecked(),
+ loader_exports_obj,
Boolean::New(isolate, env->is_main_thread())};
- Local<Value> start_execution;
- if (!ExecuteBootstrapper(
- env, "internal/bootstrap/node", &node_params, &node_args)
- .ToLocal(&start_execution)) {
- return;
- }
+ MaybeLocal<Value> result = ExecuteBootstrapper(
+ env, "internal/bootstrap/node", &node_params, &node_args);
- if (start_execution->IsFunction())
- env->set_start_execution_function(start_execution.As<Function>());
+ env->set_has_run_bootstrapping_code(true);
+
+ return scope.EscapeMaybe(result);
}
-void StartExecution(Environment* env, const char* main_script_id) {
- HandleScope handle_scope(env->isolate());
- // We have to use Local<>::New because of the optimized way in which we access
- // the object in the env->...() getters, which does not play well with
- // resetting the handle while we're accessing the object through the Local<>.
- Local<Function> start_execution =
- Local<Function>::New(env->isolate(), env->start_execution_function());
- env->set_start_execution_function(Local<Function>());
-
- if (start_execution.IsEmpty()) return;
-
- Local<Value> main_script_v;
- if (main_script_id == nullptr) {
- // TODO(joyeecheung): make this mandatory - we may also create an overload
- // for main_script that is a Local<Function>.
- main_script_v = Undefined(env->isolate());
- } else {
- main_script_v = OneByteString(env->isolate(), main_script_id);
+void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ env->performance_state()->Mark(
+ performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
+}
+
+MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
+ EscapableHandleScope scope(env->isolate());
+ CHECK_NE(main_script_id, nullptr);
+
+ std::vector<Local<String>> parameters = {
+ env->process_string(),
+ env->require_string(),
+ env->internal_binding_string(),
+ FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
+
+ std::vector<Local<Value>> arguments = {
+ env->process_object(),
+ env->native_module_require(),
+ env->internal_binding_loader(),
+ env->NewFunctionTemplate(MarkBootstrapComplete)
+ ->GetFunction(env->context())
+ .ToLocalChecked()};
+
+ MaybeLocal<Value> result =
+ ExecuteBootstrapper(env, main_script_id, &parameters, &arguments);
+ return scope.EscapeMaybe(result);
+}
+
+MaybeLocal<Value> StartMainThreadExecution(Environment* env) {
+ // To allow people to extend Node in different ways, this hook allows
+ // one to drop a file lib/_third_party_main.js into the build
+ // directory which will be executed instead of Node's normal loading.
+ if (per_process::native_module_loader.Exists("_third_party_main")) {
+ return StartExecution(env, "internal/main/run_third_party_main");
+ }
+
+ if (env->execution_mode() == Environment::ExecutionMode::kInspect ||
+ env->execution_mode() == Environment::ExecutionMode::kDebug) {
+ return StartExecution(env, "internal/main/inspect");
+ }
+
+ if (per_process::cli_options->print_help) {
+ env->set_execution_mode(Environment::ExecutionMode::kPrintHelp);
+ return StartExecution(env, "internal/main/print_help");
+ }
+
+ if (per_process::cli_options->print_bash_completion) {
+ env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion);
+ return StartExecution(env, "internal/main/print_bash_completion");
+ }
+
+ if (env->options()->prof_process) {
+ env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion);
+ return StartExecution(env, "internal/main/prof_process");
+ }
+
+ // -e/--eval without -i/--interactive
+ if (env->options()->has_eval_string && !env->options()->force_repl) {
+ env->set_execution_mode(Environment::ExecutionMode::kEvalString);
+ return StartExecution(env, "internal/main/eval_string");
+ }
+
+ if (env->options()->syntax_check_only) {
+ env->set_execution_mode(Environment::ExecutionMode::kCheckSyntax);
+ return StartExecution(env, "internal/main/check_syntax");
+ }
+
+ if (env->execution_mode() == Environment::ExecutionMode::kRunMainModule) {
+ return StartExecution(env, "internal/main/run_main_module");
+ }
+
+ if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) {
+ env->set_execution_mode(Environment::ExecutionMode::kRepl);
+ return StartExecution(env, "internal/main/repl");
}
- Local<Value> argv[] = {main_script_v};
- USE(start_execution->Call(
- env->context(), Undefined(env->isolate()), arraysize(argv), argv));
+ env->set_execution_mode(Environment::ExecutionMode::kEvalStdin);
+ return StartExecution(env, "internal/main/eval_stdin");
+}
+
+void LoadEnvironment(Environment* env) {
+ CHECK(env->is_main_thread());
+ // TODO(joyeecheung): Not all of the execution modes in
+ // StartMainThreadExecution() make sense for embedders. Pick the
+ // useful ones out, and allow embedders to customize the entry
+ // point more directly without using _third_party_main.js
+ if (!RunBootstrapping(env).IsEmpty()) {
+ USE(StartMainThreadExecution(env));
+ }
}
@@ -1180,7 +1241,7 @@ Environment* CreateEnvironment(IsolateData* isolate_data,
std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
Environment* env = new Environment(isolate_data, context);
env->Start(per_process::v8_is_profiling);
- env->CreateProcessObject(args, exec_args);
+ env->ProcessCliArgs(args, exec_args);
return env;
}
@@ -1220,7 +1281,7 @@ void FreePlatform(MultiIsolatePlatform* platform) {
Local<Context> NewContext(Isolate* isolate,
Local<ObjectTemplate> object_template) {
- auto context = Context::New(isolate, nullptr, object_template);
+ Local<Context> context = Context::New(isolate, nullptr, object_template);
if (context.IsEmpty()) return context;
HandleScope handle_scope(isolate);
@@ -1233,12 +1294,19 @@ Local<Context> NewContext(Isolate* isolate,
std::vector<Local<String>> parameters = {
FIXED_ONE_BYTE_STRING(isolate, "global")};
- std::vector<Local<Value>> arguments = {context->Global()};
- MaybeLocal<Value> result = per_process::native_module_loader.CompileAndCall(
- context, "internal/per_context", &parameters, &arguments, nullptr);
+ Local<Value> arguments[] = {context->Global()};
+ MaybeLocal<Function> maybe_fn =
+ per_process::native_module_loader.LookupAndCompile(
+ context, "internal/per_context", &parameters, nullptr);
+ if (maybe_fn.IsEmpty()) {
+ return Local<Context>();
+ }
+ Local<Function> fn = maybe_fn.ToLocalChecked();
+ MaybeLocal<Value> result =
+ fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
+ // Execution failed during context creation.
+ // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
if (result.IsEmpty()) {
- // Execution failed during context creation.
- // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
return Local<Context>();
}
}
@@ -1255,7 +1323,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
Context::Scope context_scope(context);
Environment env(isolate_data, context);
env.Start(per_process::v8_is_profiling);
- env.CreateProcessObject(args, exec_args);
+ env.ProcessCliArgs(args, exec_args);
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
CHECK(!env.inspector_agent()->IsListening());
diff --git a/src/node_internals.h b/src/node_internals.h
index 0d4fe74ebf..bf66c77e6f 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -268,8 +268,9 @@ bool SafeGetenv(const char* key, std::string* text);
void DefineZlibConstants(v8::Local<v8::Object> target);
-void RunBootstrapping(Environment* env);
-void StartExecution(Environment* env, const char* main_script_id);
+v8::MaybeLocal<v8::Value> RunBootstrapping(Environment* env);
+v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
+ const char* main_script_id);
} // namespace node
diff --git a/src/node_native_module.cc b/src/node_native_module.cc
index 27456dd546..675495e34b 100644
--- a/src/node_native_module.cc
+++ b/src/node_native_module.cc
@@ -175,26 +175,6 @@ void NativeModuleLoader::CompileFunction(
}
}
-// 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<Function> compiled =
- per_process::native_module_loader.LookupAndCompile(
- context, id, parameters, nullptr);
- if (compiled.IsEmpty()) {
- return MaybeLocal<Value>();
- }
- Local<Function> fn = compiled.ToLocalChecked().As<Function>();
- return fn->Call(
- context, v8::Null(isolate), arguments->size(), arguments->data());
-}
-
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(Environment* env,
const char* id) {
std::vector<Local<String>> parameters = {env->exports_string(),
diff --git a/src/node_native_module.h b/src/node_native_module.h
index 62c417a0b6..be1fc92a76 100644
--- a/src/node_native_module.h
+++ b/src/node_native_module.h
@@ -42,20 +42,17 @@ class NativeModuleLoader {
// Returns config.gypi as a JSON string
v8::Local<v8::String> GetConfigString(v8::Isolate* isolate) 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(
+ bool Exists(const char* id);
+
+ // For bootstrappers optional_env may be a nullptr.
+ // If an exception is encountered (e.g. source code contains
+ // syntax error), the returned value is empty.
+ v8::MaybeLocal<v8::Function> LookupAndCompile(
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);
- bool Exists(const char* id);
-
private:
static void GetCacheUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
// Passing ids of builtin module source code into JS land as
@@ -87,15 +84,6 @@ class NativeModuleLoader {
static v8::MaybeLocal<v8::Function> CompileAsModule(Environment* env,
const char* id);
- // For bootstrappers optional_env may be a nullptr.
- // If an exception is encountered (e.g. source code contains
- // syntax error), the returned value is empty.
- v8::MaybeLocal<v8::Function> LookupAndCompile(
- v8::Local<v8::Context> context,
- const char* id,
- std::vector<v8::Local<v8::String>>* parameters,
- Environment* optional_env);
-
NativeModuleRecordMap source_;
NativeModuleCacheMap code_cache_;
UnionBytes config_;
diff --git a/src/node_worker.cc b/src/node_worker.cc
index e5ba438bc1..4b78d65392 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -133,8 +133,8 @@ Worker::Worker(Environment* env,
env_->set_thread_id(thread_id_);
env_->Start(env->profiler_idle_notifier_started());
- env_->CreateProcessObject(std::vector<std::string>{},
- std::vector<std::string>{});
+ env_->ProcessCliArgs(std::vector<std::string>{},
+ std::vector<std::string>{});
// Done while on the parent thread
AddWorkerInspector(env, env_.get(), thread_id_, url_);
}
@@ -192,10 +192,10 @@ void Worker::Run() {
HandleScope handle_scope(isolate_);
Environment::AsyncCallbackScope callback_scope(env_.get());
env_->async_hooks()->push_async_ids(1, 0);
- RunBootstrapping(env_.get());
- // TODO(joyeecheung): create a main script for worker threads
- // that starts listening on the message port.
- StartExecution(env_.get(), nullptr);
+ if (!RunBootstrapping(env_.get()).IsEmpty()) {
+ USE(StartExecution(env_.get(), "internal/main/worker_thread"));
+ }
+
env_->async_hooks()->pop_async_id(1);
Debug(this, "Loaded environment for worker %llu", thread_id_);