Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NativeScript/runtime/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Runtime {
std::unique_ptr<ModuleInternal> moduleInternal_;
int workerId_;
CFRunLoopRef runtimeLoop_;
CFRunLoopObserverRef messageLoopObserver_ = nullptr;
double startTime;
double realtimeOrigin;
// TODO: refactor this. This is only needed because, during program
Expand Down
42 changes: 35 additions & 7 deletions NativeScript/runtime/Runtime.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
#include "DisposerPHV.h"
#include "IsolateWrapper.h"

#include <mutex>
#include <unordered_map>
#include "DevFlags.h"
#include "HMRSupport.h"
#include "ModuleBinding.hpp"
#include "ModuleInternalCallbacks.h"
#include "URLImpl.h"
#include "URLPatternImpl.h"
#include "URLSearchParamsImpl.h"
#include <mutex>
#include "HMRSupport.h"
#include "DevFlags.h"

#define STRINGIZE(x) #x
#define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
Expand Down Expand Up @@ -128,7 +128,7 @@ static void InitializeImportMetaObject(Local<Context> context, Local<Module> mod
std::atomic<int> Runtime::nextIsolateId{0};
SimpleAllocator allocator_;
NSDictionary* AppPackageJson = nil;
static std::unordered_map<std::string, id> AppConfigCache; // generic cache for app config values
static std::unordered_map<std::string, id> AppConfigCache; // generic cache for app config values
static std::mutex AppConfigCacheMutex;

// Global flag to track when JavaScript errors occur during execution
Expand Down Expand Up @@ -185,6 +185,12 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
}

Runtime::~Runtime() {
if (messageLoopObserver_) {
CFRunLoopObserverInvalidate(messageLoopObserver_);
CFRelease(messageLoopObserver_);
messageLoopObserver_ = nullptr;
}

auto currentIsolate = this->isolate_;
{
// make sure we remove the isolate from the list of active isolates first
Expand Down Expand Up @@ -299,8 +305,8 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
DefineDrainMicrotaskMethod(isolate, globalTemplate);
// queueMicrotask(callback) per spec
{
Local<FunctionTemplate> qmtTemplate = FunctionTemplate::New(
isolate, [](const FunctionCallbackInfo<Value>& info) {
Local<FunctionTemplate> qmtTemplate =
FunctionTemplate::New(isolate, [](const FunctionCallbackInfo<Value>& info) {
auto* isolate = info.GetIsolate();
if (info.Length() < 1 || !info[0]->IsFunction()) {
isolate->ThrowException(Exception::TypeError(
Expand Down Expand Up @@ -425,6 +431,27 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
cache->SetContext(context);

this->isolate_ = isolate;

// Pump V8's foreground task queue on each CFRunLoop iteration.
// FinalizationRegistry cleanup callbacks are posted as foreground tasks by V8
// during GC — without this, they never execute.
CFRunLoopObserverContext obsCtx = {0, this, nullptr, nullptr, nullptr};
messageLoopObserver_ = CFRunLoopObserverCreate(
kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0,
[](CFRunLoopObserverRef observer, CFRunLoopActivity activity, void* info) {
auto* runtime = static_cast<Runtime*>(info);
auto* isolate = runtime->GetIsolate();
if (!IsAlive(isolate)) {
return;
}
v8::Locker locker(isolate);
while (v8::platform::PumpMessageLoop(platform_.get(), isolate,
v8::platform::MessageLoopBehavior::kDoNotWait)) {
continue;
}
},
&obsCtx);
CFRunLoopAddObserver(runtimeLoop_, messageLoopObserver_, kCFRunLoopCommonModes);
}

void Runtime::RunMainScript() {
Expand Down Expand Up @@ -486,7 +513,8 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
result = AppPackageJson[nsKey];
}

// Store in cache (can cache nil as NSNull to differentiate presence if desired; for now, cache as-is)
// Store in cache (can cache nil as NSNull to differentiate presence if desired; for now, cache
// as-is)
{
std::lock_guard<std::mutex> lock(AppConfigCacheMutex);
AppConfigCache[key] = result;
Expand Down
Loading