/src/node/src/node_main_instance.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "node_main_instance.h" |
2 | | #include <memory> |
3 | | #if HAVE_OPENSSL |
4 | | #include "crypto/crypto_util.h" |
5 | | #endif // HAVE_OPENSSL |
6 | | #include "debug_utils-inl.h" |
7 | | #include "node_builtins.h" |
8 | | #include "node_external_reference.h" |
9 | | #include "node_internals.h" |
10 | | #include "node_options-inl.h" |
11 | | #include "node_realm.h" |
12 | | #include "node_sea.h" |
13 | | #include "node_snapshot_builder.h" |
14 | | #include "node_snapshotable.h" |
15 | | #include "node_v8_platform-inl.h" |
16 | | #include "util-inl.h" |
17 | | #if defined(LEAK_SANITIZER) |
18 | | #include <sanitizer/lsan_interface.h> |
19 | | #endif |
20 | | |
21 | | #if HAVE_INSPECTOR |
22 | | #include "inspector/worker_inspector.h" // ParentInspectorHandle |
23 | | #endif |
24 | | |
25 | | namespace node { |
26 | | |
27 | | using v8::Context; |
28 | | using v8::HandleScope; |
29 | | using v8::Isolate; |
30 | | using v8::Local; |
31 | | using v8::Locker; |
32 | | |
33 | | NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data, |
34 | | uv_loop_t* event_loop, |
35 | | MultiIsolatePlatform* platform, |
36 | | const std::vector<std::string>& args, |
37 | | const std::vector<std::string>& exec_args) |
38 | 0 | : args_(args), |
39 | 0 | exec_args_(exec_args), |
40 | 0 | array_buffer_allocator_(ArrayBufferAllocator::Create()), |
41 | 0 | isolate_(nullptr), |
42 | 0 | platform_(platform), |
43 | 0 | isolate_data_(), |
44 | 0 | isolate_params_(std::make_unique<Isolate::CreateParams>()), |
45 | 0 | snapshot_data_(snapshot_data) { |
46 | 0 | isolate_params_->array_buffer_allocator = array_buffer_allocator_.get(); |
47 | |
|
48 | 0 | isolate_ = |
49 | 0 | NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data); |
50 | 0 | CHECK_NOT_NULL(isolate_); |
51 | | |
52 | | // If the indexes are not nullptr, we are not deserializing |
53 | 0 | isolate_data_.reset( |
54 | 0 | CreateIsolateData(isolate_, |
55 | 0 | event_loop, |
56 | 0 | platform, |
57 | 0 | array_buffer_allocator_.get(), |
58 | 0 | snapshot_data->AsEmbedderWrapper().get())); |
59 | |
|
60 | 0 | isolate_data_->max_young_gen_size = |
61 | 0 | isolate_params_->constraints.max_young_generation_size_in_bytes(); |
62 | 0 | } |
63 | | |
64 | 0 | NodeMainInstance::~NodeMainInstance() { |
65 | 0 | if (isolate_params_ == nullptr) { |
66 | 0 | return; |
67 | 0 | } |
68 | | |
69 | 0 | { |
70 | | #ifdef DEBUG |
71 | | // node::Environment has been disposed and no JavaScript Execution is |
72 | | // allowed at this point. |
73 | | // Create a scope to check that no JavaScript is executed in debug build |
74 | | // and proactively crash the process in the case JavaScript is being |
75 | | // executed. |
76 | | // Isolate::Dispose() must be invoked outside of this scope to avoid |
77 | | // use-after-free. |
78 | | Isolate::DisallowJavascriptExecutionScope disallow_js( |
79 | | isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); |
80 | | #endif |
81 | | // This should only be done on a main instance that owns its isolate. |
82 | | // IsolateData must be freed before UnregisterIsolate() is called. |
83 | 0 | isolate_data_.reset(); |
84 | 0 | platform_->UnregisterIsolate(isolate_); |
85 | 0 | } |
86 | 0 | isolate_->Dispose(); |
87 | 0 | } |
88 | | |
89 | 0 | ExitCode NodeMainInstance::Run() { |
90 | 0 | Locker locker(isolate_); |
91 | 0 | Isolate::Scope isolate_scope(isolate_); |
92 | 0 | HandleScope handle_scope(isolate_); |
93 | |
|
94 | 0 | ExitCode exit_code = ExitCode::kNoFailure; |
95 | 0 | DeleteFnPtr<Environment, FreeEnvironment> env = |
96 | 0 | CreateMainEnvironment(&exit_code); |
97 | 0 | CHECK_NOT_NULL(env); |
98 | | |
99 | 0 | Context::Scope context_scope(env->context()); |
100 | 0 | Run(&exit_code, env.get()); |
101 | 0 | return exit_code; |
102 | 0 | } |
103 | | |
104 | 0 | void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) { |
105 | 0 | if (*exit_code == ExitCode::kNoFailure) { |
106 | 0 | bool runs_sea_code = false; |
107 | 0 | #ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION |
108 | 0 | if (sea::IsSingleExecutable()) { |
109 | 0 | sea::SeaResource sea = sea::FindSingleExecutableResource(); |
110 | 0 | if (!sea.use_snapshot()) { |
111 | 0 | runs_sea_code = true; |
112 | 0 | std::string_view code = sea.main_code_or_snapshot; |
113 | 0 | LoadEnvironment(env, code); |
114 | 0 | } |
115 | 0 | } |
116 | 0 | #endif |
117 | | // Either there is already a snapshot main function from SEA, or it's not |
118 | | // a SEA at all. |
119 | 0 | if (!runs_sea_code) { |
120 | 0 | LoadEnvironment(env, StartExecutionCallback{}); |
121 | 0 | } |
122 | |
|
123 | 0 | *exit_code = |
124 | 0 | SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError); |
125 | 0 | } |
126 | |
|
127 | | #if defined(LEAK_SANITIZER) |
128 | | __lsan_do_leak_check(); |
129 | | #endif |
130 | 0 | } |
131 | | |
132 | | DeleteFnPtr<Environment, FreeEnvironment> |
133 | 0 | NodeMainInstance::CreateMainEnvironment(ExitCode* exit_code) { |
134 | 0 | *exit_code = ExitCode::kNoFailure; // Reset the exit code to 0 |
135 | |
|
136 | 0 | HandleScope handle_scope(isolate_); |
137 | | |
138 | | // TODO(addaleax): This should load a real per-Isolate option, currently |
139 | | // this is still effectively per-process. |
140 | 0 | if (isolate_data_->options()->track_heap_objects) { |
141 | 0 | isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true); |
142 | 0 | } |
143 | |
|
144 | 0 | Local<Context> context; |
145 | 0 | DeleteFnPtr<Environment, FreeEnvironment> env; |
146 | |
|
147 | 0 | if (snapshot_data_ != nullptr) { |
148 | 0 | env.reset(CreateEnvironment(isolate_data_.get(), |
149 | 0 | Local<Context>(), // read from snapshot |
150 | 0 | args_, |
151 | 0 | exec_args_)); |
152 | 0 | #if HAVE_OPENSSL |
153 | 0 | crypto::InitCryptoOnce(isolate_); |
154 | 0 | #endif // HAVE_OPENSSL |
155 | 0 | } else { |
156 | 0 | context = NewContext(isolate_); |
157 | 0 | CHECK(!context.IsEmpty()); |
158 | 0 | Context::Scope context_scope(context); |
159 | 0 | env.reset( |
160 | 0 | CreateEnvironment(isolate_data_.get(), context, args_, exec_args_)); |
161 | 0 | } |
162 | | |
163 | 0 | return env; |
164 | 0 | } |
165 | | |
166 | | } // namespace node |