Skip to content

Commit 4d06ef4

Browse files
joyeecheungBethGriggs
authored andcommitted
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: #26788 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com> Signed-off-by: Beth Griggs <Bethany.Griggs@uk.ibm.com>
1 parent a5314a1 commit 4d06ef4

File tree

9 files changed

+141
-67
lines changed

9 files changed

+141
-67
lines changed

lib/internal/bootstrap/cache.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const cannotBeRequired = [
2020

2121
'internal/test/binding',
2222

23+
'internal/bootstrap/environment',
2324
'internal/bootstrap/primordials',
2425
'internal/bootstrap/loaders',
2526
'internal/bootstrap/node',

lib/internal/bootstrap/environment.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict';
2+
3+
// This runs necessary preparations to prepare a complete Node.js context
4+
// that depends on run time states.
5+
// It is currently only intended for preparing contexts for embedders.
6+
7+
/* global markBootstrapComplete */
8+
const {
9+
prepareMainThreadExecution
10+
} = require('internal/bootstrap/pre_execution');
11+
12+
prepareMainThreadExecution();
13+
markBootstrapComplete();

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
'library_files': [
3030
'lib/internal/bootstrap/primordials.js',
3131
'lib/internal/bootstrap/cache.js',
32+
'lib/internal/bootstrap/environment.js',
3233
'lib/internal/bootstrap/loaders.js',
3334
'lib/internal/bootstrap/node.js',
3435
'lib/internal/bootstrap/pre_execution.js',

src/api/environment.cc

+17
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,23 @@ Environment* CreateEnvironment(IsolateData* isolate_data,
243243
Environment::kOwnsInspector));
244244
env->InitializeLibuv(per_process::v8_is_profiling);
245245
env->ProcessCliArgs(args, exec_args);
246+
if (RunBootstrapping(env).IsEmpty()) {
247+
return nullptr;
248+
}
249+
250+
std::vector<Local<String>> parameters = {
251+
env->require_string(),
252+
FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
253+
std::vector<Local<Value>> arguments = {
254+
env->native_module_require(),
255+
env->NewFunctionTemplate(MarkBootstrapComplete)
256+
->GetFunction(env->context())
257+
.ToLocalChecked()};
258+
if (ExecuteBootstrapper(
259+
env, "internal/bootstrap/environment", &parameters, &arguments)
260+
.IsEmpty()) {
261+
return nullptr;
262+
}
246263
return env;
247264
}
248265

src/node.cc

+83-64
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,10 @@ void SignalExit(int signo) {
200200
raise(signo);
201201
}
202202

203-
static MaybeLocal<Value> ExecuteBootstrapper(
204-
Environment* env,
205-
const char* id,
206-
std::vector<Local<String>>* parameters,
207-
std::vector<Local<Value>>* arguments) {
203+
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
204+
const char* id,
205+
std::vector<Local<String>>* parameters,
206+
std::vector<Local<Value>>* arguments) {
208207
EscapableHandleScope scope(env->isolate());
209208
MaybeLocal<Function> maybe_fn =
210209
per_process::native_module_loader.LookupAndCompile(
@@ -453,9 +452,7 @@ void LoadEnvironment(Environment* env) {
453452
// StartMainThreadExecution() make sense for embedders. Pick the
454453
// useful ones out, and allow embedders to customize the entry
455454
// point more directly without using _third_party_main.js
456-
if (!RunBootstrapping(env).IsEmpty()) {
457-
USE(StartMainThreadExecution(env));
458-
}
455+
USE(StartMainThreadExecution(env));
459456
}
460457

461458

@@ -780,90 +777,117 @@ void RunBeforeExit(Environment* env) {
780777
EmitBeforeExit(env);
781778
}
782779

783-
inline int StartNodeWithIsolate(Isolate* isolate,
784-
IsolateData* isolate_data,
785-
const std::vector<std::string>& args,
786-
const std::vector<std::string>& exec_args) {
780+
// TODO(joyeecheung): align this with the CreateEnvironment exposed in node.h
781+
// and the environment creation routine in workers somehow.
782+
inline std::unique_ptr<Environment> CreateMainEnvironment(
783+
IsolateData* isolate_data,
784+
const std::vector<std::string>& args,
785+
const std::vector<std::string>& exec_args,
786+
int* exit_code) {
787+
Isolate* isolate = isolate_data->isolate();
787788
HandleScope handle_scope(isolate);
789+
790+
// TODO(addaleax): This should load a real per-Isolate option, currently
791+
// this is still effectively per-process.
792+
if (isolate_data->options()->track_heap_objects) {
793+
isolate->GetHeapProfiler()->StartTrackingHeapObjects(true);
794+
}
795+
788796
Local<Context> context = NewContext(isolate);
789797
Context::Scope context_scope(context);
790-
int exit_code = 0;
791-
Environment env(
798+
799+
std::unique_ptr<Environment> env = std::make_unique<Environment>(
792800
isolate_data,
793801
context,
794802
static_cast<Environment::Flags>(Environment::kIsMainThread |
795803
Environment::kOwnsProcessState |
796804
Environment::kOwnsInspector));
797-
env.InitializeLibuv(per_process::v8_is_profiling);
798-
env.ProcessCliArgs(args, exec_args);
805+
env->InitializeLibuv(per_process::v8_is_profiling);
806+
env->ProcessCliArgs(args, exec_args);
799807

800808
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
801-
CHECK(!env.inspector_agent()->IsListening());
809+
CHECK(!env->inspector_agent()->IsListening());
802810
// Inspector agent can't fail to start, but if it was configured to listen
803811
// right away on the websocket port and fails to bind/etc, this will return
804812
// false.
805-
env.inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "",
806-
env.options()->debug_options(),
807-
env.inspector_host_port(),
808-
true);
809-
if (env.options()->debug_options().inspector_enabled &&
810-
!env.inspector_agent()->IsListening()) {
811-
exit_code = 12; // Signal internal error.
812-
goto exit;
813+
env->inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "",
814+
env->options()->debug_options(),
815+
env->inspector_host_port(),
816+
true);
817+
if (env->options()->debug_options().inspector_enabled &&
818+
!env->inspector_agent()->IsListening()) {
819+
*exit_code = 12; // Signal internal error.
820+
return env;
813821
}
814822
#else
815823
// inspector_enabled can't be true if !HAVE_INSPECTOR or !NODE_USE_V8_PLATFORM
816824
// - the option parser should not allow that.
817-
CHECK(!env.options()->debug_options().inspector_enabled);
825+
CHECK(!env->options()->debug_options().inspector_enabled);
818826
#endif // HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
819827

820-
{
821-
AsyncCallbackScope callback_scope(&env);
822-
env.async_hooks()->push_async_ids(1, 0);
823-
LoadEnvironment(&env);
824-
env.async_hooks()->pop_async_id(1);
828+
if (RunBootstrapping(env.get()).IsEmpty()) {
829+
*exit_code = 1;
825830
}
826831

827-
{
828-
SealHandleScope seal(isolate);
829-
bool more;
830-
env.performance_state()->Mark(
831-
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
832-
do {
833-
uv_run(env.event_loop(), UV_RUN_DEFAULT);
832+
return env;
833+
}
834834

835-
per_process::v8_platform.DrainVMTasks(isolate);
835+
inline int StartNodeWithIsolate(Isolate* isolate,
836+
IsolateData* isolate_data,
837+
const std::vector<std::string>& args,
838+
const std::vector<std::string>& exec_args) {
839+
int exit_code = 0;
840+
std::unique_ptr<Environment> env =
841+
CreateMainEnvironment(isolate_data, args, exec_args, &exit_code);
842+
CHECK_NOT_NULL(env);
843+
HandleScope handle_scope(env->isolate());
844+
Context::Scope context_scope(env->context());
845+
846+
if (exit_code == 0) {
847+
{
848+
AsyncCallbackScope callback_scope(env.get());
849+
env->async_hooks()->push_async_ids(1, 0);
850+
LoadEnvironment(env.get());
851+
env->async_hooks()->pop_async_id(1);
852+
}
836853

837-
more = uv_loop_alive(env.event_loop());
838-
if (more && !env.is_stopping()) continue;
854+
{
855+
SealHandleScope seal(isolate);
856+
bool more;
857+
env->performance_state()->Mark(
858+
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
859+
do {
860+
uv_run(env->event_loop(), UV_RUN_DEFAULT);
839861

840-
RunBeforeExit(&env);
862+
per_process::v8_platform.DrainVMTasks(isolate);
841863

842-
// Emit `beforeExit` if the loop became alive either after emitting
843-
// event, or after running some callbacks.
844-
more = uv_loop_alive(env.event_loop());
845-
} while (more == true && !env.is_stopping());
846-
env.performance_state()->Mark(
847-
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
848-
}
864+
more = uv_loop_alive(env->event_loop());
865+
if (more && !env->is_stopping()) continue;
849866

850-
env.set_trace_sync_io(false);
867+
RunBeforeExit(env.get());
851868

852-
exit_code = EmitExit(&env);
869+
// Emit `beforeExit` if the loop became alive either after emitting
870+
// event, or after running some callbacks.
871+
more = uv_loop_alive(env->event_loop());
872+
} while (more == true && !env->is_stopping());
873+
env->performance_state()->Mark(
874+
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
875+
}
853876

854-
WaitForInspectorDisconnect(&env);
877+
env->set_trace_sync_io(false);
878+
exit_code = EmitExit(env.get());
879+
WaitForInspectorDisconnect(env.get());
880+
}
855881

856-
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
857-
exit:
858-
#endif
859-
env.set_can_call_into_js(false);
860-
env.stop_sub_worker_contexts();
882+
env->set_can_call_into_js(false);
883+
env->stop_sub_worker_contexts();
861884
uv_tty_reset_mode();
862-
env.RunCleanup();
863-
RunAtExit(&env);
885+
env->RunCleanup();
886+
RunAtExit(env.get());
864887

865888
per_process::v8_platform.DrainVMTasks(isolate);
866889
per_process::v8_platform.CancelVMTasks(isolate);
890+
867891
#if defined(LEAK_SANITIZER)
868892
__lsan_do_leak_check();
869893
#endif
@@ -891,11 +915,6 @@ inline int StartNodeWithLoopAndArgs(uv_loop_t* event_loop,
891915
per_process::v8_platform.Platform(),
892916
allocator.get()),
893917
&FreeIsolateData);
894-
// TODO(addaleax): This should load a real per-Isolate option, currently
895-
// this is still effectively per-process.
896-
if (isolate_data->options()->track_heap_objects) {
897-
isolate->GetHeapProfiler()->StartTrackingHeapObjects(true);
898-
}
899918
exit_code =
900919
StartNodeWithIsolate(isolate, isolate_data.get(), args, exec_args);
901920
}

src/node.h

+2
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
299299

300300
// TODO(addaleax): Add an official variant using STL containers, and move
301301
// per-Environment options parsing here.
302+
// Returns nullptr when the Environment cannot be created e.g. there are
303+
// pending JavaScript exceptions.
302304
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
303305
v8::Local<v8::Context> context,
304306
int argc,

src/node_internals.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,12 @@ v8::MaybeLocal<v8::Value> RunBootstrapping(Environment* env);
302302
v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
303303
const char* main_script_id);
304304
v8::MaybeLocal<v8::Object> GetPerContextExports(v8::Local<v8::Context> context);
305-
305+
v8::MaybeLocal<v8::Value> ExecuteBootstrapper(
306+
Environment* env,
307+
const char* id,
308+
std::vector<v8::Local<v8::String>>* parameters,
309+
std::vector<v8::Local<v8::Value>>* arguments);
310+
void MarkBootstrapComplete(const v8::FunctionCallbackInfo<v8::Value>& args);
306311
namespace profiler {
307312
void StartCoverageCollection(Environment* env);
308313
}

test/cctest/node_test_fixture.h

-2
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ class EnvironmentTestFixture : public NodeTestFixture {
131131
1, *argv,
132132
argv.nr_args(), *argv);
133133
CHECK_NE(nullptr, environment_);
134-
// TODO(addaleax): Make this a public API.
135-
CHECK(!RunBootstrapping(environment_).IsEmpty());
136134
}
137135

138136
~Env() {

test/cctest/test_environment.cc

+18
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ class EnvironmentTest : public EnvironmentTestFixture {
2323
}
2424
};
2525

26+
TEST_F(EnvironmentTest, PreExeuctionPreparation) {
27+
const v8::HandleScope handle_scope(isolate_);
28+
const Argv argv;
29+
Env env {handle_scope, argv};
30+
31+
v8::Local<v8::Context> context = isolate_->GetCurrentContext();
32+
33+
const char* run_script = "process.argv0";
34+
v8::Local<v8::Script> script = v8::Script::Compile(
35+
context,
36+
v8::String::NewFromOneByte(isolate_,
37+
reinterpret_cast<const uint8_t*>(run_script),
38+
v8::NewStringType::kNormal).ToLocalChecked())
39+
.ToLocalChecked();
40+
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
41+
CHECK(result->IsString());
42+
}
43+
2644
TEST_F(EnvironmentTest, AtExitWithEnvironment) {
2745
const v8::HandleScope handle_scope(isolate_);
2846
const Argv argv;

0 commit comments

Comments
 (0)