process: run RunBootstrapping in CreateEnvironment
Also creates `CreateMainEnvironment` to encapsulate the code creating the main environment from the provided Isolate data and arguments. PR-URL: https://github.com/nodejs/node/pull/26788 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com>
This commit is contained in:
parent
e02f511dcc
commit
1944265678
@ -20,6 +20,7 @@ const cannotBeRequired = [
|
|||||||
|
|
||||||
'internal/test/binding',
|
'internal/test/binding',
|
||||||
|
|
||||||
|
'internal/bootstrap/environment',
|
||||||
'internal/bootstrap/primordials',
|
'internal/bootstrap/primordials',
|
||||||
'internal/bootstrap/loaders',
|
'internal/bootstrap/loaders',
|
||||||
'internal/bootstrap/node',
|
'internal/bootstrap/node',
|
||||||
|
13
lib/internal/bootstrap/environment.js
Normal file
13
lib/internal/bootstrap/environment.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// This runs necessary preparations to prepare a complete Node.js context
|
||||||
|
// that depends on run time states.
|
||||||
|
// It is currently only intended for preparing contexts for embedders.
|
||||||
|
|
||||||
|
/* global markBootstrapComplete */
|
||||||
|
const {
|
||||||
|
prepareMainThreadExecution
|
||||||
|
} = require('internal/bootstrap/pre_execution');
|
||||||
|
|
||||||
|
prepareMainThreadExecution();
|
||||||
|
markBootstrapComplete();
|
1
node.gyp
1
node.gyp
@ -28,6 +28,7 @@
|
|||||||
'library_files': [
|
'library_files': [
|
||||||
'lib/internal/bootstrap/primordials.js',
|
'lib/internal/bootstrap/primordials.js',
|
||||||
'lib/internal/bootstrap/cache.js',
|
'lib/internal/bootstrap/cache.js',
|
||||||
|
'lib/internal/bootstrap/environment.js',
|
||||||
'lib/internal/bootstrap/loaders.js',
|
'lib/internal/bootstrap/loaders.js',
|
||||||
'lib/internal/bootstrap/node.js',
|
'lib/internal/bootstrap/node.js',
|
||||||
'lib/internal/bootstrap/pre_execution.js',
|
'lib/internal/bootstrap/pre_execution.js',
|
||||||
|
@ -251,6 +251,23 @@ Environment* CreateEnvironment(IsolateData* isolate_data,
|
|||||||
Environment::kOwnsInspector));
|
Environment::kOwnsInspector));
|
||||||
env->InitializeLibuv(per_process::v8_is_profiling);
|
env->InitializeLibuv(per_process::v8_is_profiling);
|
||||||
env->ProcessCliArgs(args, exec_args);
|
env->ProcessCliArgs(args, exec_args);
|
||||||
|
if (RunBootstrapping(env).IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Local<String>> parameters = {
|
||||||
|
env->require_string(),
|
||||||
|
FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
|
||||||
|
std::vector<Local<Value>> arguments = {
|
||||||
|
env->native_module_require(),
|
||||||
|
env->NewFunctionTemplate(MarkBootstrapComplete)
|
||||||
|
->GetFunction(env->context())
|
||||||
|
.ToLocalChecked()};
|
||||||
|
if (ExecuteBootstrapper(
|
||||||
|
env, "internal/bootstrap/environment", ¶meters, &arguments)
|
||||||
|
.IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
151
src/node.cc
151
src/node.cc
@ -200,11 +200,10 @@ void SignalExit(int signo) {
|
|||||||
raise(signo);
|
raise(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MaybeLocal<Value> ExecuteBootstrapper(
|
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
|
||||||
Environment* env,
|
const char* id,
|
||||||
const char* id,
|
std::vector<Local<String>>* parameters,
|
||||||
std::vector<Local<String>>* parameters,
|
std::vector<Local<Value>>* arguments) {
|
||||||
std::vector<Local<Value>>* arguments) {
|
|
||||||
EscapableHandleScope scope(env->isolate());
|
EscapableHandleScope scope(env->isolate());
|
||||||
MaybeLocal<Function> maybe_fn =
|
MaybeLocal<Function> maybe_fn =
|
||||||
per_process::native_module_loader.LookupAndCompile(
|
per_process::native_module_loader.LookupAndCompile(
|
||||||
@ -453,9 +452,7 @@ void LoadEnvironment(Environment* env) {
|
|||||||
// StartMainThreadExecution() make sense for embedders. Pick the
|
// StartMainThreadExecution() make sense for embedders. Pick the
|
||||||
// useful ones out, and allow embedders to customize the entry
|
// useful ones out, and allow embedders to customize the entry
|
||||||
// point more directly without using _third_party_main.js
|
// point more directly without using _third_party_main.js
|
||||||
if (!RunBootstrapping(env).IsEmpty()) {
|
USE(StartMainThreadExecution(env));
|
||||||
USE(StartMainThreadExecution(env));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -780,90 +777,117 @@ void RunBeforeExit(Environment* env) {
|
|||||||
EmitBeforeExit(env);
|
EmitBeforeExit(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int StartNodeWithIsolate(Isolate* isolate,
|
// TODO(joyeecheung): align this with the CreateEnvironment exposed in node.h
|
||||||
IsolateData* isolate_data,
|
// and the environment creation routine in workers somehow.
|
||||||
const std::vector<std::string>& args,
|
inline std::unique_ptr<Environment> CreateMainEnvironment(
|
||||||
const std::vector<std::string>& exec_args) {
|
IsolateData* isolate_data,
|
||||||
|
const std::vector<std::string>& args,
|
||||||
|
const std::vector<std::string>& exec_args,
|
||||||
|
int* exit_code) {
|
||||||
|
Isolate* isolate = isolate_data->isolate();
|
||||||
HandleScope handle_scope(isolate);
|
HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
|
// TODO(addaleax): This should load a real per-Isolate option, currently
|
||||||
|
// this is still effectively per-process.
|
||||||
|
if (isolate_data->options()->track_heap_objects) {
|
||||||
|
isolate->GetHeapProfiler()->StartTrackingHeapObjects(true);
|
||||||
|
}
|
||||||
|
|
||||||
Local<Context> context = NewContext(isolate);
|
Local<Context> context = NewContext(isolate);
|
||||||
Context::Scope context_scope(context);
|
Context::Scope context_scope(context);
|
||||||
int exit_code = 0;
|
|
||||||
Environment env(
|
std::unique_ptr<Environment> env = std::make_unique<Environment>(
|
||||||
isolate_data,
|
isolate_data,
|
||||||
context,
|
context,
|
||||||
static_cast<Environment::Flags>(Environment::kIsMainThread |
|
static_cast<Environment::Flags>(Environment::kIsMainThread |
|
||||||
Environment::kOwnsProcessState |
|
Environment::kOwnsProcessState |
|
||||||
Environment::kOwnsInspector));
|
Environment::kOwnsInspector));
|
||||||
env.InitializeLibuv(per_process::v8_is_profiling);
|
env->InitializeLibuv(per_process::v8_is_profiling);
|
||||||
env.ProcessCliArgs(args, exec_args);
|
env->ProcessCliArgs(args, exec_args);
|
||||||
|
|
||||||
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
|
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
|
||||||
CHECK(!env.inspector_agent()->IsListening());
|
CHECK(!env->inspector_agent()->IsListening());
|
||||||
// Inspector agent can't fail to start, but if it was configured to listen
|
// Inspector agent can't fail to start, but if it was configured to listen
|
||||||
// right away on the websocket port and fails to bind/etc, this will return
|
// right away on the websocket port and fails to bind/etc, this will return
|
||||||
// false.
|
// false.
|
||||||
env.inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "",
|
env->inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "",
|
||||||
env.options()->debug_options(),
|
env->options()->debug_options(),
|
||||||
env.inspector_host_port(),
|
env->inspector_host_port(),
|
||||||
true);
|
true);
|
||||||
if (env.options()->debug_options().inspector_enabled &&
|
if (env->options()->debug_options().inspector_enabled &&
|
||||||
!env.inspector_agent()->IsListening()) {
|
!env->inspector_agent()->IsListening()) {
|
||||||
exit_code = 12; // Signal internal error.
|
*exit_code = 12; // Signal internal error.
|
||||||
goto exit;
|
return env;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// inspector_enabled can't be true if !HAVE_INSPECTOR or !NODE_USE_V8_PLATFORM
|
// inspector_enabled can't be true if !HAVE_INSPECTOR or !NODE_USE_V8_PLATFORM
|
||||||
// - the option parser should not allow that.
|
// - the option parser should not allow that.
|
||||||
CHECK(!env.options()->debug_options().inspector_enabled);
|
CHECK(!env->options()->debug_options().inspector_enabled);
|
||||||
#endif // HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
|
#endif // HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
|
||||||
|
|
||||||
{
|
if (RunBootstrapping(env.get()).IsEmpty()) {
|
||||||
AsyncCallbackScope callback_scope(&env);
|
*exit_code = 1;
|
||||||
env.async_hooks()->push_async_ids(1, 0);
|
|
||||||
LoadEnvironment(&env);
|
|
||||||
env.async_hooks()->pop_async_id(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
return env;
|
||||||
SealHandleScope seal(isolate);
|
}
|
||||||
bool more;
|
|
||||||
env.performance_state()->Mark(
|
|
||||||
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
|
|
||||||
do {
|
|
||||||
uv_run(env.event_loop(), UV_RUN_DEFAULT);
|
|
||||||
|
|
||||||
per_process::v8_platform.DrainVMTasks(isolate);
|
inline int StartNodeWithIsolate(Isolate* isolate,
|
||||||
|
IsolateData* isolate_data,
|
||||||
|
const std::vector<std::string>& args,
|
||||||
|
const std::vector<std::string>& exec_args) {
|
||||||
|
int exit_code = 0;
|
||||||
|
std::unique_ptr<Environment> env =
|
||||||
|
CreateMainEnvironment(isolate_data, args, exec_args, &exit_code);
|
||||||
|
CHECK_NOT_NULL(env);
|
||||||
|
HandleScope handle_scope(env->isolate());
|
||||||
|
Context::Scope context_scope(env->context());
|
||||||
|
|
||||||
more = uv_loop_alive(env.event_loop());
|
if (exit_code == 0) {
|
||||||
if (more && !env.is_stopping()) continue;
|
{
|
||||||
|
AsyncCallbackScope callback_scope(env.get());
|
||||||
|
env->async_hooks()->push_async_ids(1, 0);
|
||||||
|
LoadEnvironment(env.get());
|
||||||
|
env->async_hooks()->pop_async_id(1);
|
||||||
|
}
|
||||||
|
|
||||||
RunBeforeExit(&env);
|
{
|
||||||
|
SealHandleScope seal(isolate);
|
||||||
|
bool more;
|
||||||
|
env->performance_state()->Mark(
|
||||||
|
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
|
||||||
|
do {
|
||||||
|
uv_run(env->event_loop(), UV_RUN_DEFAULT);
|
||||||
|
|
||||||
// Emit `beforeExit` if the loop became alive either after emitting
|
per_process::v8_platform.DrainVMTasks(isolate);
|
||||||
// event, or after running some callbacks.
|
|
||||||
more = uv_loop_alive(env.event_loop());
|
more = uv_loop_alive(env->event_loop());
|
||||||
} while (more == true && !env.is_stopping());
|
if (more && !env->is_stopping()) continue;
|
||||||
env.performance_state()->Mark(
|
|
||||||
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
|
RunBeforeExit(env.get());
|
||||||
|
|
||||||
|
// Emit `beforeExit` if the loop became alive either after emitting
|
||||||
|
// event, or after running some callbacks.
|
||||||
|
more = uv_loop_alive(env->event_loop());
|
||||||
|
} while (more == true && !env->is_stopping());
|
||||||
|
env->performance_state()->Mark(
|
||||||
|
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
env->set_trace_sync_io(false);
|
||||||
|
exit_code = EmitExit(env.get());
|
||||||
|
WaitForInspectorDisconnect(env.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
env.set_trace_sync_io(false);
|
env->set_can_call_into_js(false);
|
||||||
|
env->stop_sub_worker_contexts();
|
||||||
exit_code = EmitExit(&env);
|
|
||||||
|
|
||||||
WaitForInspectorDisconnect(&env);
|
|
||||||
|
|
||||||
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
|
|
||||||
exit:
|
|
||||||
#endif
|
|
||||||
env.set_can_call_into_js(false);
|
|
||||||
env.stop_sub_worker_contexts();
|
|
||||||
uv_tty_reset_mode();
|
uv_tty_reset_mode();
|
||||||
env.RunCleanup();
|
env->RunCleanup();
|
||||||
RunAtExit(&env);
|
RunAtExit(env.get());
|
||||||
|
|
||||||
per_process::v8_platform.DrainVMTasks(isolate);
|
per_process::v8_platform.DrainVMTasks(isolate);
|
||||||
per_process::v8_platform.CancelVMTasks(isolate);
|
per_process::v8_platform.CancelVMTasks(isolate);
|
||||||
|
|
||||||
#if defined(LEAK_SANITIZER)
|
#if defined(LEAK_SANITIZER)
|
||||||
__lsan_do_leak_check();
|
__lsan_do_leak_check();
|
||||||
#endif
|
#endif
|
||||||
@ -891,11 +915,6 @@ inline int StartNodeWithLoopAndArgs(uv_loop_t* event_loop,
|
|||||||
per_process::v8_platform.Platform(),
|
per_process::v8_platform.Platform(),
|
||||||
allocator.get()),
|
allocator.get()),
|
||||||
&FreeIsolateData);
|
&FreeIsolateData);
|
||||||
// TODO(addaleax): This should load a real per-Isolate option, currently
|
|
||||||
// this is still effectively per-process.
|
|
||||||
if (isolate_data->options()->track_heap_objects) {
|
|
||||||
isolate->GetHeapProfiler()->StartTrackingHeapObjects(true);
|
|
||||||
}
|
|
||||||
exit_code =
|
exit_code =
|
||||||
StartNodeWithIsolate(isolate, isolate_data.get(), args, exec_args);
|
StartNodeWithIsolate(isolate, isolate_data.get(), args, exec_args);
|
||||||
}
|
}
|
||||||
|
@ -311,6 +311,8 @@ NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
|
|||||||
|
|
||||||
// TODO(addaleax): Add an official variant using STL containers, and move
|
// TODO(addaleax): Add an official variant using STL containers, and move
|
||||||
// per-Environment options parsing here.
|
// per-Environment options parsing here.
|
||||||
|
// Returns nullptr when the Environment cannot be created e.g. there are
|
||||||
|
// pending JavaScript exceptions.
|
||||||
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
|
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
|
||||||
v8::Local<v8::Context> context,
|
v8::Local<v8::Context> context,
|
||||||
int argc,
|
int argc,
|
||||||
|
@ -302,7 +302,12 @@ v8::MaybeLocal<v8::Value> RunBootstrapping(Environment* env);
|
|||||||
v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
|
v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
|
||||||
const char* main_script_id);
|
const char* main_script_id);
|
||||||
v8::MaybeLocal<v8::Object> GetPerContextExports(v8::Local<v8::Context> context);
|
v8::MaybeLocal<v8::Object> GetPerContextExports(v8::Local<v8::Context> context);
|
||||||
|
v8::MaybeLocal<v8::Value> ExecuteBootstrapper(
|
||||||
|
Environment* env,
|
||||||
|
const char* id,
|
||||||
|
std::vector<v8::Local<v8::String>>* parameters,
|
||||||
|
std::vector<v8::Local<v8::Value>>* arguments);
|
||||||
|
void MarkBootstrapComplete(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
namespace profiler {
|
namespace profiler {
|
||||||
void StartCoverageCollection(Environment* env);
|
void StartCoverageCollection(Environment* env);
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,6 @@ class EnvironmentTestFixture : public NodeTestFixture {
|
|||||||
1, *argv,
|
1, *argv,
|
||||||
argv.nr_args(), *argv);
|
argv.nr_args(), *argv);
|
||||||
CHECK_NE(nullptr, environment_);
|
CHECK_NE(nullptr, environment_);
|
||||||
// TODO(addaleax): Make this a public API.
|
|
||||||
CHECK(!RunBootstrapping(environment_).IsEmpty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Env() {
|
~Env() {
|
||||||
|
@ -23,6 +23,24 @@ class EnvironmentTest : public EnvironmentTestFixture {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST_F(EnvironmentTest, PreExeuctionPreparation) {
|
||||||
|
const v8::HandleScope handle_scope(isolate_);
|
||||||
|
const Argv argv;
|
||||||
|
Env env {handle_scope, argv};
|
||||||
|
|
||||||
|
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
|
||||||
|
|
||||||
|
const char* run_script = "process.argv0";
|
||||||
|
v8::Local<v8::Script> script = v8::Script::Compile(
|
||||||
|
context,
|
||||||
|
v8::String::NewFromOneByte(isolate_,
|
||||||
|
reinterpret_cast<const uint8_t*>(run_script),
|
||||||
|
v8::NewStringType::kNormal).ToLocalChecked())
|
||||||
|
.ToLocalChecked();
|
||||||
|
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
|
||||||
|
CHECK(result->IsString());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(EnvironmentTest, AtExitWithEnvironment) {
|
TEST_F(EnvironmentTest, AtExitWithEnvironment) {
|
||||||
const v8::HandleScope handle_scope(isolate_);
|
const v8::HandleScope handle_scope(isolate_);
|
||||||
const Argv argv;
|
const Argv argv;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user