-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
process: run RunBootstrapping in CreateEnvironment #26788
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -200,11 +200,10 @@ void SignalExit(int signo) { | |
raise(signo); | ||
} | ||
|
||
static MaybeLocal<Value> ExecuteBootstrapper( | ||
Environment* env, | ||
const char* id, | ||
std::vector<Local<String>>* parameters, | ||
std::vector<Local<Value>>* arguments) { | ||
MaybeLocal<Value> ExecuteBootstrapper(Environment* env, | ||
const char* id, | ||
std::vector<Local<String>>* parameters, | ||
std::vector<Local<Value>>* arguments) { | ||
EscapableHandleScope scope(env->isolate()); | ||
MaybeLocal<Function> maybe_fn = | ||
per_process::native_module_loader.LookupAndCompile( | ||
|
@@ -453,9 +452,7 @@ void LoadEnvironment(Environment* env) { | |
// 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)); | ||
} | ||
USE(StartMainThreadExecution(env)); | ||
} | ||
|
||
|
||
|
@@ -780,90 +777,117 @@ void RunBeforeExit(Environment* env) { | |
EmitBeforeExit(env); | ||
} | ||
|
||
inline int StartNodeWithIsolate(Isolate* isolate, | ||
IsolateData* isolate_data, | ||
const std::vector<std::string>& args, | ||
const std::vector<std::string>& exec_args) { | ||
// TODO(joyeecheung): align this with the CreateEnvironment exposed in node.h | ||
// and the environment creation routine in workers somehow. | ||
inline std::unique_ptr<Environment> CreateMainEnvironment( | ||
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); | ||
|
||
// TODO(addaleax): This should load a real per-Isolate option, currently | ||
// this is still effectively per-process. | ||
if (isolate_data->options()->track_heap_objects) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thinking was when we implement snapshot, this could be where the context is deserialized from the snapshot (as opposed to using |
||
isolate->GetHeapProfiler()->StartTrackingHeapObjects(true); | ||
} | ||
|
||
Local<Context> context = NewContext(isolate); | ||
Context::Scope context_scope(context); | ||
int exit_code = 0; | ||
Environment env( | ||
|
||
std::unique_ptr<Environment> env = std::make_unique<Environment>( | ||
isolate_data, | ||
context, | ||
static_cast<Environment::Flags>(Environment::kIsMainThread | | ||
Environment::kOwnsProcessState | | ||
Environment::kOwnsInspector)); | ||
env.InitializeLibuv(per_process::v8_is_profiling); | ||
env.ProcessCliArgs(args, exec_args); | ||
env->InitializeLibuv(per_process::v8_is_profiling); | ||
env->ProcessCliArgs(args, exec_args); | ||
|
||
#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 | ||
// right away on the websocket port and fails to bind/etc, this will return | ||
// false. | ||
env.inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "", | ||
env.options()->debug_options(), | ||
env.inspector_host_port(), | ||
true); | ||
if (env.options()->debug_options().inspector_enabled && | ||
!env.inspector_agent()->IsListening()) { | ||
exit_code = 12; // Signal internal error. | ||
goto exit; | ||
env->inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "", | ||
env->options()->debug_options(), | ||
env->inspector_host_port(), | ||
true); | ||
if (env->options()->debug_options().inspector_enabled && | ||
!env->inspector_agent()->IsListening()) { | ||
*exit_code = 12; // Signal internal error. | ||
return env; | ||
} | ||
#else | ||
// inspector_enabled can't be true if !HAVE_INSPECTOR or !NODE_USE_V8_PLATFORM | ||
// - 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 | ||
|
||
{ | ||
AsyncCallbackScope callback_scope(&env); | ||
env.async_hooks()->push_async_ids(1, 0); | ||
LoadEnvironment(&env); | ||
env.async_hooks()->pop_async_id(1); | ||
if (RunBootstrapping(env.get()).IsEmpty()) { | ||
*exit_code = 1; | ||
} | ||
|
||
{ | ||
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); | ||
return env; | ||
} | ||
|
||
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()); | ||
|
||
if (exit_code == 0) { | ||
{ | ||
AsyncCallbackScope callback_scope(env.get()); | ||
env->async_hooks()->push_async_ids(1, 0); | ||
LoadEnvironment(env.get()); | ||
env->async_hooks()->pop_async_id(1); | ||
} | ||
|
||
more = uv_loop_alive(env.event_loop()); | ||
if (more && !env.is_stopping()) continue; | ||
{ | ||
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); | ||
|
||
RunBeforeExit(&env); | ||
per_process::v8_platform.DrainVMTasks(isolate); | ||
|
||
// 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); | ||
} | ||
more = uv_loop_alive(env->event_loop()); | ||
if (more && !env->is_stopping()) continue; | ||
|
||
env.set_trace_sync_io(false); | ||
RunBeforeExit(env.get()); | ||
|
||
exit_code = EmitExit(&env); | ||
// 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); | ||
} | ||
|
||
WaitForInspectorDisconnect(&env); | ||
env->set_trace_sync_io(false); | ||
exit_code = EmitExit(env.get()); | ||
WaitForInspectorDisconnect(env.get()); | ||
} | ||
|
||
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM | ||
exit: | ||
#endif | ||
env.set_can_call_into_js(false); | ||
env.stop_sub_worker_contexts(); | ||
env->set_can_call_into_js(false); | ||
env->stop_sub_worker_contexts(); | ||
uv_tty_reset_mode(); | ||
env.RunCleanup(); | ||
RunAtExit(&env); | ||
env->RunCleanup(); | ||
RunAtExit(env.get()); | ||
|
||
per_process::v8_platform.DrainVMTasks(isolate); | ||
per_process::v8_platform.CancelVMTasks(isolate); | ||
|
||
#if defined(LEAK_SANITIZER) | ||
__lsan_do_leak_check(); | ||
#endif | ||
|
@@ -891,11 +915,6 @@ inline int StartNodeWithLoopAndArgs(uv_loop_t* event_loop, | |
per_process::v8_platform.Platform(), | ||
allocator.get()), | ||
&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 = | ||
StartNodeWithIsolate(isolate, isolate_data.get(), args, exec_args); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are splitting
RunBootstrapping
andStartExecution
, this requires the user not to pass any arguments that result in an async operation done in pre-execution at the moment. This is not ideal, but we may be able to split what's done inenvironment.js
in the future to make sure nothing async is done during that...then the bootstrap will be divided into three phases: