blob: 35f1d78cfc8b75abbfbab97f93d97c952c728358 [file] [log] [blame]
Joyee Cheungca9e24e2019-01-16 19:00:551#include "node.h"
2#include "node_context_data.h"
3#include "node_errors.h"
4#include "node_internals.h"
Joyee Cheungdfd7e992019-04-09 21:08:485#include "node_native_module_env.h"
Joyee Cheungca9e24e2019-01-16 19:00:556#include "node_platform.h"
Joyee Cheungca9e24e2019-01-16 19:00:557#include "node_v8_platform-inl.h"
8#include "uv.h"
9
Anna Henningsena9fb51f2019-11-11 14:24:1310#if HAVE_INSPECTOR
11#include "inspector/worker_inspector.h" // ParentInspectorHandle
12#endif
13
Joyee Cheungca9e24e2019-01-16 19:00:5514namespace node {
Gus Caplanb046bd12019-03-19 23:00:1615using errors::TryCatchScope;
16using v8::Array;
Joyee Cheungca9e24e2019-01-16 19:00:5517using v8::Context;
Anna Henningsenb0de48e2019-03-07 14:45:3118using v8::EscapableHandleScope;
Gus Caplan545f7282019-10-11 22:53:4119using v8::FinalizationGroup;
Joyee Cheungca9e24e2019-01-16 19:00:5520using v8::Function;
Gus Caplan7a742ec2020-03-15 00:54:1521using v8::FunctionCallbackInfo;
Joyee Cheungca9e24e2019-01-16 19:00:5522using v8::HandleScope;
23using v8::Isolate;
24using v8::Local;
25using v8::MaybeLocal;
Joyee Cheungca9e24e2019-01-16 19:00:5526using v8::MicrotasksPolicy;
Joyee Cheung3da36d02019-04-10 08:31:5227using v8::Null;
Anna Henningsenb0de48e2019-03-07 14:45:3128using v8::Object;
Joyee Cheungca9e24e2019-01-16 19:00:5529using v8::ObjectTemplate;
Anna Henningsenb0de48e2019-03-07 14:45:3130using v8::Private;
Gus Caplan7a742ec2020-03-15 00:54:1531using v8::PropertyDescriptor;
Joyee Cheungca9e24e2019-01-16 19:00:5532using v8::String;
33using v8::Value;
34
35static bool AllowWasmCodeGenerationCallback(Local<Context> context,
36 Local<String>) {
37 Local<Value> wasm_code_gen =
38 context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
39 return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
40}
41
42static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
Anna Henningsen2699f8c2019-03-05 22:03:2443 DebugSealHandleScope scope(isolate);
Joyee Cheungca9e24e2019-01-16 19:00:5544 Environment* env = Environment::GetCurrent(isolate);
Anna Henningsen85b95cc2019-02-14 22:30:3745 return env != nullptr &&
Gireesh Punathild35af562018-06-12 13:01:4646 (env->is_main_thread() || !env->is_stopping()) &&
Anna Henningsen85b95cc2019-02-14 22:30:3747 env->should_abort_on_uncaught_toggle()[0] &&
Joyee Cheungca9e24e2019-01-16 19:00:5548 !env->inside_should_not_abort_on_uncaught_scope();
49}
50
Gus Caplanb046bd12019-03-19 23:00:1651static 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 MaybeLocal<String> s = exception->ToString(context);
57 return s.IsEmpty() ?
58 MaybeLocal<Value>() :
59 MaybeLocal<Value>(s.ToLocalChecked());
60 }
61 Local<Function> prepare = env->prepare_stack_trace_callback();
62 if (prepare.IsEmpty()) {
63 MaybeLocal<String> s = exception->ToString(context);
64 return s.IsEmpty() ?
65 MaybeLocal<Value>() :
66 MaybeLocal<Value>(s.ToLocalChecked());
67 }
68 Local<Value> args[] = {
69 context->Global(),
70 exception,
71 trace,
72 };
73 // This TryCatch + Rethrow is required by V8 due to details around exception
74 // handling there. For C++ callbacks, V8 expects a scheduled exception (which
75 // is what ReThrow gives us). Just returning the empty MaybeLocal would leave
76 // us with a pending exception.
77 TryCatchScope try_catch(env);
78 MaybeLocal<Value> result = prepare->Call(
79 context, Undefined(env->isolate()), arraysize(args), args);
80 if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
81 try_catch.ReThrow();
82 }
83 return result;
84}
85
Gus Caplan545f7282019-10-11 22:53:4186static void HostCleanupFinalizationGroupCallback(
87 Local<Context> context, Local<FinalizationGroup> group) {
88 Environment* env = Environment::GetCurrent(context);
89 if (env == nullptr) {
90 return;
91 }
92 env->RegisterFinalizationGroupForCleanup(group);
93}
94
Anna Henningsen0e3addd2019-03-08 15:19:3395void* NodeArrayBufferAllocator::Allocate(size_t size) {
Anna Henningsenabe6a2e2020-01-28 14:25:1096 void* ret;
Joyee Cheungca9e24e2019-01-16 19:00:5597 if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
Anna Henningsenabe6a2e2020-01-28 14:25:1098 ret = UncheckedCalloc(size);
Joyee Cheungca9e24e2019-01-16 19:00:5599 else
Anna Henningsenabe6a2e2020-01-28 14:25:10100 ret = UncheckedMalloc(size);
101 if (LIKELY(ret != nullptr))
102 total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
103 return ret;
104}
105
106void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
107 void* ret = node::UncheckedMalloc(size);
108 if (LIKELY(ret != nullptr))
109 total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
110 return ret;
111}
112
Ulan Degenbaev445af352020-01-27 16:23:57113void* NodeArrayBufferAllocator::ReallocateBuffer(
Anna Henningsenabe6a2e2020-01-28 14:25:10114 void* data, size_t old_size, size_t size) {
115 void* ret = UncheckedRealloc<char>(static_cast<char*>(data), size);
116 if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
117 total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
118 return ret;
119}
120
121void NodeArrayBufferAllocator::Free(void* data, size_t size) {
122 total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
123 free(data);
Joyee Cheungca9e24e2019-01-16 19:00:55124}
125
Anna Henningsen37673532019-02-18 16:30:10126DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
127 CHECK(allocations_.empty());
128}
129
130void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
131 Mutex::ScopedLock lock(mutex_);
Anna Henningsen0e3addd2019-03-08 15:19:33132 void* data = NodeArrayBufferAllocator::Allocate(size);
Anna Henningsen37673532019-02-18 16:30:10133 RegisterPointerInternal(data, size);
134 return data;
135}
136
137void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
138 Mutex::ScopedLock lock(mutex_);
Anna Henningsen0e3addd2019-03-08 15:19:33139 void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
Anna Henningsen37673532019-02-18 16:30:10140 RegisterPointerInternal(data, size);
141 return data;
142}
143
144void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
145 Mutex::ScopedLock lock(mutex_);
146 UnregisterPointerInternal(data, size);
Anna Henningsen0e3addd2019-03-08 15:19:33147 NodeArrayBufferAllocator::Free(data, size);
Anna Henningsen37673532019-02-18 16:30:10148}
149
Ulan Degenbaev445af352020-01-27 16:23:57150void* DebuggingArrayBufferAllocator::ReallocateBuffer(void* data,
Anna Henningsen37673532019-02-18 16:30:10151 size_t old_size,
152 size_t size) {
153 Mutex::ScopedLock lock(mutex_);
Ulan Degenbaev445af352020-01-27 16:23:57154 void* ret = NodeArrayBufferAllocator::ReallocateBuffer(data, old_size, size);
Anna Henningsen37673532019-02-18 16:30:10155 if (ret == nullptr) {
156 if (size == 0) // i.e. equivalent to free().
157 UnregisterPointerInternal(data, old_size);
158 return nullptr;
159 }
160
161 if (data != nullptr) {
162 auto it = allocations_.find(data);
163 CHECK_NE(it, allocations_.end());
164 allocations_.erase(it);
165 }
166
167 RegisterPointerInternal(ret, size);
168 return ret;
169}
170
171void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
172 Mutex::ScopedLock lock(mutex_);
Anna Henningsenabe6a2e2020-01-28 14:25:10173 NodeArrayBufferAllocator::RegisterPointer(data, size);
Anna Henningsen37673532019-02-18 16:30:10174 RegisterPointerInternal(data, size);
175}
176
177void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
178 Mutex::ScopedLock lock(mutex_);
Anna Henningsenabe6a2e2020-01-28 14:25:10179 NodeArrayBufferAllocator::UnregisterPointer(data, size);
Anna Henningsen37673532019-02-18 16:30:10180 UnregisterPointerInternal(data, size);
181}
182
183void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
184 size_t size) {
185 if (data == nullptr) return;
186 auto it = allocations_.find(data);
187 CHECK_NE(it, allocations_.end());
Anna Henningsen427fce72019-04-10 08:53:54188 if (size > 0) {
189 // We allow allocations with size 1 for 0-length buffers to avoid having
190 // to deal with nullptr values.
191 CHECK_EQ(it->second, size);
192 }
Anna Henningsen37673532019-02-18 16:30:10193 allocations_.erase(it);
194}
195
196void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
197 size_t size) {
198 if (data == nullptr) return;
199 CHECK_EQ(allocations_.count(data), 0);
200 allocations_[data] = size;
201}
202
Anna Henningsen0e3addd2019-03-08 15:19:33203std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
204 if (debug || per_process::cli_options->debug_arraybuffer_allocations)
205 return std::make_unique<DebuggingArrayBufferAllocator>();
Anna Henningsen37673532019-02-18 16:30:10206 else
Anna Henningsen0e3addd2019-03-08 15:19:33207 return std::make_unique<NodeArrayBufferAllocator>();
208}
209
210ArrayBufferAllocator* CreateArrayBufferAllocator() {
211 return ArrayBufferAllocator::Create().release();
Joyee Cheungca9e24e2019-01-16 19:00:55212}
213
214void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
215 delete allocator;
216}
217
Joyee Cheungcab1dc52019-04-14 06:41:04218void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
Victor Gomes64159cb2020-04-24 15:28:20219#ifndef __Fuchsia__
Kelvin Jin285e0362019-05-17 22:34:19220 const uint64_t constrained_memory = uv_get_constrained_memory();
221 const uint64_t total_memory = constrained_memory > 0 ?
222 std::min(uv_get_total_memory(), constrained_memory) :
223 uv_get_total_memory();
Ali Ijaz Sheikh1d996f52019-02-01 19:38:52224 if (total_memory > 0) {
225 // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
226 // This default is based on browser use-cases. Tell V8 to configure the
227 // heap based on the actual physical memory.
Anna Henningsenb21e7c72019-03-08 15:55:40228 params->constraints.ConfigureDefaults(total_memory, 0);
Ali Ijaz Sheikh1d996f52019-02-01 19:38:52229 }
Victor Gomes64159cb2020-04-24 15:28:20230#endif
Anna Henningsenb21e7c72019-03-08 15:55:40231}
Joyee Cheungca9e24e2019-01-16 19:00:55232
Shelley Vohrfc02cf52019-10-26 04:14:36233void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
234 if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
235 isolate->AddMessageListenerWithErrorLevel(
236 errors::PerIsolateMessageListener,
237 Isolate::MessageErrorLevel::kMessageError |
238 Isolate::MessageErrorLevel::kMessageWarning);
239
240 auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
241 s.should_abort_on_uncaught_exception_callback :
242 ShouldAbortOnUncaughtException;
243 isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
244
245 auto* fatal_error_cb = s.fatal_error_callback ?
246 s.fatal_error_callback : OnFatalError;
247 isolate->SetFatalErrorHandler(fatal_error_cb);
248
249 auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
250 s.prepare_stack_trace_callback : PrepareStackTraceCallback;
251 isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
252}
253
254void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
255 isolate->SetMicrotasksPolicy(s.policy);
256
257 auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
258 s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
259 isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
260
261 auto* promise_reject_cb = s.promise_reject_callback ?
262 s.promise_reject_callback : task_queue::PromiseRejectCallback;
263 isolate->SetPromiseRejectCallback(promise_reject_cb);
264
265 auto* host_cleanup_cb = s.host_cleanup_finalization_group_callback ?
266 s.host_cleanup_finalization_group_callback :
267 HostCleanupFinalizationGroupCallback;
268 isolate->SetHostCleanupFinalizationGroupCallback(host_cleanup_cb);
269
270 if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
271 v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
272}
273
274void SetIsolateUpForNode(v8::Isolate* isolate,
275 const IsolateSettings& settings) {
276 SetIsolateErrorHandlers(isolate, settings);
277 SetIsolateMiscHandlers(isolate, settings);
Joyee Cheung70d887e2019-04-19 04:50:38278}
279
Anna Henningsenb21e7c72019-03-08 15:55:40280void SetIsolateUpForNode(v8::Isolate* isolate) {
Shelley Vohrfc02cf52019-10-26 04:14:36281 IsolateSettings settings;
282 SetIsolateUpForNode(isolate, settings);
Anna Henningsenb21e7c72019-03-08 15:55:40283}
284
285Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
286 return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform());
287}
288
Joyee Cheungcab1dc52019-04-14 06:41:04289// TODO(joyeecheung): we may want to expose this, but then we need to be
290// careful about what we override in the params.
291Isolate* NewIsolate(Isolate::CreateParams* params,
Anna Henningsenb21e7c72019-03-08 15:55:40292 uv_loop_t* event_loop,
293 MultiIsolatePlatform* platform) {
Anna Henningsenb21e7c72019-03-08 15:55:40294 Isolate* isolate = Isolate::Allocate();
295 if (isolate == nullptr) return nullptr;
296
297 // Register the isolate on the platform before the isolate gets initialized,
298 // so that the isolate can access the platform during initialization.
299 platform->RegisterIsolate(isolate, event_loop);
Anna Henningsenb21e7c72019-03-08 15:55:40300
Joyee Cheungcab1dc52019-04-14 06:41:04301 SetIsolateCreateParamsForNode(params);
302 Isolate::Initialize(isolate, *params);
Anna Henningsenb21e7c72019-03-08 15:55:40303 SetIsolateUpForNode(isolate);
Joyee Cheungca9e24e2019-01-16 19:00:55304
305 return isolate;
306}
307
Joyee Cheungcab1dc52019-04-14 06:41:04308Isolate* NewIsolate(ArrayBufferAllocator* allocator,
309 uv_loop_t* event_loop,
310 MultiIsolatePlatform* platform) {
311 Isolate::CreateParams params;
312 if (allocator != nullptr) params.array_buffer_allocator = allocator;
313 return NewIsolate(&params, event_loop, platform);
314}
315
Anna Henningsen2bdeb882019-10-22 20:03:53316Isolate* NewIsolate(std::shared_ptr<ArrayBufferAllocator> allocator,
317 uv_loop_t* event_loop,
318 MultiIsolatePlatform* platform) {
319 Isolate::CreateParams params;
320 if (allocator) params.array_buffer_allocator_shared = allocator;
321 return NewIsolate(&params, event_loop, platform);
322}
323
Joyee Cheungca9e24e2019-01-16 19:00:55324IsolateData* CreateIsolateData(Isolate* isolate,
325 uv_loop_t* loop,
326 MultiIsolatePlatform* platform,
327 ArrayBufferAllocator* allocator) {
Anna Henningsen5c0e18f2019-02-18 16:30:42328 return new IsolateData(isolate, loop, platform, allocator);
Joyee Cheungca9e24e2019-01-16 19:00:55329}
330
331void FreeIsolateData(IsolateData* isolate_data) {
332 delete isolate_data;
333}
334
Anna Henningsen8aa7ef72020-04-05 21:13:31335InspectorParentHandle::~InspectorParentHandle() {}
336
337// Hide the internal handle class from the public API.
338#if HAVE_INSPECTOR
339struct InspectorParentHandleImpl : public InspectorParentHandle {
340 std::unique_ptr<inspector::ParentInspectorHandle> impl;
341
342 explicit InspectorParentHandleImpl(
343 std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
344 : impl(std::move(impl)) {}
345};
346#endif
347
Joyee Cheungca9e24e2019-01-16 19:00:55348Environment* CreateEnvironment(IsolateData* isolate_data,
349 Local<Context> context,
350 int argc,
351 const char* const* argv,
352 int exec_argc,
353 const char* const* exec_argv) {
Anna Henningsena9fb51f2019-11-11 14:24:13354 return CreateEnvironment(
355 isolate_data, context,
356 std::vector<std::string>(argv, argv + argc),
357 std::vector<std::string>(exec_argv, exec_argv + exec_argc));
358}
359
360Environment* CreateEnvironment(
361 IsolateData* isolate_data,
362 Local<Context> context,
363 const std::vector<std::string>& args,
364 const std::vector<std::string>& exec_args,
365 EnvironmentFlags::Flags flags,
Anna Henningsen8aa7ef72020-04-05 21:13:31366 ThreadId thread_id,
367 std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
Joyee Cheungca9e24e2019-01-16 19:00:55368 Isolate* isolate = context->GetIsolate();
369 HandleScope handle_scope(isolate);
370 Context::Scope context_scope(context);
371 // TODO(addaleax): This is a much better place for parsing per-Environment
372 // options than the global parse call.
Anna Henningsen39eca842019-02-01 22:47:38373 Environment* env = new Environment(
374 isolate_data,
375 context,
Joyee Cheungbda7da32019-05-20 11:06:55376 args,
377 exec_args,
Anna Henningsena9fb51f2019-11-11 14:24:13378 flags,
379 thread_id);
380 if (flags & EnvironmentFlags::kOwnsProcessState) {
381 env->set_abort_on_uncaught_exception(false);
382 }
383
Anna Henningsen8aa7ef72020-04-05 21:13:31384#if HAVE_INSPECTOR
385 if (inspector_parent_handle) {
386 env->InitializeInspector(
387 std::move(static_cast<InspectorParentHandleImpl*>(
388 inspector_parent_handle.get())->impl));
389 } else {
390 env->InitializeInspector({});
391 }
392#endif
393
Anna Henningsen288382a2019-11-11 12:29:07394 if (env->RunBootstrapping().IsEmpty()) {
395 FreeEnvironment(env);
Joyee Cheung19442652019-03-19 16:12:23396 return nullptr;
Anna Henningsen288382a2019-11-11 12:29:07397 }
Anna Henningsena9fb51f2019-11-11 14:24:13398
Joyee Cheungca9e24e2019-01-16 19:00:55399 return env;
400}
401
402void FreeEnvironment(Environment* env) {
Anna Henningsend7bc5812019-11-10 19:47:03403 {
404 // TODO(addaleax): This should maybe rather be in a SealHandleScope.
405 HandleScope handle_scope(env->isolate());
406 Context::Scope context_scope(env->context());
407 env->set_stopping(true);
408 env->stop_sub_worker_contexts();
409 env->RunCleanup();
410 RunAtExit(env);
411 }
412
413 // This call needs to be made while the `Environment` is still alive
414 // because we assume that it is available for async tracking in the
415 // NodePlatform implementation.
416 MultiIsolatePlatform* platform = env->isolate_data()->platform();
417 if (platform != nullptr)
418 platform->DrainTasks(env->isolate());
419
Joyee Cheungca9e24e2019-01-16 19:00:55420 delete env;
421}
422
Anna Henningsena9fb51f2019-11-11 14:24:13423NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
424 Environment* env,
425 ThreadId thread_id,
426 const char* url) {
427 CHECK_NOT_NULL(env);
428 CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
429#if HAVE_INSPECTOR
430 return std::make_unique<InspectorParentHandleImpl>(
431 env->inspector_agent()->GetParentHandle(thread_id.id, url));
432#else
433 return {};
434#endif
435}
436
437void LoadEnvironment(Environment* env) {
Anna Henningsen7dead842019-11-19 14:42:09438 USE(LoadEnvironment(env,
439 StartExecutionCallback{},
440 {}));
Anna Henningsena9fb51f2019-11-11 14:24:13441}
442
443MaybeLocal<Value> LoadEnvironment(
444 Environment* env,
Anna Henningsenc44edec2019-11-13 15:54:57445 StartExecutionCallback cb,
Anna Henningsen8aa7ef72020-04-05 21:13:31446 std::unique_ptr<InspectorParentHandle> removeme) {
Anna Henningsena9fb51f2019-11-11 14:24:13447 env->InitializeLibuv(per_process::v8_is_profiling);
448 env->InitializeDiagnostics();
449
Anna Henningsenc44edec2019-11-13 15:54:57450 return StartExecution(env, cb);
Anna Henningsena9fb51f2019-11-11 14:24:13451}
452
Anna Henningsen7dead842019-11-19 14:42:09453MaybeLocal<Value> LoadEnvironment(
454 Environment* env,
455 const char* main_script_source_utf8,
Anna Henningsen8aa7ef72020-04-05 21:13:31456 std::unique_ptr<InspectorParentHandle> removeme) {
Anna Henningsen7dead842019-11-19 14:42:09457 CHECK_NOT_NULL(main_script_source_utf8);
458 return LoadEnvironment(
459 env,
460 [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
461 // This is a slightly hacky way to convert UTF-8 to UTF-16.
462 Local<String> str =
463 String::NewFromUtf8(env->isolate(),
464 main_script_source_utf8,
465 v8::NewStringType::kNormal).ToLocalChecked();
466 auto main_utf16 = std::make_unique<String::Value>(env->isolate(), str);
467
468 // TODO(addaleax): Avoid having a global table for all scripts.
469 std::string name = "embedder_main_" + std::to_string(env->thread_id());
470 native_module::NativeModuleEnv::Add(
471 name.c_str(),
472 UnionBytes(**main_utf16, main_utf16->length()));
473 env->set_main_utf16(std::move(main_utf16));
474 std::vector<Local<String>> params = {
475 env->process_string(),
476 env->require_string()};
477 std::vector<Local<Value>> args = {
478 env->process_object(),
479 env->native_module_require()};
480 return ExecuteBootstrapper(env, name.c_str(), &params, &args);
Anna Henningsen8aa7ef72020-04-05 21:13:31481 });
Anna Henningsen7dead842019-11-19 14:42:09482}
483
Joyee Cheungca9e24e2019-01-16 19:00:55484Environment* GetCurrentEnvironment(Local<Context> context) {
485 return Environment::GetCurrent(context);
486}
487
488MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
489 return per_process::v8_platform.Platform();
490}
491
Anna Henningsen7e0264d2020-02-28 05:13:59492MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env) {
493 return GetMultiIsolatePlatform(env->isolate_data());
494}
495
496MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
497 return env->platform();
498}
499
Joyee Cheungca9e24e2019-01-16 19:00:55500MultiIsolatePlatform* CreatePlatform(
501 int thread_pool_size,
502 node::tracing::TracingController* tracing_controller) {
Anna Henningsen887b6a12020-02-28 05:43:02503 return CreatePlatform(
504 thread_pool_size,
505 static_cast<v8::TracingController*>(tracing_controller));
506}
507
508MultiIsolatePlatform* CreatePlatform(
509 int thread_pool_size,
510 v8::TracingController* tracing_controller) {
Anna Henningsen821e21d2020-02-28 01:11:35511 return MultiIsolatePlatform::Create(thread_pool_size, tracing_controller)
512 .release();
Joyee Cheungca9e24e2019-01-16 19:00:55513}
514
Joyee Cheungca9e24e2019-01-16 19:00:55515void FreePlatform(MultiIsolatePlatform* platform) {
516 delete platform;
517}
518
Anna Henningsen821e21d2020-02-28 01:11:35519std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
520 int thread_pool_size,
Anna Henningsen887b6a12020-02-28 05:43:02521 v8::TracingController* tracing_controller) {
Anna Henningsen821e21d2020-02-28 01:11:35522 return std::make_unique<NodePlatform>(thread_pool_size, tracing_controller);
523}
524
Anna Henningsenb0de48e2019-03-07 14:45:31525MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
526 Isolate* isolate = context->GetIsolate();
527 EscapableHandleScope handle_scope(isolate);
528
529 Local<Object> global = context->Global();
530 Local<Private> key = Private::ForApi(isolate,
531 FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
532
533 Local<Value> existing_value;
534 if (!global->GetPrivate(context, key).ToLocal(&existing_value))
535 return MaybeLocal<Object>();
536 if (existing_value->IsObject())
537 return handle_scope.Escape(existing_value.As<Object>());
538
539 Local<Object> exports = Object::New(isolate);
Joyee Cheunge6c22772020-02-11 14:49:24540 if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
541 !InitializePrimordials(context))
Anna Henningsenb0de48e2019-03-07 14:45:31542 return MaybeLocal<Object>();
543 return handle_scope.Escape(exports);
544}
545
Shelley Vohrb086e382019-10-22 18:11:25546// Any initialization logic should be performed in
547// InitializeContext, because embedders don't necessarily
548// call NewContext and so they will experience breakages.
Joyee Cheungca9e24e2019-01-16 19:00:55549Local<Context> NewContext(Isolate* isolate,
550 Local<ObjectTemplate> object_template) {
551 auto context = Context::New(isolate, nullptr, object_template);
552 if (context.IsEmpty()) return context;
Samuel Attard33ae95c2019-07-04 22:57:09553
554 if (!InitializeContext(context)) {
555 return Local<Context>();
556 }
Gus Caplan1ec41542019-09-16 21:05:20557
Samuel Attard33ae95c2019-07-04 22:57:09558 return context;
559}
560
Gus Caplan7a742ec2020-03-15 00:54:15561void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
562 THROW_ERR_PROTO_ACCESS(info.GetIsolate());
563}
564
Gus Caplan1ec41542019-09-16 21:05:20565// This runs at runtime, regardless of whether the context
566// is created from a snapshot.
567void InitializeContextRuntime(Local<Context> context) {
568 Isolate* isolate = context->GetIsolate();
569 HandleScope handle_scope(isolate);
570
571 // Delete `Intl.v8BreakIterator`
572 // https://github.com/nodejs/node/issues/14909
573 Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
574 Local<String> break_iter_string =
575 FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
576 Local<Value> intl_v;
577 if (context->Global()->Get(context, intl_string).ToLocal(&intl_v) &&
578 intl_v->IsObject()) {
579 Local<Object> intl = intl_v.As<Object>();
580 intl->Delete(context, break_iter_string).FromJust();
581 }
582
583 // Delete `Atomics.wake`
584 // https://github.com/nodejs/node/issues/21219
585 Local<String> atomics_string = FIXED_ONE_BYTE_STRING(isolate, "Atomics");
586 Local<String> wake_string = FIXED_ONE_BYTE_STRING(isolate, "wake");
587 Local<Value> atomics_v;
588 if (context->Global()->Get(context, atomics_string).ToLocal(&atomics_v) &&
589 atomics_v->IsObject()) {
590 Local<Object> atomics = atomics_v.As<Object>();
591 atomics->Delete(context, wake_string).FromJust();
592 }
Gus Caplan7a742ec2020-03-15 00:54:15593
594 // Remove __proto__
595 // https://github.com/nodejs/node/issues/31951
596 Local<String> object_string = FIXED_ONE_BYTE_STRING(isolate, "Object");
597 Local<String> prototype_string = FIXED_ONE_BYTE_STRING(isolate, "prototype");
598 Local<Object> prototype = context->Global()
599 ->Get(context, object_string)
600 .ToLocalChecked()
601 .As<Object>()
602 ->Get(context, prototype_string)
603 .ToLocalChecked()
604 .As<Object>();
605 Local<String> proto_string = FIXED_ONE_BYTE_STRING(isolate, "__proto__");
606 if (per_process::cli_options->disable_proto == "delete") {
607 prototype->Delete(context, proto_string).ToChecked();
608 } else if (per_process::cli_options->disable_proto == "throw") {
609 Local<Value> thrower =
610 Function::New(context, ProtoThrower).ToLocalChecked();
611 PropertyDescriptor descriptor(thrower, thrower);
612 descriptor.set_enumerable(false);
613 descriptor.set_configurable(true);
614 prototype->DefineProperty(context, proto_string, descriptor).ToChecked();
615 } else if (per_process::cli_options->disable_proto != "") {
616 // Validated in ProcessGlobalArgs
617 FatalError("InitializeContextRuntime()", "invalid --disable-proto mode");
618 }
Gus Caplan1ec41542019-09-16 21:05:20619}
620
Shelley Vohrb086e382019-10-22 18:11:25621bool InitializeContextForSnapshot(Local<Context> context) {
Samuel Attard33ae95c2019-07-04 22:57:09622 Isolate* isolate = context->GetIsolate();
Joyee Cheungca9e24e2019-01-16 19:00:55623 HandleScope handle_scope(isolate);
624
625 context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
626 True(isolate));
Joyee Cheunge6c22772020-02-11 14:49:24627 return InitializePrimordials(context);
628}
Joyee Cheungca9e24e2019-01-16 19:00:55629
Joyee Cheunge6c22772020-02-11 14:49:24630bool InitializePrimordials(Local<Context> context) {
631 // Run per-context JS files.
632 Isolate* isolate = context->GetIsolate();
633 Context::Scope context_scope(context);
634 Local<Object> exports;
Anna Henningsenb0de48e2019-03-07 14:45:31635
Joyee Cheunge6c22772020-02-11 14:49:24636 Local<String> primordials_string =
637 FIXED_ONE_BYTE_STRING(isolate, "primordials");
638 Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
639 Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
Joyee Cheungca9e24e2019-01-16 19:00:55640
Joyee Cheunge6c22772020-02-11 14:49:24641 // Create primordials first and make it available to per-context scripts.
642 Local<Object> primordials = Object::New(isolate);
643 if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
644 !GetPerContextExports(context).ToLocal(&exports) ||
645 !exports->Set(context, primordials_string, primordials).FromJust()) {
646 return false;
647 }
648
649 static const char* context_files[] = {"internal/per_context/primordials",
650 "internal/per_context/domexception",
651 "internal/per_context/messageport",
652 nullptr};
653
654 for (const char** module = context_files; *module != nullptr; module++) {
655 std::vector<Local<String>> parameters = {
656 global_string, exports_string, primordials_string};
657 Local<Value> arguments[] = {context->Global(), exports, primordials};
658 MaybeLocal<Function> maybe_fn =
659 native_module::NativeModuleEnv::LookupAndCompile(
660 context, *module, &parameters, nullptr);
661 if (maybe_fn.IsEmpty()) {
Samuel Attard33ae95c2019-07-04 22:57:09662 return false;
Joyee Cheung3da36d02019-04-10 08:31:52663 }
Joyee Cheunge6c22772020-02-11 14:49:24664 Local<Function> fn = maybe_fn.ToLocalChecked();
665 MaybeLocal<Value> result =
666 fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
667 // Execution failed during context creation.
668 // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
669 if (result.IsEmpty()) {
670 return false;
Joyee Cheungca9e24e2019-01-16 19:00:55671 }
672 }
673
Samuel Attard33ae95c2019-07-04 22:57:09674 return true;
Joyee Cheungca9e24e2019-01-16 19:00:55675}
676
Shelley Vohrb086e382019-10-22 18:11:25677bool InitializeContext(Local<Context> context) {
678 if (!InitializeContextForSnapshot(context)) {
679 return false;
680 }
681
682 InitializeContextRuntime(context);
683 return true;
684}
685
Joyee Cheungca9e24e2019-01-16 19:00:55686uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
687 HandleScope handle_scope(isolate);
688 Local<Context> context = isolate->GetCurrentContext();
689 if (context.IsEmpty()) return nullptr;
690 Environment* env = Environment::GetCurrent(context);
691 if (env == nullptr) return nullptr;
692 return env->event_loop();
693}
694
Anna Henningsene460e142019-11-05 21:50:24695void AddLinkedBinding(Environment* env, const node_module& mod) {
696 CHECK_NOT_NULL(env);
697 Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
698
699 node_module* prev_head = env->extra_linked_bindings_head();
700 env->extra_linked_bindings()->push_back(mod);
701 if (prev_head != nullptr)
702 prev_head->nm_link = &env->extra_linked_bindings()->back();
703}
704
705void AddLinkedBinding(Environment* env,
706 const char* name,
707 addon_context_register_func fn,
708 void* priv) {
709 node_module mod = {
710 NODE_MODULE_VERSION,
711 NM_F_LINKED,
712 nullptr, // nm_dso_handle
713 nullptr, // nm_filename
714 nullptr, // nm_register_func
715 fn,
716 name,
717 priv,
718 nullptr // nm_link
719 };
720 AddLinkedBinding(env, mod);
721}
722
Anna Henningsena9fb51f2019-11-11 14:24:13723static std::atomic<uint64_t> next_thread_id{0};
724
725ThreadId AllocateEnvironmentThreadId() {
726 return ThreadId { next_thread_id++ };
727}
728
Anna Henningsend812f162020-03-28 01:46:41729void DefaultProcessExitHandler(Environment* env, int exit_code) {
Anna Henningsenf6215362020-04-02 21:40:25730 env->set_can_call_into_js(false);
731 env->stop_sub_worker_contexts();
Anna Henningsend812f162020-03-28 01:46:41732 DisposePlatform();
733 exit(exit_code);
734}
735
736
737void SetProcessExitHandler(Environment* env,
738 std::function<void(Environment*, int)>&& handler) {
739 env->set_process_exit_handler(std::move(handler));
740}
741
Joyee Cheungca9e24e2019-01-16 19:00:55742} // namespace node