1 #include "node.h"
2 #include "node_context_data.h"
3 #include "node_errors.h"
4 #include "node_internals.h"
5 #include "node_native_module_env.h"
6 #include "node_platform.h"
7 #include "node_v8_platform-inl.h"
8 #include "uv.h"
9
10 #if HAVE_INSPECTOR
11 #include "inspector/worker_inspector.h" // ParentInspectorHandle
12 #endif
13
14 namespace node {
15 using errors::TryCatchScope;
16 using v8::Array;
17 using v8::Context;
18 using v8::EscapableHandleScope;
19 using v8::FinalizationGroup;
20 using v8::Function;
21 using v8::FunctionCallbackInfo;
22 using v8::HandleScope;
23 using v8::Isolate;
24 using v8::Local;
25 using v8::MaybeLocal;
26 using v8::Null;
27 using v8::Object;
28 using v8::ObjectTemplate;
29 using v8::Private;
30 using v8::PropertyDescriptor;
31 using v8::String;
32 using v8::Value;
33
AllowWasmCodeGenerationCallback(Local<Context> context,Local<String>)34 bool AllowWasmCodeGenerationCallback(Local<Context> context,
35 Local<String>) {
36 Local<Value> wasm_code_gen =
37 context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
38 return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
39 }
40
ShouldAbortOnUncaughtException(Isolate * isolate)41 bool ShouldAbortOnUncaughtException(Isolate* isolate) {
42 DebugSealHandleScope scope(isolate);
43 Environment* env = Environment::GetCurrent(isolate);
44 return env != nullptr &&
45 (env->is_main_thread() || !env->is_stopping()) &&
46 env->abort_on_uncaught_exception() &&
47 env->should_abort_on_uncaught_toggle()[0] &&
48 !env->inside_should_not_abort_on_uncaught_scope();
49 }
50
PrepareStackTraceCallback(Local<Context> context,Local<Value> exception,Local<Array> trace)51 MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
52 Local<Value> exception,
53 Local<Array> trace) {
54 Environment* env = Environment::GetCurrent(context);
55 if (env == nullptr) {
56 return exception->ToString(context).FromMaybe(Local<Value>());
57 }
58 Local<Function> prepare = env->prepare_stack_trace_callback();
59 if (prepare.IsEmpty()) {
60 return exception->ToString(context).FromMaybe(Local<Value>());
61 }
62 Local<Value> args[] = {
63 context->Global(),
64 exception,
65 trace,
66 };
67 // This TryCatch + Rethrow is required by V8 due to details around exception
68 // handling there. For C++ callbacks, V8 expects a scheduled exception (which
69 // is what ReThrow gives us). Just returning the empty MaybeLocal would leave
70 // us with a pending exception.
71 TryCatchScope try_catch(env);
72 MaybeLocal<Value> result = prepare->Call(
73 context, Undefined(env->isolate()), arraysize(args), args);
74 if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
75 try_catch.ReThrow();
76 }
77 return result;
78 }
79
HostCleanupFinalizationGroupCallback(Local<Context> context,Local<FinalizationGroup> group)80 static void HostCleanupFinalizationGroupCallback(
81 Local<Context> context, Local<FinalizationGroup> group) {
82 Environment* env = Environment::GetCurrent(context);
83 if (env == nullptr) {
84 return;
85 }
86 env->RegisterFinalizationGroupForCleanup(group);
87 }
88
Allocate(size_t size)89 void* NodeArrayBufferAllocator::Allocate(size_t size) {
90 void* ret;
91 if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
92 ret = UncheckedCalloc(size);
93 else
94 ret = UncheckedMalloc(size);
95 if (LIKELY(ret != nullptr))
96 total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
97 return ret;
98 }
99
AllocateUninitialized(size_t size)100 void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
101 void* ret = node::UncheckedMalloc(size);
102 if (LIKELY(ret != nullptr))
103 total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
104 return ret;
105 }
106
Reallocate(void * data,size_t old_size,size_t size)107 void* NodeArrayBufferAllocator::Reallocate(
108 void* data, size_t old_size, size_t size) {
109 void* ret = UncheckedRealloc<char>(static_cast<char*>(data), size);
110 if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
111 total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
112 return ret;
113 }
114
Free(void * data,size_t size)115 void NodeArrayBufferAllocator::Free(void* data, size_t size) {
116 total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
117 free(data);
118 }
119
~DebuggingArrayBufferAllocator()120 DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
121 CHECK(allocations_.empty());
122 }
123
Allocate(size_t size)124 void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
125 Mutex::ScopedLock lock(mutex_);
126 void* data = NodeArrayBufferAllocator::Allocate(size);
127 RegisterPointerInternal(data, size);
128 return data;
129 }
130
AllocateUninitialized(size_t size)131 void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
132 Mutex::ScopedLock lock(mutex_);
133 void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
134 RegisterPointerInternal(data, size);
135 return data;
136 }
137
Free(void * data,size_t size)138 void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
139 Mutex::ScopedLock lock(mutex_);
140 UnregisterPointerInternal(data, size);
141 NodeArrayBufferAllocator::Free(data, size);
142 }
143
Reallocate(void * data,size_t old_size,size_t size)144 void* DebuggingArrayBufferAllocator::Reallocate(void* data,
145 size_t old_size,
146 size_t size) {
147 Mutex::ScopedLock lock(mutex_);
148 void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
149 if (ret == nullptr) {
150 if (size == 0) // i.e. equivalent to free().
151 UnregisterPointerInternal(data, old_size);
152 return nullptr;
153 }
154
155 if (data != nullptr) {
156 auto it = allocations_.find(data);
157 CHECK_NE(it, allocations_.end());
158 allocations_.erase(it);
159 }
160
161 RegisterPointerInternal(ret, size);
162 return ret;
163 }
164
RegisterPointer(void * data,size_t size)165 void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
166 Mutex::ScopedLock lock(mutex_);
167 NodeArrayBufferAllocator::RegisterPointer(data, size);
168 RegisterPointerInternal(data, size);
169 }
170
UnregisterPointer(void * data,size_t size)171 void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
172 Mutex::ScopedLock lock(mutex_);
173 NodeArrayBufferAllocator::UnregisterPointer(data, size);
174 UnregisterPointerInternal(data, size);
175 }
176
UnregisterPointerInternal(void * data,size_t size)177 void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
178 size_t size) {
179 if (data == nullptr) return;
180 auto it = allocations_.find(data);
181 CHECK_NE(it, allocations_.end());
182 if (size > 0) {
183 // We allow allocations with size 1 for 0-length buffers to avoid having
184 // to deal with nullptr values.
185 CHECK_EQ(it->second, size);
186 }
187 allocations_.erase(it);
188 }
189
RegisterPointerInternal(void * data,size_t size)190 void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
191 size_t size) {
192 if (data == nullptr) return;
193 CHECK_EQ(allocations_.count(data), 0);
194 allocations_[data] = size;
195 }
196
Create(bool debug)197 std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
198 if (debug || per_process::cli_options->debug_arraybuffer_allocations)
199 return std::make_unique<DebuggingArrayBufferAllocator>();
200 else
201 return std::make_unique<NodeArrayBufferAllocator>();
202 }
203
CreateArrayBufferAllocator()204 ArrayBufferAllocator* CreateArrayBufferAllocator() {
205 return ArrayBufferAllocator::Create().release();
206 }
207
FreeArrayBufferAllocator(ArrayBufferAllocator * allocator)208 void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
209 delete allocator;
210 }
211
SetIsolateCreateParamsForNode(Isolate::CreateParams * params)212 void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
213 const uint64_t constrained_memory = uv_get_constrained_memory();
214 const uint64_t total_memory = constrained_memory > 0 ?
215 std::min(uv_get_total_memory(), constrained_memory) :
216 uv_get_total_memory();
217 if (total_memory > 0) {
218 // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
219 // This default is based on browser use-cases. Tell V8 to configure the
220 // heap based on the actual physical memory.
221 params->constraints.ConfigureDefaults(total_memory, 0);
222 }
223 }
224
SetIsolateErrorHandlers(v8::Isolate * isolate,const IsolateSettings & s)225 void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
226 if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
227 isolate->AddMessageListenerWithErrorLevel(
228 errors::PerIsolateMessageListener,
229 Isolate::MessageErrorLevel::kMessageError |
230 Isolate::MessageErrorLevel::kMessageWarning);
231
232 auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
233 s.should_abort_on_uncaught_exception_callback :
234 ShouldAbortOnUncaughtException;
235 isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
236
237 auto* fatal_error_cb = s.fatal_error_callback ?
238 s.fatal_error_callback : OnFatalError;
239 isolate->SetFatalErrorHandler(fatal_error_cb);
240
241 auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
242 s.prepare_stack_trace_callback : PrepareStackTraceCallback;
243 isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
244 }
245
SetIsolateMiscHandlers(v8::Isolate * isolate,const IsolateSettings & s)246 void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
247 isolate->SetMicrotasksPolicy(s.policy);
248
249 auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
250 s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
251 isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
252
253 if ((s.flags & SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK) == 0) {
254 auto* promise_reject_cb = s.promise_reject_callback ?
255 s.promise_reject_callback : PromiseRejectCallback;
256 isolate->SetPromiseRejectCallback(promise_reject_cb);
257 }
258
259 auto* host_cleanup_cb = s.host_cleanup_finalization_group_callback ?
260 s.host_cleanup_finalization_group_callback :
261 HostCleanupFinalizationGroupCallback;
262 isolate->SetHostCleanupFinalizationGroupCallback(host_cleanup_cb);
263
264 if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
265 v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
266 }
267
SetIsolateUpForNode(v8::Isolate * isolate,const IsolateSettings & settings)268 void SetIsolateUpForNode(v8::Isolate* isolate,
269 const IsolateSettings& settings) {
270 SetIsolateErrorHandlers(isolate, settings);
271 SetIsolateMiscHandlers(isolate, settings);
272 }
273
SetIsolateUpForNode(v8::Isolate * isolate)274 void SetIsolateUpForNode(v8::Isolate* isolate) {
275 IsolateSettings settings;
276 SetIsolateUpForNode(isolate, settings);
277 }
278
NewIsolate(ArrayBufferAllocator * allocator,uv_loop_t * event_loop)279 Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
280 return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform());
281 }
282
283 // TODO(joyeecheung): we may want to expose this, but then we need to be
284 // careful about what we override in the params.
NewIsolate(Isolate::CreateParams * params,uv_loop_t * event_loop,MultiIsolatePlatform * platform)285 Isolate* NewIsolate(Isolate::CreateParams* params,
286 uv_loop_t* event_loop,
287 MultiIsolatePlatform* platform) {
288 Isolate* isolate = Isolate::Allocate();
289 if (isolate == nullptr) return nullptr;
290
291 // Register the isolate on the platform before the isolate gets initialized,
292 // so that the isolate can access the platform during initialization.
293 platform->RegisterIsolate(isolate, event_loop);
294
295 SetIsolateCreateParamsForNode(params);
296 Isolate::Initialize(isolate, *params);
297 SetIsolateUpForNode(isolate);
298
299 return isolate;
300 }
301
NewIsolate(ArrayBufferAllocator * allocator,uv_loop_t * event_loop,MultiIsolatePlatform * platform)302 Isolate* NewIsolate(ArrayBufferAllocator* allocator,
303 uv_loop_t* event_loop,
304 MultiIsolatePlatform* platform) {
305 Isolate::CreateParams params;
306 if (allocator != nullptr) params.array_buffer_allocator = allocator;
307 return NewIsolate(¶ms, event_loop, platform);
308 }
309
CreateIsolateData(Isolate * isolate,uv_loop_t * loop,MultiIsolatePlatform * platform,ArrayBufferAllocator * allocator)310 IsolateData* CreateIsolateData(Isolate* isolate,
311 uv_loop_t* loop,
312 MultiIsolatePlatform* platform,
313 ArrayBufferAllocator* allocator) {
314 return new IsolateData(isolate, loop, platform, allocator);
315 }
316
FreeIsolateData(IsolateData * isolate_data)317 void FreeIsolateData(IsolateData* isolate_data) {
318 delete isolate_data;
319 }
320
~InspectorParentHandle()321 InspectorParentHandle::~InspectorParentHandle() {}
322
323 // Hide the internal handle class from the public API.
324 #if HAVE_INSPECTOR
325 struct InspectorParentHandleImpl : public InspectorParentHandle {
326 std::unique_ptr<inspector::ParentInspectorHandle> impl;
327
InspectorParentHandleImplnode::InspectorParentHandleImpl328 explicit InspectorParentHandleImpl(
329 std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
330 : impl(std::move(impl)) {}
331 };
332 #endif
333
CreateEnvironment(IsolateData * isolate_data,Local<Context> context,int argc,const char * const * argv,int exec_argc,const char * const * exec_argv)334 Environment* CreateEnvironment(IsolateData* isolate_data,
335 Local<Context> context,
336 int argc,
337 const char* const* argv,
338 int exec_argc,
339 const char* const* exec_argv) {
340 return CreateEnvironment(
341 isolate_data, context,
342 std::vector<std::string>(argv, argv + argc),
343 std::vector<std::string>(exec_argv, exec_argv + exec_argc));
344 }
345
CreateEnvironment(IsolateData * isolate_data,Local<Context> context,const std::vector<std::string> & args,const std::vector<std::string> & exec_args,EnvironmentFlags::Flags flags,ThreadId thread_id,std::unique_ptr<InspectorParentHandle> inspector_parent_handle)346 Environment* CreateEnvironment(
347 IsolateData* isolate_data,
348 Local<Context> context,
349 const std::vector<std::string>& args,
350 const std::vector<std::string>& exec_args,
351 EnvironmentFlags::Flags flags,
352 ThreadId thread_id,
353 std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
354 Isolate* isolate = context->GetIsolate();
355 HandleScope handle_scope(isolate);
356 Context::Scope context_scope(context);
357 // TODO(addaleax): This is a much better place for parsing per-Environment
358 // options than the global parse call.
359 Environment* env = new Environment(
360 isolate_data,
361 context,
362 args,
363 exec_args,
364 flags,
365 thread_id);
366
367 #if HAVE_INSPECTOR
368 if (inspector_parent_handle) {
369 env->InitializeInspector(
370 std::move(static_cast<InspectorParentHandleImpl*>(
371 inspector_parent_handle.get())->impl));
372 } else {
373 env->InitializeInspector({});
374 }
375 #endif
376
377 if (env->RunBootstrapping().IsEmpty()) {
378 FreeEnvironment(env);
379 return nullptr;
380 }
381
382 return env;
383 }
384
FreeEnvironment(Environment * env)385 void FreeEnvironment(Environment* env) {
386 {
387 // TODO(addaleax): This should maybe rather be in a SealHandleScope.
388 HandleScope handle_scope(env->isolate());
389 Context::Scope context_scope(env->context());
390 env->set_stopping(true);
391 env->stop_sub_worker_contexts();
392 env->RunCleanup();
393 RunAtExit(env);
394 }
395
396 // This call needs to be made while the `Environment` is still alive
397 // because we assume that it is available for async tracking in the
398 // NodePlatform implementation.
399 MultiIsolatePlatform* platform = env->isolate_data()->platform();
400 if (platform != nullptr)
401 platform->DrainTasks(env->isolate());
402
403 delete env;
404 }
405
GetInspectorParentHandle(Environment * env,ThreadId thread_id,const char * url)406 NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
407 Environment* env,
408 ThreadId thread_id,
409 const char* url) {
410 CHECK_NOT_NULL(env);
411 CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
412 #if HAVE_INSPECTOR
413 return std::make_unique<InspectorParentHandleImpl>(
414 env->inspector_agent()->GetParentHandle(thread_id.id, url));
415 #else
416 return {};
417 #endif
418 }
419
LoadEnvironment(Environment * env)420 void LoadEnvironment(Environment* env) {
421 USE(LoadEnvironment(env,
422 StartExecutionCallback{},
423 {}));
424 }
425
LoadEnvironment(Environment * env,StartExecutionCallback cb,std::unique_ptr<InspectorParentHandle> removeme)426 MaybeLocal<Value> LoadEnvironment(
427 Environment* env,
428 StartExecutionCallback cb,
429 std::unique_ptr<InspectorParentHandle> removeme) {
430 env->InitializeLibuv(per_process::v8_is_profiling);
431 env->InitializeDiagnostics();
432
433 return StartExecution(env, cb);
434 }
435
LoadEnvironment(Environment * env,const char * main_script_source_utf8,std::unique_ptr<InspectorParentHandle> removeme)436 MaybeLocal<Value> LoadEnvironment(
437 Environment* env,
438 const char* main_script_source_utf8,
439 std::unique_ptr<InspectorParentHandle> removeme) {
440 CHECK_NOT_NULL(main_script_source_utf8);
441 return LoadEnvironment(
442 env,
443 [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
444 // This is a slightly hacky way to convert UTF-8 to UTF-16.
445 Local<String> str =
446 String::NewFromUtf8(env->isolate(),
447 main_script_source_utf8,
448 v8::NewStringType::kNormal).ToLocalChecked();
449 auto main_utf16 = std::make_unique<String::Value>(env->isolate(), str);
450
451 // TODO(addaleax): Avoid having a global table for all scripts.
452 std::string name = "embedder_main_" + std::to_string(env->thread_id());
453 native_module::NativeModuleEnv::Add(
454 name.c_str(),
455 UnionBytes(**main_utf16, main_utf16->length()));
456 env->set_main_utf16(std::move(main_utf16));
457 std::vector<Local<String>> params = {
458 env->process_string(),
459 env->require_string()};
460 std::vector<Local<Value>> args = {
461 env->process_object(),
462 env->native_module_require()};
463 return ExecuteBootstrapper(env, name.c_str(), ¶ms, &args);
464 });
465 }
466
GetCurrentEnvironment(Local<Context> context)467 Environment* GetCurrentEnvironment(Local<Context> context) {
468 return Environment::GetCurrent(context);
469 }
470
GetMainThreadMultiIsolatePlatform()471 MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
472 return per_process::v8_platform.Platform();
473 }
474
GetMultiIsolatePlatform(Environment * env)475 MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env) {
476 return GetMultiIsolatePlatform(env->isolate_data());
477 }
478
GetMultiIsolatePlatform(IsolateData * env)479 MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
480 return env->platform();
481 }
482
CreatePlatform(int thread_pool_size,node::tracing::TracingController * tracing_controller)483 MultiIsolatePlatform* CreatePlatform(
484 int thread_pool_size,
485 node::tracing::TracingController* tracing_controller) {
486 return CreatePlatform(
487 thread_pool_size,
488 static_cast<v8::TracingController*>(tracing_controller));
489 }
490
CreatePlatform(int thread_pool_size,v8::TracingController * tracing_controller)491 MultiIsolatePlatform* CreatePlatform(
492 int thread_pool_size,
493 v8::TracingController* tracing_controller) {
494 return MultiIsolatePlatform::Create(thread_pool_size, tracing_controller)
495 .release();
496 }
497
FreePlatform(MultiIsolatePlatform * platform)498 void FreePlatform(MultiIsolatePlatform* platform) {
499 delete platform;
500 }
501
Create(int thread_pool_size,v8::TracingController * tracing_controller)502 std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
503 int thread_pool_size,
504 v8::TracingController* tracing_controller) {
505 return std::make_unique<NodePlatform>(thread_pool_size, tracing_controller);
506 }
507
GetPerContextExports(Local<Context> context)508 MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
509 Isolate* isolate = context->GetIsolate();
510 EscapableHandleScope handle_scope(isolate);
511
512 Local<Object> global = context->Global();
513 Local<Private> key = Private::ForApi(isolate,
514 FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
515
516 Local<Value> existing_value;
517 if (!global->GetPrivate(context, key).ToLocal(&existing_value))
518 return MaybeLocal<Object>();
519 if (existing_value->IsObject())
520 return handle_scope.Escape(existing_value.As<Object>());
521
522 Local<Object> exports = Object::New(isolate);
523 if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
524 !InitializePrimordials(context))
525 return MaybeLocal<Object>();
526 return handle_scope.Escape(exports);
527 }
528
529 // Any initialization logic should be performed in
530 // InitializeContext, because embedders don't necessarily
531 // call NewContext and so they will experience breakages.
NewContext(Isolate * isolate,Local<ObjectTemplate> object_template)532 Local<Context> NewContext(Isolate* isolate,
533 Local<ObjectTemplate> object_template) {
534 auto context = Context::New(isolate, nullptr, object_template);
535 if (context.IsEmpty()) return context;
536
537 if (!InitializeContext(context)) {
538 return Local<Context>();
539 }
540
541 return context;
542 }
543
ProtoThrower(const FunctionCallbackInfo<Value> & info)544 void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
545 THROW_ERR_PROTO_ACCESS(info.GetIsolate());
546 }
547
548 // This runs at runtime, regardless of whether the context
549 // is created from a snapshot.
InitializeContextRuntime(Local<Context> context)550 void InitializeContextRuntime(Local<Context> context) {
551 Isolate* isolate = context->GetIsolate();
552 HandleScope handle_scope(isolate);
553
554 // Delete `Intl.v8BreakIterator`
555 // https://github.com/nodejs/node/issues/14909
556 Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
557 Local<String> break_iter_string =
558 FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
559 Local<Value> intl_v;
560 if (context->Global()->Get(context, intl_string).ToLocal(&intl_v) &&
561 intl_v->IsObject()) {
562 Local<Object> intl = intl_v.As<Object>();
563 intl->Delete(context, break_iter_string).Check();
564 }
565
566 // Delete `Atomics.wake`
567 // https://github.com/nodejs/node/issues/21219
568 Local<String> atomics_string = FIXED_ONE_BYTE_STRING(isolate, "Atomics");
569 Local<String> wake_string = FIXED_ONE_BYTE_STRING(isolate, "wake");
570 Local<Value> atomics_v;
571 if (context->Global()->Get(context, atomics_string).ToLocal(&atomics_v) &&
572 atomics_v->IsObject()) {
573 Local<Object> atomics = atomics_v.As<Object>();
574 atomics->Delete(context, wake_string).Check();
575 }
576
577 // Remove __proto__
578 // https://github.com/nodejs/node/issues/31951
579 Local<String> object_string = FIXED_ONE_BYTE_STRING(isolate, "Object");
580 Local<String> prototype_string = FIXED_ONE_BYTE_STRING(isolate, "prototype");
581 Local<Object> prototype = context->Global()
582 ->Get(context, object_string)
583 .ToLocalChecked()
584 .As<Object>()
585 ->Get(context, prototype_string)
586 .ToLocalChecked()
587 .As<Object>();
588 Local<String> proto_string = FIXED_ONE_BYTE_STRING(isolate, "__proto__");
589 if (per_process::cli_options->disable_proto == "delete") {
590 prototype->Delete(context, proto_string).ToChecked();
591 } else if (per_process::cli_options->disable_proto == "throw") {
592 Local<Value> thrower =
593 Function::New(context, ProtoThrower).ToLocalChecked();
594 PropertyDescriptor descriptor(thrower, thrower);
595 descriptor.set_enumerable(false);
596 descriptor.set_configurable(true);
597 prototype->DefineProperty(context, proto_string, descriptor).ToChecked();
598 } else if (per_process::cli_options->disable_proto != "") {
599 // Validated in ProcessGlobalArgs
600 FatalError("InitializeContextRuntime()", "invalid --disable-proto mode");
601 }
602 }
603
InitializeContextForSnapshot(Local<Context> context)604 bool InitializeContextForSnapshot(Local<Context> context) {
605 Isolate* isolate = context->GetIsolate();
606 HandleScope handle_scope(isolate);
607
608 context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
609 True(isolate));
610 return InitializePrimordials(context);
611 }
612
InitializePrimordials(Local<Context> context)613 bool InitializePrimordials(Local<Context> context) {
614 // Run per-context JS files.
615 Isolate* isolate = context->GetIsolate();
616 Context::Scope context_scope(context);
617 Local<Object> exports;
618
619 Local<String> primordials_string =
620 FIXED_ONE_BYTE_STRING(isolate, "primordials");
621 Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
622 Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
623
624 // Create primordials first and make it available to per-context scripts.
625 Local<Object> primordials = Object::New(isolate);
626 if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
627 !GetPerContextExports(context).ToLocal(&exports) ||
628 !exports->Set(context, primordials_string, primordials).FromJust()) {
629 return false;
630 }
631
632 static const char* context_files[] = {"internal/per_context/primordials",
633 "internal/per_context/domexception",
634 "internal/per_context/messageport",
635 nullptr};
636
637 for (const char** module = context_files; *module != nullptr; module++) {
638 std::vector<Local<String>> parameters = {
639 global_string, exports_string, primordials_string};
640 Local<Value> arguments[] = {context->Global(), exports, primordials};
641 MaybeLocal<Function> maybe_fn =
642 native_module::NativeModuleEnv::LookupAndCompile(
643 context, *module, ¶meters, nullptr);
644 Local<Function> fn;
645 if (!maybe_fn.ToLocal(&fn)) {
646 return false;
647 }
648 MaybeLocal<Value> result =
649 fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
650 // Execution failed during context creation.
651 // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
652 if (result.IsEmpty()) {
653 return false;
654 }
655 }
656
657 return true;
658 }
659
InitializeContext(Local<Context> context)660 bool InitializeContext(Local<Context> context) {
661 if (!InitializeContextForSnapshot(context)) {
662 return false;
663 }
664
665 InitializeContextRuntime(context);
666 return true;
667 }
668
GetCurrentEventLoop(Isolate * isolate)669 uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
670 HandleScope handle_scope(isolate);
671 Local<Context> context = isolate->GetCurrentContext();
672 if (context.IsEmpty()) return nullptr;
673 Environment* env = Environment::GetCurrent(context);
674 if (env == nullptr) return nullptr;
675 return env->event_loop();
676 }
677
AddLinkedBinding(Environment * env,const node_module & mod)678 void AddLinkedBinding(Environment* env, const node_module& mod) {
679 CHECK_NOT_NULL(env);
680 Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
681
682 node_module* prev_head = env->extra_linked_bindings_head();
683 env->extra_linked_bindings()->push_back(mod);
684 if (prev_head != nullptr)
685 prev_head->nm_link = &env->extra_linked_bindings()->back();
686 }
687
AddLinkedBinding(Environment * env,const char * name,addon_context_register_func fn,void * priv)688 void AddLinkedBinding(Environment* env,
689 const char* name,
690 addon_context_register_func fn,
691 void* priv) {
692 node_module mod = {
693 NODE_MODULE_VERSION,
694 NM_F_LINKED,
695 nullptr, // nm_dso_handle
696 nullptr, // nm_filename
697 nullptr, // nm_register_func
698 fn,
699 name,
700 priv,
701 nullptr // nm_link
702 };
703 AddLinkedBinding(env, mod);
704 }
705
706 static std::atomic<uint64_t> next_thread_id{0};
707
AllocateEnvironmentThreadId()708 ThreadId AllocateEnvironmentThreadId() {
709 ThreadId ret;
710 ret.id = next_thread_id++;
711 return ret;
712 }
713
DefaultProcessExitHandler(Environment * env,int exit_code)714 void DefaultProcessExitHandler(Environment* env, int exit_code) {
715 Stop(env);
716 DisposePlatform();
717 uv_library_shutdown();
718 exit(exit_code);
719 }
720
721
SetProcessExitHandler(Environment * env,std::function<void (Environment *,int)> && handler)722 void SetProcessExitHandler(Environment* env,
723 std::function<void(Environment*, int)>&& handler) {
724 env->set_process_exit_handler(std::move(handler));
725 }
726
727 } // namespace node
728