1 #include <memory>
2
3 #include "node_main_instance.h"
4 #include "node_internals.h"
5 #include "node_options-inl.h"
6 #include "node_v8_platform-inl.h"
7 #include "util-inl.h"
8 #if defined(LEAK_SANITIZER)
9 #include <sanitizer/lsan_interface.h>
10 #endif
11
12 #if HAVE_INSPECTOR
13 #include "inspector/worker_inspector.h" // ParentInspectorHandle
14 #endif
15
16 namespace node {
17
18 using v8::Context;
19 using v8::HandleScope;
20 using v8::Isolate;
21 using v8::Local;
22 using v8::Locker;
23 using v8::SealHandleScope;
24
NodeMainInstance(Isolate * isolate,uv_loop_t * event_loop,MultiIsolatePlatform * platform,const std::vector<std::string> & args,const std::vector<std::string> & exec_args)25 NodeMainInstance::NodeMainInstance(Isolate* isolate,
26 uv_loop_t* event_loop,
27 MultiIsolatePlatform* platform,
28 const std::vector<std::string>& args,
29 const std::vector<std::string>& exec_args)
30 : args_(args),
31 exec_args_(exec_args),
32 array_buffer_allocator_(nullptr),
33 isolate_(isolate),
34 platform_(platform),
35 isolate_data_(nullptr),
36 owns_isolate_(false),
37 deserialize_mode_(false) {
38 isolate_data_ =
39 std::make_unique<IsolateData>(isolate_, event_loop, platform, nullptr);
40
41 SetIsolateMiscHandlers(isolate_, {});
42 }
43
Create(Isolate * isolate,uv_loop_t * event_loop,MultiIsolatePlatform * platform,const std::vector<std::string> & args,const std::vector<std::string> & exec_args)44 std::unique_ptr<NodeMainInstance> NodeMainInstance::Create(
45 Isolate* isolate,
46 uv_loop_t* event_loop,
47 MultiIsolatePlatform* platform,
48 const std::vector<std::string>& args,
49 const std::vector<std::string>& exec_args) {
50 return std::unique_ptr<NodeMainInstance>(
51 new NodeMainInstance(isolate, event_loop, platform, args, exec_args));
52 }
53
NodeMainInstance(Isolate::CreateParams * params,uv_loop_t * event_loop,MultiIsolatePlatform * platform,const std::vector<std::string> & args,const std::vector<std::string> & exec_args,const std::vector<size_t> * per_isolate_data_indexes)54 NodeMainInstance::NodeMainInstance(
55 Isolate::CreateParams* params,
56 uv_loop_t* event_loop,
57 MultiIsolatePlatform* platform,
58 const std::vector<std::string>& args,
59 const std::vector<std::string>& exec_args,
60 const std::vector<size_t>* per_isolate_data_indexes)
61 : args_(args),
62 exec_args_(exec_args),
63 array_buffer_allocator_(ArrayBufferAllocator::Create()),
64 isolate_(nullptr),
65 platform_(platform),
66 isolate_data_(nullptr),
67 owns_isolate_(true) {
68 params->array_buffer_allocator = array_buffer_allocator_.get();
69 isolate_ = Isolate::Allocate();
70 CHECK_NOT_NULL(isolate_);
71 // Register the isolate on the platform before the isolate gets initialized,
72 // so that the isolate can access the platform during initialization.
73 platform->RegisterIsolate(isolate_, event_loop);
74 SetIsolateCreateParamsForNode(params);
75 Isolate::Initialize(isolate_, *params);
76
77 deserialize_mode_ = per_isolate_data_indexes != nullptr;
78 // If the indexes are not nullptr, we are not deserializing
79 CHECK_IMPLIES(deserialize_mode_, params->external_references != nullptr);
80 isolate_data_ = std::make_unique<IsolateData>(isolate_,
81 event_loop,
82 platform,
83 array_buffer_allocator_.get(),
84 per_isolate_data_indexes);
85 IsolateSettings s;
86 SetIsolateMiscHandlers(isolate_, s);
87 if (!deserialize_mode_) {
88 // If in deserialize mode, delay until after the deserialization is
89 // complete.
90 SetIsolateErrorHandlers(isolate_, s);
91 }
92 isolate_data_->max_young_gen_size =
93 params->constraints.max_young_generation_size_in_bytes();
94 }
95
Dispose()96 void NodeMainInstance::Dispose() {
97 CHECK(!owns_isolate_);
98 platform_->DrainTasks(isolate_);
99 }
100
~NodeMainInstance()101 NodeMainInstance::~NodeMainInstance() {
102 if (!owns_isolate_) {
103 return;
104 }
105 platform_->UnregisterIsolate(isolate_);
106 isolate_->Dispose();
107 }
108
Run()109 int NodeMainInstance::Run() {
110 Locker locker(isolate_);
111 Isolate::Scope isolate_scope(isolate_);
112 HandleScope handle_scope(isolate_);
113
114 int exit_code = 0;
115 DeleteFnPtr<Environment, FreeEnvironment> env =
116 CreateMainEnvironment(&exit_code);
117
118 CHECK_NOT_NULL(env);
119 Context::Scope context_scope(env->context());
120
121 if (exit_code == 0) {
122 LoadEnvironment(env.get());
123
124 env->set_trace_sync_io(env->options()->trace_sync_io);
125
126 {
127 SealHandleScope seal(isolate_);
128 bool more;
129 env->performance_state()->Mark(
130 node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
131 do {
132 uv_run(env->event_loop(), UV_RUN_DEFAULT);
133
134 per_process::v8_platform.DrainVMTasks(isolate_);
135
136 more = uv_loop_alive(env->event_loop());
137 if (more && !env->is_stopping()) continue;
138
139 if (!uv_loop_alive(env->event_loop())) {
140 if (EmitProcessBeforeExit(env.get()).IsNothing())
141 break;
142 }
143
144 // Emit `beforeExit` if the loop became alive either after emitting
145 // event, or after running some callbacks.
146 more = uv_loop_alive(env->event_loop());
147 } while (more == true && !env->is_stopping());
148 env->performance_state()->Mark(
149 node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
150 }
151
152 env->set_trace_sync_io(false);
153 if (!env->is_stopping()) env->VerifyNoStrongBaseObjects();
154 exit_code = EmitProcessExit(env.get()).FromMaybe(1);
155 }
156
157 ResetStdio();
158
159 // TODO(addaleax): Neither NODE_SHARED_MODE nor HAVE_INSPECTOR really
160 // make sense here.
161 #if HAVE_INSPECTOR && defined(__POSIX__) && !defined(NODE_SHARED_MODE)
162 struct sigaction act;
163 memset(&act, 0, sizeof(act));
164 for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
165 if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF)
166 continue;
167 act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
168 CHECK_EQ(0, sigaction(nr, &act, nullptr));
169 }
170 #endif
171
172 #if defined(LEAK_SANITIZER)
173 __lsan_do_leak_check();
174 #endif
175
176 return exit_code;
177 }
178
179 DeleteFnPtr<Environment, FreeEnvironment>
CreateMainEnvironment(int * exit_code)180 NodeMainInstance::CreateMainEnvironment(int* exit_code) {
181 *exit_code = 0; // Reset the exit code to 0
182
183 HandleScope handle_scope(isolate_);
184
185 // TODO(addaleax): This should load a real per-Isolate option, currently
186 // this is still effectively per-process.
187 if (isolate_data_->options()->track_heap_objects) {
188 isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true);
189 }
190
191 Local<Context> context;
192 if (deserialize_mode_) {
193 context =
194 Context::FromSnapshot(isolate_, kNodeContextIndex).ToLocalChecked();
195 InitializeContextRuntime(context);
196 SetIsolateErrorHandlers(isolate_, {});
197 } else {
198 context = NewContext(isolate_);
199 }
200
201 CHECK(!context.IsEmpty());
202 Context::Scope context_scope(context);
203
204 DeleteFnPtr<Environment, FreeEnvironment> env { CreateEnvironment(
205 isolate_data_.get(),
206 context,
207 args_,
208 exec_args_,
209 EnvironmentFlags::kDefaultFlags) };
210
211 if (*exit_code != 0) {
212 return env;
213 }
214
215 if (env == nullptr) {
216 *exit_code = 1;
217 }
218
219 return env;
220 }
221
222 } // namespace node
223