Skip to content
Open
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
40 changes: 40 additions & 0 deletions .github/workflows/npm_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,46 @@ jobs:
# "Existing file at -resultBundlePath".
on_retry_command: rm -rf $TEST_FOLDER/test_results_attempt1.xcresult; mv $TEST_FOLDER/test_results.xcresult $TEST_FOLDER/test_results_attempt1.xcresult 2>/dev/null; for f in $TEST_FOLDER/test_results*; do [ "$f" = "$TEST_FOLDER/test_results_attempt1.xcresult" ] || rm -rf "$f"; done; xcrun simctl shutdown all
new_command_on_retry: xcodebuild -project v8ios.xcodeproj -scheme TestRunner -resultBundlePath $TEST_FOLDER/test_results -destination platform\=iOS\ Simulator,OS\=latest,name\=iPhone\ 16\ Pro build test
# When the runtime suite fails it is almost always because the in-app
# Jasmine run died before POSTing results (crash or hang). The xcresult is
# black-box and captures nothing from inside the app, so collect the two
# things that actually explain it: the native crash report (.ips) and the
# simulator's unified log (the app's console.log / last spec before a stall).
# The watchdog in TestRunnerTests.swift prints which artifact to look at.
- name: Collect crash reports & simulator log (on failure)
if: ${{ failure() }}
run: |
DIAG="$TEST_FOLDER/diagnostics"
mkdir -p "$DIAG"
# Simulator app crashes land in the host's DiagnosticReports.
cp -R ~/Library/Logs/DiagnosticReports/. "$DIAG/DiagnosticReports/" 2>/dev/null || true
cp -R ~/Library/Logs/CoreSimulator/. "$DIAG/CoreSimulator/" 2>/dev/null || true
# Unified log = the app's console output (so the last spec before a hang
# is visible even when nothing was POSTed). `log collect` needs a booted
# device; don't rely on the `booted` alias (the prior collect failed
# because the sim wasn't booted at that moment). Resolve a concrete UDID
# — prefer one already booted from the test run, else the test device,
# booting it so the persisted log store can be collected.
UDID="$(xcrun simctl list devices booted | grep -oE '[0-9A-Fa-f-]{36}' | head -1)"
if [ -z "$UDID" ]; then
UDID="$(xcrun simctl list devices 'iPhone 16 Pro' | grep -oE '[0-9A-Fa-f-]{36}' | head -1)"
[ -n "$UDID" ] && xcrun simctl boot "$UDID" 2>/dev/null || true
[ -n "$UDID" ] && xcrun simctl bootstatus "$UDID" 2>/dev/null || true
fi
if [ -n "$UDID" ]; then
echo "Collecting unified log from simulator $UDID"
xcrun simctl spawn "$UDID" log collect --output "$DIAG/simulator.logarchive" 2>/dev/null || true
else
echo "No simulator UDID resolved; skipping logarchive collection."
fi
echo "Collected diagnostics:"; ls -laR "$DIAG" 2>/dev/null || true
- name: Upload test diagnostics (on failure)
if: ${{ failure() }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: test-diagnostics
path: ${{ env.TEST_FOLDER }}/diagnostics
if-no-files-found: ignore
- name: Validate Test Results
run: |
xcparse attachments $TEST_FOLDER/test_results.xcresult $TEST_FOLDER/test-out
Expand Down
18 changes: 18 additions & 0 deletions NativeScript/NativeScript.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "inspector/JsV8InspectorClient.h"
#include "runtime/Console.h"
#include "runtime/Helpers.h"
#include "runtime/ModuleInternalCallbacks.h"
#include "runtime/Runtime.h"
#include "runtime/RuntimeConfig.h"
#include "runtime/Tasks.h"
Expand Down Expand Up @@ -43,6 +44,23 @@ - (void)runMainApplication {

CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
tns::Tasks::Drain();

// Async-pipeline boot handoff. For UI apps Tasks::Drain() invokes
// UIApplicationMain and never returns — the app's main runloop services
// any in-flight async module loads. When Drain returns (the entry never
// called UIApplicationMain — e.g. a top-level-await entry still loading
// its graph), pump a manual runloop until the pending module work
// settles, Node-like. A load completion may itself register the
// UIApplicationMain task, so drain after each slice; if that drain calls
// UIApplicationMain, it takes over from here and never returns.
if (tns::HasPendingAsyncModuleGraphWork()) {
const CFAbsoluteTime deadline = CFAbsoluteTimeGetCurrent() + 120.0;
while (tns::HasPendingAsyncModuleGraphWork() && CFAbsoluteTimeGetCurrent() < deadline) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.01, true);
tns::Tasks::Drain();
}
tns::Tasks::Drain();
}
}

