• 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::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(&params, 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(), &params, &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, &parameters, 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