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