- (bool)liveSync {
Expand Down
15 changes: 15 additions & 0 deletions NativeScript/runtime/ConcurrentQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ std::vector<std::shared_ptr<worker::Message>> ConcurrentQueue::PopAll() {
return messages;
}

bool ConcurrentQueue::IsEmpty() {
std::unique_lock<std::mutex> mlock(this->mutex_);
return this->messagesQueue_.empty();
}

void ConcurrentQueue::Signal() {
// Mirrors Push()'s validity handling instead of SignalAndWakeUp()'s
// assert: a retry racing Terminate() must be a silent no-op.
if (this->runLoopTasksSource_ == nullptr ||
!CFRunLoopSourceIsValid(this->runLoopTasksSource_)) {
return;
}
this->SignalAndWakeUp();
}

void ConcurrentQueue::SignalAndWakeUp() {
if (this->runLoopTasksSource_ != nullptr) {
tns::Assert(CFRunLoopSourceIsValid(this->runLoopTasksSource_));
Expand Down
6 changes: 6 additions & 0 deletions NativeScript/runtime/ConcurrentQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ struct ConcurrentQueue {
void Initialize(CFRunLoopRef runLoop, void (*performWork)(void*), void* info);
void Push(std::shared_ptr<worker::Message> message);
std::vector<std::shared_ptr<worker::Message>> PopAll();
bool IsEmpty();
// Re-arm the drain source without enqueueing a new message — used to
// retry delivery of already-queued messages (e.g. a worker whose entry
// script hasn't installed `onmessage` yet). Safe from any thread; a
// no-op once terminated.
void Signal();
void Terminate();
private:
std::queue<std::shared_ptr<worker::Message>> messagesQueue_;
Expand Down
6 changes: 6 additions & 0 deletions NativeScript/runtime/DataWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,9 @@ class WorkerWrapper : public BaseDataWrapper {
const std::string& stackTrace,
int lineNumber, bool async = true);
void PostMessage(std::shared_ptr<worker::Message> message);
// Re-arm the message drain without enqueueing — used by the deferred-drain
// retry when the worker's entry script hasn't installed `onmessage` yet.
void SignalMessageDrain();
void Close();
void Terminate();

Expand All @@ -576,6 +579,9 @@ class WorkerWrapper : public BaseDataWrapper {
std::atomic<bool> isTerminating_;
std::atomic<bool> isDisposed_;
std::atomic<bool> isWeak_;
// True while a deferred drain retry is in flight (see DrainPendingTasks) —
// prevents stacking one retry per drain attempt.
std::atomic<bool> drainRetryPending_;
std::function<void(v8::Isolate*, v8::Local<v8::Object> thiz,
std::shared_ptr<worker::Message>)>
onMessage_;
Expand Down
28 changes: 0 additions & 28 deletions NativeScript/runtime/DevFlags.h

This file was deleted.

97 changes: 0 additions & 97 deletions NativeScript/runtime/DevFlags.mm

This file was deleted.

61 changes: 0 additions & 61 deletions NativeScript/runtime/HMRSupport.h

This file was deleted.

Loading
Loading