• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params, 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(&params, 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(), &params, &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, &parameters, 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