Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 1 | #include "node.h" |
| 2 | #include "node_context_data.h" |
| 3 | #include "node_errors.h" |
| 4 | #include "node_internals.h" |
Joyee Cheung | dfd7e99 | 2019-04-09 21:08:48 | [diff] [blame] | 5 | #include "node_native_module_env.h" |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 6 | #include "node_platform.h" |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 7 | #include "node_v8_platform-inl.h" |
| 8 | #include "uv.h" |
| 9 | |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 10 | #if HAVE_INSPECTOR |
| 11 | #include "inspector/worker_inspector.h" // ParentInspectorHandle |
| 12 | #endif |
| 13 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 14 | namespace node { |
Gus Caplan | b046bd1 | 2019-03-19 23:00:16 | [diff] [blame] | 15 | using errors::TryCatchScope; |
| 16 | using v8::Array; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 17 | using v8::Context; |
Anna Henningsen | b0de48e | 2019-03-07 14:45:31 | [diff] [blame] | 18 | using v8::EscapableHandleScope; |
Gus Caplan | 545f728 | 2019-10-11 22:53:41 | [diff] [blame] | 19 | using v8::FinalizationGroup; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 20 | using v8::Function; |
Gus Caplan | 7a742ec | 2020-03-15 00:54:15 | [diff] [blame] | 21 | using v8::FunctionCallbackInfo; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 22 | using v8::HandleScope; |
| 23 | using v8::Isolate; |
| 24 | using v8::Local; |
| 25 | using v8::MaybeLocal; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 26 | using v8::MicrotasksPolicy; |
Joyee Cheung | 3da36d0 | 2019-04-10 08:31:52 | [diff] [blame] | 27 | using v8::Null; |
Anna Henningsen | b0de48e | 2019-03-07 14:45:31 | [diff] [blame] | 28 | using v8::Object; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 29 | using v8::ObjectTemplate; |
Anna Henningsen | b0de48e | 2019-03-07 14:45:31 | [diff] [blame] | 30 | using v8::Private; |
Gus Caplan | 7a742ec | 2020-03-15 00:54:15 | [diff] [blame] | 31 | using v8::PropertyDescriptor; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 32 | using v8::String; |
| 33 | using v8::Value; |
| 34 | |
| 35 | static 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 | |
| 42 | static bool ShouldAbortOnUncaughtException(Isolate* isolate) { |
Anna Henningsen | 2699f8c | 2019-03-05 22:03:24 | [diff] [blame] | 43 | DebugSealHandleScope scope(isolate); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 44 | Environment* env = Environment::GetCurrent(isolate); |
Anna Henningsen | 85b95cc | 2019-02-14 22:30:37 | [diff] [blame] | 45 | return env != nullptr && |
Gireesh Punathil | d35af56 | 2018-06-12 13:01:46 | [diff] [blame] | 46 | (env->is_main_thread() || !env->is_stopping()) && |
Anna Henningsen | 85b95cc | 2019-02-14 22:30:37 | [diff] [blame] | 47 | env->should_abort_on_uncaught_toggle()[0] && |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 48 | !env->inside_should_not_abort_on_uncaught_scope(); |
| 49 | } |
| 50 | |
Gus Caplan | b046bd1 | 2019-03-19 23:00:16 | [diff] [blame] | 51 | static 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 Caplan | 545f728 | 2019-10-11 22:53:41 | [diff] [blame] | 86 | static 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 Henningsen | 0e3addd | 2019-03-08 15:19:33 | [diff] [blame] | 95 | void* NodeArrayBufferAllocator::Allocate(size_t size) { |
Anna Henningsen | abe6a2e | 2020-01-28 14:25:10 | [diff] [blame] | 96 | void* ret; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 97 | if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers) |
Anna Henningsen | abe6a2e | 2020-01-28 14:25:10 | [diff] [blame] | 98 | ret = UncheckedCalloc(size); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 99 | else |
Anna Henningsen | abe6a2e | 2020-01-28 14:25:10 | [diff] [blame] | 100 | ret = UncheckedMalloc(size); |
| 101 | if (LIKELY(ret != nullptr)) |
| 102 | total_mem_usage_.fetch_add(size, std::memory_order_relaxed); |
| 103 | return ret; |
| 104 | } |
| 105 | |
| 106 | void* 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 Degenbaev | 445af35 | 2020-01-27 16:23:57 | [diff] [blame] | 113 | void* NodeArrayBufferAllocator::ReallocateBuffer( |
Anna Henningsen | abe6a2e | 2020-01-28 14:25:10 | [diff] [blame] | 114 | 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 | |
| 121 | void NodeArrayBufferAllocator::Free(void* data, size_t size) { |
| 122 | total_mem_usage_.fetch_sub(size, std::memory_order_relaxed); |
| 123 | free(data); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 124 | } |
| 125 | |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 126 | DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() { |
| 127 | CHECK(allocations_.empty()); |
| 128 | } |
| 129 | |
| 130 | void* DebuggingArrayBufferAllocator::Allocate(size_t size) { |
| 131 | Mutex::ScopedLock lock(mutex_); |
Anna Henningsen | 0e3addd | 2019-03-08 15:19:33 | [diff] [blame] | 132 | void* data = NodeArrayBufferAllocator::Allocate(size); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 133 | RegisterPointerInternal(data, size); |
| 134 | return data; |
| 135 | } |
| 136 | |
| 137 | void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) { |
| 138 | Mutex::ScopedLock lock(mutex_); |
Anna Henningsen | 0e3addd | 2019-03-08 15:19:33 | [diff] [blame] | 139 | void* data = NodeArrayBufferAllocator::AllocateUninitialized(size); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 140 | RegisterPointerInternal(data, size); |
| 141 | return data; |
| 142 | } |
| 143 | |
| 144 | void DebuggingArrayBufferAllocator::Free(void* data, size_t size) { |
| 145 | Mutex::ScopedLock lock(mutex_); |
| 146 | UnregisterPointerInternal(data, size); |
Anna Henningsen | 0e3addd | 2019-03-08 15:19:33 | [diff] [blame] | 147 | NodeArrayBufferAllocator::Free(data, size); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 148 | } |
| 149 | |
Ulan Degenbaev | 445af35 | 2020-01-27 16:23:57 | [diff] [blame] | 150 | void* DebuggingArrayBufferAllocator::ReallocateBuffer(void* data, |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 151 | size_t old_size, |
| 152 | size_t size) { |
| 153 | Mutex::ScopedLock lock(mutex_); |
Ulan Degenbaev | 445af35 | 2020-01-27 16:23:57 | [diff] [blame] | 154 | void* ret = NodeArrayBufferAllocator::ReallocateBuffer(data, old_size, size); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 155 | 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 | |
| 171 | void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) { |
| 172 | Mutex::ScopedLock lock(mutex_); |
Anna Henningsen | abe6a2e | 2020-01-28 14:25:10 | [diff] [blame] | 173 | NodeArrayBufferAllocator::RegisterPointer(data, size); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 174 | RegisterPointerInternal(data, size); |
| 175 | } |
| 176 | |
| 177 | void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) { |
| 178 | Mutex::ScopedLock lock(mutex_); |
Anna Henningsen | abe6a2e | 2020-01-28 14:25:10 | [diff] [blame] | 179 | NodeArrayBufferAllocator::UnregisterPointer(data, size); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 180 | UnregisterPointerInternal(data, size); |
| 181 | } |
| 182 | |
| 183 | void 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 Henningsen | 427fce7 | 2019-04-10 08:53:54 | [diff] [blame] | 188 | 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 Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 193 | allocations_.erase(it); |
| 194 | } |
| 195 | |
| 196 | void 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 Henningsen | 0e3addd | 2019-03-08 15:19:33 | [diff] [blame] | 203 | std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) { |
| 204 | if (debug || per_process::cli_options->debug_arraybuffer_allocations) |
| 205 | return std::make_unique<DebuggingArrayBufferAllocator>(); |
Anna Henningsen | 3767353 | 2019-02-18 16:30:10 | [diff] [blame] | 206 | else |
Anna Henningsen | 0e3addd | 2019-03-08 15:19:33 | [diff] [blame] | 207 | return std::make_unique<NodeArrayBufferAllocator>(); |
| 208 | } |
| 209 | |
| 210 | ArrayBufferAllocator* CreateArrayBufferAllocator() { |
| 211 | return ArrayBufferAllocator::Create().release(); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) { |
| 215 | delete allocator; |
| 216 | } |
| 217 | |
Joyee Cheung | cab1dc5 | 2019-04-14 06:41:04 | [diff] [blame] | 218 | void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) { |
Victor Gomes | 64159cb | 2020-04-24 15:28:20 | [diff] [blame] | 219 | #ifndef __Fuchsia__ |
Kelvin Jin | 285e036 | 2019-05-17 22:34:19 | [diff] [blame] | 220 | 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 Sheikh | 1d996f5 | 2019-02-01 19:38:52 | [diff] [blame] | 224 | 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 Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 228 | params->constraints.ConfigureDefaults(total_memory, 0); |
Ali Ijaz Sheikh | 1d996f5 | 2019-02-01 19:38:52 | [diff] [blame] | 229 | } |
Victor Gomes | 64159cb | 2020-04-24 15:28:20 | [diff] [blame] | 230 | #endif |
Anna Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 231 | } |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 232 | |
Shelley Vohr | fc02cf5 | 2019-10-26 04:14:36 | [diff] [blame] | 233 | void 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 | |
| 254 | void 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 | |
| 274 | void SetIsolateUpForNode(v8::Isolate* isolate, |
| 275 | const IsolateSettings& settings) { |
| 276 | SetIsolateErrorHandlers(isolate, settings); |
| 277 | SetIsolateMiscHandlers(isolate, settings); |
Joyee Cheung | 70d887e | 2019-04-19 04:50:38 | [diff] [blame] | 278 | } |
| 279 | |
Anna Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 280 | void SetIsolateUpForNode(v8::Isolate* isolate) { |
Shelley Vohr | fc02cf5 | 2019-10-26 04:14:36 | [diff] [blame] | 281 | IsolateSettings settings; |
| 282 | SetIsolateUpForNode(isolate, settings); |
Anna Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 283 | } |
| 284 | |
| 285 | Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) { |
| 286 | return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform()); |
| 287 | } |
| 288 | |
Joyee Cheung | cab1dc5 | 2019-04-14 06:41:04 | [diff] [blame] | 289 | // TODO(joyeecheung): we may want to expose this, but then we need to be |
| 290 | // careful about what we override in the params. |
| 291 | Isolate* NewIsolate(Isolate::CreateParams* params, |
Anna Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 292 | uv_loop_t* event_loop, |
| 293 | MultiIsolatePlatform* platform) { |
Anna Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 294 | 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 Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 300 | |
Joyee Cheung | cab1dc5 | 2019-04-14 06:41:04 | [diff] [blame] | 301 | SetIsolateCreateParamsForNode(params); |
| 302 | Isolate::Initialize(isolate, *params); |
Anna Henningsen | b21e7c7 | 2019-03-08 15:55:40 | [diff] [blame] | 303 | SetIsolateUpForNode(isolate); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 304 | |
| 305 | return isolate; |
| 306 | } |
| 307 | |
Joyee Cheung | cab1dc5 | 2019-04-14 06:41:04 | [diff] [blame] | 308 | Isolate* 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(¶ms, event_loop, platform); |
| 314 | } |
| 315 | |
Anna Henningsen | 2bdeb88 | 2019-10-22 20:03:53 | [diff] [blame] | 316 | Isolate* 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(¶ms, event_loop, platform); |
| 322 | } |
| 323 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 324 | IsolateData* CreateIsolateData(Isolate* isolate, |
| 325 | uv_loop_t* loop, |
| 326 | MultiIsolatePlatform* platform, |
| 327 | ArrayBufferAllocator* allocator) { |
Anna Henningsen | 5c0e18f | 2019-02-18 16:30:42 | [diff] [blame] | 328 | return new IsolateData(isolate, loop, platform, allocator); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 329 | } |
| 330 | |
| 331 | void FreeIsolateData(IsolateData* isolate_data) { |
| 332 | delete isolate_data; |
| 333 | } |
| 334 | |
Anna Henningsen | 8aa7ef7 | 2020-04-05 21:13:31 | [diff] [blame] | 335 | InspectorParentHandle::~InspectorParentHandle() {} |
| 336 | |
| 337 | // Hide the internal handle class from the public API. |
| 338 | #if HAVE_INSPECTOR |
| 339 | struct 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 Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 348 | Environment* 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 Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 354 | 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 | |
| 360 | Environment* 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 Henningsen | 8aa7ef7 | 2020-04-05 21:13:31 | [diff] [blame] | 366 | ThreadId thread_id, |
| 367 | std::unique_ptr<InspectorParentHandle> inspector_parent_handle) { |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 368 | 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 Henningsen | 39eca84 | 2019-02-01 22:47:38 | [diff] [blame] | 373 | Environment* env = new Environment( |
| 374 | isolate_data, |
| 375 | context, |
Joyee Cheung | bda7da3 | 2019-05-20 11:06:55 | [diff] [blame] | 376 | args, |
| 377 | exec_args, |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 378 | flags, |
| 379 | thread_id); |
| 380 | if (flags & EnvironmentFlags::kOwnsProcessState) { |
| 381 | env->set_abort_on_uncaught_exception(false); |
| 382 | } |
| 383 | |
Anna Henningsen | 8aa7ef7 | 2020-04-05 21:13:31 | [diff] [blame] | 384 | #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 Henningsen | 288382a | 2019-11-11 12:29:07 | [diff] [blame] | 394 | if (env->RunBootstrapping().IsEmpty()) { |
| 395 | FreeEnvironment(env); |
Joyee Cheung | 1944265 | 2019-03-19 16:12:23 | [diff] [blame] | 396 | return nullptr; |
Anna Henningsen | 288382a | 2019-11-11 12:29:07 | [diff] [blame] | 397 | } |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 398 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 399 | return env; |
| 400 | } |
| 401 | |
| 402 | void FreeEnvironment(Environment* env) { |
Anna Henningsen | d7bc581 | 2019-11-10 19:47:03 | [diff] [blame] | 403 | { |
| 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 Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 420 | delete env; |
| 421 | } |
| 422 | |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 423 | NODE_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 | |
| 437 | void LoadEnvironment(Environment* env) { |
Anna Henningsen | 7dead84 | 2019-11-19 14:42:09 | [diff] [blame] | 438 | USE(LoadEnvironment(env, |
| 439 | StartExecutionCallback{}, |
| 440 | {})); |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 441 | } |
| 442 | |
| 443 | MaybeLocal<Value> LoadEnvironment( |
| 444 | Environment* env, |
Anna Henningsen | c44edec | 2019-11-13 15:54:57 | [diff] [blame] | 445 | StartExecutionCallback cb, |
Anna Henningsen | 8aa7ef7 | 2020-04-05 21:13:31 | [diff] [blame] | 446 | std::unique_ptr<InspectorParentHandle> removeme) { |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 447 | env->InitializeLibuv(per_process::v8_is_profiling); |
| 448 | env->InitializeDiagnostics(); |
| 449 | |
Anna Henningsen | c44edec | 2019-11-13 15:54:57 | [diff] [blame] | 450 | return StartExecution(env, cb); |
Anna Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 451 | } |
| 452 | |
Anna Henningsen | 7dead84 | 2019-11-19 14:42:09 | [diff] [blame] | 453 | MaybeLocal<Value> LoadEnvironment( |
| 454 | Environment* env, |
| 455 | const char* main_script_source_utf8, |
Anna Henningsen | 8aa7ef7 | 2020-04-05 21:13:31 | [diff] [blame] | 456 | std::unique_ptr<InspectorParentHandle> removeme) { |
Anna Henningsen | 7dead84 | 2019-11-19 14:42:09 | [diff] [blame] | 457 | 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(), ¶ms, &args); |
Anna Henningsen | 8aa7ef7 | 2020-04-05 21:13:31 | [diff] [blame] | 481 | }); |
Anna Henningsen | 7dead84 | 2019-11-19 14:42:09 | [diff] [blame] | 482 | } |
| 483 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 484 | Environment* GetCurrentEnvironment(Local<Context> context) { |
| 485 | return Environment::GetCurrent(context); |
| 486 | } |
| 487 | |
| 488 | MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() { |
| 489 | return per_process::v8_platform.Platform(); |
| 490 | } |
| 491 | |
Anna Henningsen | 7e0264d | 2020-02-28 05:13:59 | [diff] [blame] | 492 | MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env) { |
| 493 | return GetMultiIsolatePlatform(env->isolate_data()); |
| 494 | } |
| 495 | |
| 496 | MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) { |
| 497 | return env->platform(); |
| 498 | } |
| 499 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 500 | MultiIsolatePlatform* CreatePlatform( |
| 501 | int thread_pool_size, |
| 502 | node::tracing::TracingController* tracing_controller) { |
Anna Henningsen | 887b6a1 | 2020-02-28 05:43:02 | [diff] [blame] | 503 | return CreatePlatform( |
| 504 | thread_pool_size, |
| 505 | static_cast<v8::TracingController*>(tracing_controller)); |
| 506 | } |
| 507 | |
| 508 | MultiIsolatePlatform* CreatePlatform( |
| 509 | int thread_pool_size, |
| 510 | v8::TracingController* tracing_controller) { |
Anna Henningsen | 821e21d | 2020-02-28 01:11:35 | [diff] [blame] | 511 | return MultiIsolatePlatform::Create(thread_pool_size, tracing_controller) |
| 512 | .release(); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 513 | } |
| 514 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 515 | void FreePlatform(MultiIsolatePlatform* platform) { |
| 516 | delete platform; |
| 517 | } |
| 518 | |
Anna Henningsen | 821e21d | 2020-02-28 01:11:35 | [diff] [blame] | 519 | std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create( |
| 520 | int thread_pool_size, |
Anna Henningsen | 887b6a1 | 2020-02-28 05:43:02 | [diff] [blame] | 521 | v8::TracingController* tracing_controller) { |
Anna Henningsen | 821e21d | 2020-02-28 01:11:35 | [diff] [blame] | 522 | return std::make_unique<NodePlatform>(thread_pool_size, tracing_controller); |
| 523 | } |
| 524 | |
Anna Henningsen | b0de48e | 2019-03-07 14:45:31 | [diff] [blame] | 525 | MaybeLocal<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 Cheung | e6c2277 | 2020-02-11 14:49:24 | [diff] [blame] | 540 | if (context->Global()->SetPrivate(context, key, exports).IsNothing() || |
| 541 | !InitializePrimordials(context)) |
Anna Henningsen | b0de48e | 2019-03-07 14:45:31 | [diff] [blame] | 542 | return MaybeLocal<Object>(); |
| 543 | return handle_scope.Escape(exports); |
| 544 | } |
| 545 | |
Shelley Vohr | b086e38 | 2019-10-22 18:11:25 | [diff] [blame] | 546 | // Any initialization logic should be performed in |
| 547 | // InitializeContext, because embedders don't necessarily |
| 548 | // call NewContext and so they will experience breakages. |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 549 | Local<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 Attard | 33ae95c | 2019-07-04 22:57:09 | [diff] [blame] | 553 | |
| 554 | if (!InitializeContext(context)) { |
| 555 | return Local<Context>(); |
| 556 | } |
Gus Caplan | 1ec4154 | 2019-09-16 21:05:20 | [diff] [blame] | 557 | |
Samuel Attard | 33ae95c | 2019-07-04 22:57:09 | [diff] [blame] | 558 | return context; |
| 559 | } |
| 560 | |
Gus Caplan | 7a742ec | 2020-03-15 00:54:15 | [diff] [blame] | 561 | void ProtoThrower(const FunctionCallbackInfo<Value>& info) { |
| 562 | THROW_ERR_PROTO_ACCESS(info.GetIsolate()); |
| 563 | } |
| 564 | |
Gus Caplan | 1ec4154 | 2019-09-16 21:05:20 | [diff] [blame] | 565 | // This runs at runtime, regardless of whether the context |
| 566 | // is created from a snapshot. |
| 567 | void 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 Caplan | 7a742ec | 2020-03-15 00:54:15 | [diff] [blame] | 593 | |
| 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 Caplan | 1ec4154 | 2019-09-16 21:05:20 | [diff] [blame] | 619 | } |
| 620 | |
Shelley Vohr | b086e38 | 2019-10-22 18:11:25 | [diff] [blame] | 621 | bool InitializeContextForSnapshot(Local<Context> context) { |
Samuel Attard | 33ae95c | 2019-07-04 22:57:09 | [diff] [blame] | 622 | Isolate* isolate = context->GetIsolate(); |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 623 | HandleScope handle_scope(isolate); |
| 624 | |
| 625 | context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration, |
| 626 | True(isolate)); |
Joyee Cheung | e6c2277 | 2020-02-11 14:49:24 | [diff] [blame] | 627 | return InitializePrimordials(context); |
| 628 | } |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 629 | |
Joyee Cheung | e6c2277 | 2020-02-11 14:49:24 | [diff] [blame] | 630 | bool 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 Henningsen | b0de48e | 2019-03-07 14:45:31 | [diff] [blame] | 635 | |
Joyee Cheung | e6c2277 | 2020-02-11 14:49:24 | [diff] [blame] | 636 | 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 Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 640 | |
Joyee Cheung | e6c2277 | 2020-02-11 14:49:24 | [diff] [blame] | 641 | // 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, ¶meters, nullptr); |
| 661 | if (maybe_fn.IsEmpty()) { |
Samuel Attard | 33ae95c | 2019-07-04 22:57:09 | [diff] [blame] | 662 | return false; |
Joyee Cheung | 3da36d0 | 2019-04-10 08:31:52 | [diff] [blame] | 663 | } |
Joyee Cheung | e6c2277 | 2020-02-11 14:49:24 | [diff] [blame] | 664 | 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 Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 671 | } |
| 672 | } |
| 673 | |
Samuel Attard | 33ae95c | 2019-07-04 22:57:09 | [diff] [blame] | 674 | return true; |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 675 | } |
| 676 | |
Shelley Vohr | b086e38 | 2019-10-22 18:11:25 | [diff] [blame] | 677 | bool InitializeContext(Local<Context> context) { |
| 678 | if (!InitializeContextForSnapshot(context)) { |
| 679 | return false; |
| 680 | } |
| 681 | |
| 682 | InitializeContextRuntime(context); |
| 683 | return true; |
| 684 | } |
| 685 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 686 | uv_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 Henningsen | e460e14 | 2019-11-05 21:50:24 | [diff] [blame] | 695 | void 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 | |
| 705 | void 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 Henningsen | a9fb51f | 2019-11-11 14:24:13 | [diff] [blame] | 723 | static std::atomic<uint64_t> next_thread_id{0}; |
| 724 | |
| 725 | ThreadId AllocateEnvironmentThreadId() { |
| 726 | return ThreadId { next_thread_id++ }; |
| 727 | } |
| 728 | |
Anna Henningsen | d812f16 | 2020-03-28 01:46:41 | [diff] [blame] | 729 | void DefaultProcessExitHandler(Environment* env, int exit_code) { |
Anna Henningsen | f621536 | 2020-04-02 21:40:25 | [diff] [blame] | 730 | env->set_can_call_into_js(false); |
| 731 | env->stop_sub_worker_contexts(); |
Anna Henningsen | d812f16 | 2020-03-28 01:46:41 | [diff] [blame] | 732 | DisposePlatform(); |
| 733 | exit(exit_code); |
| 734 | } |
| 735 | |
| 736 | |
| 737 | void SetProcessExitHandler(Environment* env, |
| 738 | std::function<void(Environment*, int)>&& handler) { |
| 739 | env->set_process_exit_handler(std::move(handler)); |
| 740 | } |
| 741 | |
Joyee Cheung | ca9e24e | 2019-01-16 19:00:55 | [diff] [blame] | 742 | } // namespace node |