|
22 | 22 | #include "DisposerPHV.h" |
23 | 23 | #include "IsolateWrapper.h" |
24 | 24 |
|
| 25 | +#include <mutex> |
25 | 26 | #include <unordered_map> |
| 27 | +#include "DevFlags.h" |
| 28 | +#include "HMRSupport.h" |
26 | 29 | #include "ModuleBinding.hpp" |
27 | 30 | #include "ModuleInternalCallbacks.h" |
28 | 31 | #include "URLImpl.h" |
29 | 32 | #include "URLPatternImpl.h" |
30 | 33 | #include "URLSearchParamsImpl.h" |
31 | | -#include <mutex> |
32 | | -#include "HMRSupport.h" |
33 | | -#include "DevFlags.h" |
34 | 34 |
|
35 | 35 | #define STRINGIZE(x) #x |
36 | 36 | #define STRINGIZE_VALUE_OF(x) STRINGIZE(x) |
@@ -128,7 +128,7 @@ static void InitializeImportMetaObject(Local<Context> context, Local<Module> mod |
128 | 128 | std::atomic<int> Runtime::nextIsolateId{0}; |
129 | 129 | SimpleAllocator allocator_; |
130 | 130 | NSDictionary* AppPackageJson = nil; |
131 | | -static std::unordered_map<std::string, id> AppConfigCache; // generic cache for app config values |
| 131 | +static std::unordered_map<std::string, id> AppConfigCache; // generic cache for app config values |
132 | 132 | static std::mutex AppConfigCacheMutex; |
133 | 133 |
|
134 | 134 | // Global flag to track when JavaScript errors occur during execution |
@@ -185,6 +185,12 @@ void DisposeIsolateWhenPossible(Isolate* isolate) { |
185 | 185 | } |
186 | 186 |
|
187 | 187 | Runtime::~Runtime() { |
| 188 | + if (messageLoopObserver_) { |
| 189 | + CFRunLoopObserverInvalidate(messageLoopObserver_); |
| 190 | + CFRelease(messageLoopObserver_); |
| 191 | + messageLoopObserver_ = nullptr; |
| 192 | + } |
| 193 | + |
188 | 194 | auto currentIsolate = this->isolate_; |
189 | 195 | { |
190 | 196 | // make sure we remove the isolate from the list of active isolates first |
@@ -299,8 +305,8 @@ void DisposeIsolateWhenPossible(Isolate* isolate) { |
299 | 305 | DefineDrainMicrotaskMethod(isolate, globalTemplate); |
300 | 306 | // queueMicrotask(callback) per spec |
301 | 307 | { |
302 | | - Local<FunctionTemplate> qmtTemplate = FunctionTemplate::New( |
303 | | - isolate, [](const FunctionCallbackInfo<Value>& info) { |
| 308 | + Local<FunctionTemplate> qmtTemplate = |
| 309 | + FunctionTemplate::New(isolate, [](const FunctionCallbackInfo<Value>& info) { |
304 | 310 | auto* isolate = info.GetIsolate(); |
305 | 311 | if (info.Length() < 1 || !info[0]->IsFunction()) { |
306 | 312 | isolate->ThrowException(Exception::TypeError( |
@@ -425,6 +431,27 @@ void DisposeIsolateWhenPossible(Isolate* isolate) { |
425 | 431 | cache->SetContext(context); |
426 | 432 |
|
427 | 433 | this->isolate_ = isolate; |
| 434 | + |
| 435 | + // Pump V8's foreground task queue on each CFRunLoop iteration. |
| 436 | + // FinalizationRegistry cleanup callbacks are posted as foreground tasks by V8 |
| 437 | + // during GC — without this, they never execute. |
| 438 | + CFRunLoopObserverContext obsCtx = {0, this, nullptr, nullptr, nullptr}; |
| 439 | + messageLoopObserver_ = CFRunLoopObserverCreate( |
| 440 | + kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, |
| 441 | + [](CFRunLoopObserverRef observer, CFRunLoopActivity activity, void* info) { |
| 442 | + auto* runtime = static_cast<Runtime*>(info); |
| 443 | + auto* isolate = runtime->GetIsolate(); |
| 444 | + if (!IsAlive(isolate)) { |
| 445 | + return; |
| 446 | + } |
| 447 | + v8::Locker locker(isolate); |
| 448 | + while (v8::platform::PumpMessageLoop(platform_.get(), isolate, |
| 449 | + v8::platform::MessageLoopBehavior::kDoNotWait)) { |
| 450 | + continue; |
| 451 | + } |
| 452 | + }, |
| 453 | + &obsCtx); |
| 454 | + CFRunLoopAddObserver(runtimeLoop_, messageLoopObserver_, kCFRunLoopCommonModes); |
428 | 455 | } |
429 | 456 |
|
430 | 457 | void Runtime::RunMainScript() { |
@@ -486,7 +513,8 @@ void DisposeIsolateWhenPossible(Isolate* isolate) { |
486 | 513 | result = AppPackageJson[nsKey]; |
487 | 514 | } |
488 | 515 |
|
489 | | - // Store in cache (can cache nil as NSNull to differentiate presence if desired; for now, cache as-is) |
| 516 | + // Store in cache (can cache nil as NSNull to differentiate presence if desired; for now, cache |
| 517 | + // as-is) |
490 | 518 | { |
491 | 519 | std::lock_guard<std::mutex> lock(AppConfigCacheMutex); |
492 | 520 | AppConfigCache[key] = result; |
|
0 commit comments