Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -885,10 +885,10 @@ index f85d1129..43c9a8be 100644
}
diff --git a/test/js/node/process/arraybuffer-accounting.fixture.mjs b/test/js/node/process/arraybuffer-accounting.fixture.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..d2bce713c2bd0a7bc66262eb327e1a6cf52676b4
index 0000000000000000000000000000000000000000..8611deb06e3f23ad5605ac7693efcfb6c833a16d
--- /dev/null
+++ b/test/js/node/process/arraybuffer-accounting.fixture.mjs
@@ -0,0 +1,361 @@
@@ -0,0 +1,366 @@
+import assert from "node:assert/strict";
+import { once } from "node:events";
+import { readFileSync } from "node:fs";
Expand Down Expand Up @@ -1081,6 +1081,11 @@ index 0000000000000000000000000000000000000000..d2bce713c2bd0a7bc66262eb327e1a6c
+ return [before, retained, isolated, released];
+}
+
+// Keep JIT compilation of the busy loop separate from this large fixture.
+function spinUntilReleased(flag) {
+ while (!Atomics.load(flag, 0)) {}
+}
+
+const kind = isMainThread ? process.argv[2] : typeof workerData === "string" ? workerData : workerData.kind;
+if (!isMainThread && ["busy", "wait", "shutdown", "startup"].includes(kind)) {
+ // Finish startup work before comparing snapshots of a fresh allocation.
Expand All @@ -1091,7 +1096,7 @@ index 0000000000000000000000000000000000000000..d2bce713c2bd0a7bc66262eb327e1a6c
+ if (kind === "wait") {
+ assert.equal(Atomics.wait(flag, 0, 0), "ok");
+ } else {
+ while (!Atomics.load(flag, 0)) {}
+ spinUntilReleased(flag);
+ }
+ parentPort.postMessage("released");
+} else if (!isMainThread && kind === "transfer") {
Expand Down
41 changes: 41 additions & 0 deletions .github/openclaw/qualify-arm64.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
: "${ENGINE_BUILD_DIR:?}" "${QUALIFICATION_DIR:?}"
case "$(uname -m)" in arm64|aarch64) ;; *) echo 'Native ARM64 host required' >&2; exit 1;; esac
mkdir -p "$QUALIFICATION_DIR"
QUALIFICATION_DIR=$(cd "$QUALIFICATION_DIR" && pwd)
jsc="$ENGINE_BUILD_DIR/bin/jsc"
"$ENGINE_BUILD_DIR/bin/testmasm" > "$QUALIFICATION_DIR/testmasm.log" 2>&1
"$ENGINE_BUILD_DIR/bin/testFFI" > "$QUALIFICATION_DIR/testffi.log" 2>&1
Tools/Scripts/run-jsc-stress-tests JSTests/stress --jsc "$jsc" --child-processes "${ENGINE_TEST_JOBS:-4}" \
--filter 'promise|microtask|dynamic-import|bun-async-context|module-loader|top-level-await|async-module|module-namespace|intl-segmenter|callsite-syntax-positions|stack-position-regressions|error-stack' \
--output-dir "$QUALIFICATION_DIR/jsc-stress" --no-retry > "$QUALIFICATION_DIR/jsc-stress.log" 2>&1
python3 .github/openclaw/verify-jsc-results.py "$QUALIFICATION_DIR/jsc-stress" --require module-namespace-esmodule-marker.js --require callsite-syntax-positions.js --require stack-position-regressions.js
Tools/Scripts/run-jsc-stress-tests JSTests/modules.yaml --jsc "$jsc" --child-processes "${ENGINE_TEST_JOBS:-4}" \
--output-dir "$QUALIFICATION_DIR/jsc-modules" --no-retry > "$QUALIFICATION_DIR/jsc-modules.log" 2>&1
# Accounting requires generational GC; run its established explicit modes below.
for fixture in array-buffer-accounting heap-allocation-sampling; do
for tier in interpreter baseline dfg ftl concurrent; do
args=(--useGenerationalGC=true --forceMiniVMMode=false --useDollarVM=true)
case "$tier" in
interpreter) args+=(--useJIT=false);;
baseline) args+=(--useDFGJIT=false --useFTLJIT=false);;
dfg) args+=(--useFTLJIT=false --useConcurrentJIT=false --thresholdForJITAfterWarmUp=10 --thresholdForOptimizeAfterWarmUp=20);;
ftl) args+=(--useConcurrentJIT=false --thresholdForJITAfterWarmUp=10 --thresholdForOptimizeAfterWarmUp=20 --thresholdForFTLOptimizeAfterWarmUp=20);;
concurrent) args+=(--gcAtEnd=true --useConcurrentGC=true);;
esac
"$jsc" "${args[@]}" "JSTests/stress/$fixture.js" > "$QUALIFICATION_DIR/$fixture-$tier.log" 2>&1
done
done
python3 - "$QUALIFICATION_DIR" "$(git rev-parse HEAD)" <<'PY'
import json, platform, sys
from pathlib import Path
out = Path(sys.argv[1])
counts = {}
for suite, minimum in [('jsc-stress', 1400), ('jsc-modules', 1600)]:
lines = (out / suite / 'results').read_text().splitlines()
assert len(lines) >= minimum and all(line.endswith(': PASS') for line in lines), suite
counts[suite] = len(lines)
assert 'testAdd64RegisterAddress()' in (out / 'testmasm.log').read_text()
(out / 'arm64-gate.json').write_text(json.dumps({'passed': True, 'source': sys.argv[2], 'machine': platform.machine(), 'system': platform.system(), 'counts': counts, 'accounting_modes': 5, 'sampling_modes': 5, 'testmasm': True, 'testffi': True}, indent=2) + '\n')
PY
64 changes: 64 additions & 0 deletions .github/workflows/openclaw-arm64.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: OpenClaw ARM64 regressions
on:
pull_request:
branches: [openclaw/main, openclaw/release-5718a6ec]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: openclaw-arm64-${{ github.ref }}
cancel-in-progress: true
jobs:
linux-arm64:
if: github.repository == 'openclaw/WebKit'
runs-on: ubuntu-24.04-arm
timeout-minutes: 150
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
sparse-checkout-cone-mode: false
sparse-checkout: |
/*
!/LayoutTests/
!/JSTests/*
!/PerformanceTests/
!/Websites/
!/ManualTests/
!/WebDriverTests/
/JSTests/stress/
/JSTests/modules/
/JSTests/*.yaml
/JSTests/BUN-TEST-DIFFERENCES.md
- name: Install native build and regression tools
run: |
curl -fsSL --retry 5 https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc > /dev/null
echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble-23 main' | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends cmake ninja-build clang-23 lld-23 libicu-dev ruby ruby-highline libjson-pp-perl
- name: Build native ARM64 JSC and assembler tests
run: |
test "$(uname -m)" = aarch64
cmake -S . -B "$RUNNER_TEMP/jsc-build" -G Ninja \
-DPORT=JSCOnly -DCMAKE_BUILD_TYPE=Release -DDEVELOPER_MODE=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=OFF \
-DENABLE_STATIC_JSC=ON -DUSE_BUN_JSC_ADDITIONS=ON -DUSE_BUN_EVENT_LOOP=ON \
-DUSE_MIMALLOC=ON -DUSE_EXTERNAL_MIMALLOC=OFF -DENABLE_FTL_JIT=ON \
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON -DALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS=ON \
-DENABLE_REMOTE_INSPECTOR=ON -DCMAKE_C_COMPILER=clang-23 -DCMAKE_CXX_COMPILER=clang++-23
cmake --build "$RUNNER_TEMP/jsc-build" --target jsc testmasm testFFI -j4
- name: Qualify assembler and all JIT tiers
env:
ENGINE_BUILD_DIR: ${{ runner.temp }}/jsc-build
QUALIFICATION_DIR: ${{ runner.temp }}/arm64-proof
run: bash .github/openclaw/qualify-arm64.sh
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
if: always()
with:
name: linux-arm64-proof
path: |
${{ runner.temp }}/arm64-proof/*.json
${{ runner.temp }}/arm64-proof/*.log
${{ runner.temp }}/arm64-proof/jsc-*/results
if-no-files-found: warn
retention-days: 7
38 changes: 19 additions & 19 deletions JSTests/stress/async-stack-trace-promise-all-basic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ requireOptions("--useAsyncStackTrace=1")

// Stack columns name syntax tokens, not call parentheses.
const source = "async-stack-trace-promise-all-basic.js";

function nop() {}
Expand Down Expand Up @@ -71,12 +71,12 @@ function shouldThrowAsync(run, errorType, message, stackFunctions) {
await run();
}, Error, "error",
[
["thrower", "65:59"],
["async run", "66:43"],
["async test", "71:25"],
["thrower", "65:50"],
["async run", "66:26"],
["async test", "71:16"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "19:20"],
["global code", "69:24"]
["shouldThrowAsync", "19:5"],
["global code", "69:8"]
],
);
drainMicrotasks();
Expand All @@ -101,12 +101,12 @@ function shouldThrowAsync(run, errorType, message, stackFunctions) {
await runner();
}, Error, "task2 error",
[
["task2", "93:20"],
["async runner", "96:46"],
["async test", "101:28"],
["task2", "93:11"],
["async runner", "96:29"],
["async test", "101:16"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "19:20"],
["global code", "99:24"]
["shouldThrowAsync", "19:5"],
["global code", "99:8"]
],
);
drainMicrotasks();
Expand Down Expand Up @@ -140,15 +140,15 @@ function shouldThrowAsync(run, errorType, message, stackFunctions) {
await runner();
}, Error, "task2 error",
[
["baz", "131:20"],
["async bar", "127:22"],
["async foo", "123:14"],
["async task2", "120:14"],
["async runner", "135:46"],
["async test", "140:28"],
["baz", "131:11"],
["async bar", "127:5"],
["async foo", "123:5"],
["async task2", "120:5"],
["async runner", "135:29"],
["async test", "140:16"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "19:20"],
["global code", "138:24"]
["shouldThrowAsync", "19:5"],
["global code", "138:8"]
],
);
drainMicrotasks();
Expand Down
34 changes: 17 additions & 17 deletions JSTests/stress/async-stack-trace-promise-allSettled-basic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ requireOptions("--useAsyncStackTrace=1")

// Stack columns name syntax tokens, not call parentheses.
const source = "async-stack-trace-promise-allSettled-basic.js";

function nop() {}
Expand Down Expand Up @@ -60,11 +60,11 @@ function unwrap(promise) {
shouldBe(results.length, 1);
shouldBe(results[0].status, "rejected");
testStack(results[0].reason, [
["thrower", "53:59"],
["async run", "55:36"],
["thrower", "53:50"],
["async run", "55:12"],
["drainMicrotasks", "[native code]"],
["unwrap", "47:18"],
["global code", "59:27"]
["unwrap", "47:3"],
["global code", "59:21"]
]);
}
}
Expand Down Expand Up @@ -98,25 +98,25 @@ function unwrap(promise) {
shouldBe(results[3].status, "rejected");
shouldBe(results[4].status, "rejected");
testStack(results[1].reason, [
["task1", "78:20"],
["async run", "89:36"],
["task1", "78:11"],
["async run", "89:12"],
["drainMicrotasks", "[native code]"],
["unwrap", "47:18"],
["global code", "93:27"]
["unwrap", "47:3"],
["global code", "93:21"]
]);
testStack(results[3].reason, [
["task2", "85:20"],
["async run", "89:36"],
["task2", "85:11"],
["async run", "89:12"],
["drainMicrotasks", "[native code]"],
["unwrap", "47:18"],
["global code", "93:27"]
["unwrap", "47:3"],
["global code", "93:21"]
]);
testStack(results[4].reason, [
["task3", "87:52"],
["async run", "89:36"],
["task3", "87:43"],
["async run", "89:12"],
["drainMicrotasks", "[native code]"],
["unwrap", "47:18"],
["global code", "93:27"]
["unwrap", "47:3"],
["global code", "93:21"]
]);
}
}
42 changes: 21 additions & 21 deletions JSTests/stress/async-stack-trace-promise-any-basic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ requireOptions("--useAsyncStackTrace=1")

// Stack columns name syntax tokens, not call parentheses.
const source = "async-stack-trace-promise-any-basic.js";

function nop() {}
Expand Down Expand Up @@ -78,12 +78,12 @@ function shouldThrowAsync(run, errorType) {
shouldBe(aggregateError.errors.length, 1);
testStack(aggregateError.errors[0],
[
["thrower", "68:59"],
["async run", "69:43"],
["async test", "74:18"],
["thrower", "68:50"],
["async run", "69:26"],
["async test", "74:9"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "56:18"],
["global code", "72:44"]
["shouldThrowAsync", "56:3"],
["global code", "72:28"]
]
);
}
Expand Down Expand Up @@ -116,32 +116,32 @@ function shouldThrowAsync(run, errorType) {
shouldBe(aggregateError.errors.length, 3);
testStack(aggregateError.errors[0],
[
["task1", "97:20"],
["async run", "107:43"],
["async test", "112:18"],
["task1", "97:11"],
["async run", "107:26"],
["async test", "112:9"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "56:18"],
["global code", "110:44"]
["shouldThrowAsync", "56:3"],
["global code", "110:28"]
]
);
testStack(aggregateError.errors[1],
[
["task2", "104:20"],
["async run", "107:43"],
["async test", "112:18"],
["task2", "104:11"],
["async run", "107:26"],
["async test", "112:9"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "56:18"],
["global code", "110:44"]
["shouldThrowAsync", "56:3"],
["global code", "110:28"]
]
);
testStack(aggregateError.errors[2],
[
["task3", "106:52"],
["async run", "107:43"],
["async test", "112:18"],
["task3", "106:43"],
["async run", "107:26"],
["async test", "112:9"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "56:18"],
["global code", "110:44"]
["shouldThrowAsync", "56:3"],
["global code", "110:28"]
]
);
}
Expand Down
22 changes: 11 additions & 11 deletions JSTests/stress/async-stack-trace-promise-race-basic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ requireOptions("--useAsyncStackTrace=1")

// Stack columns name syntax tokens, not call parentheses.
const source = "async-stack-trace-promise-race-basic.js";

function nop() {}
Expand Down Expand Up @@ -70,12 +70,12 @@ function shouldThrowAsync(run, errorType, message, stackFunctions) {
async function test() {
await run();
}, Error, 'error', [
["thrower", "65:59"],
["async run", "66:44"],
["async test", "71:18"],
["thrower", "65:50"],
["async run", "66:26"],
["async test", "71:9"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "19:20"],
["global code", "69:21"]
["shouldThrowAsync", "19:5"],
["global code", "69:5"]
]
);
drainMicrotasks();
Expand Down Expand Up @@ -104,12 +104,12 @@ function shouldThrowAsync(run, errorType, message, stackFunctions) {
async function test() {
await run();
}, Error, 'error from task1' , [
["task1", "90:20"],
["async run", "100:44"],
["async test", "105:18"],
["task1", "90:11"],
["async run", "100:26"],
["async test", "105:9"],
["drainMicrotasks", "[native code]"],
["shouldThrowAsync", "19:20"],
["global code", "103:21"]
["shouldThrowAsync", "19:5"],
["global code", "103:5"]
]
);
drainMicrotasks();
Expand Down
2 changes: 2 additions & 0 deletions OPENCLAW.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ baseline. Engine and Bun headers and libraries must be rebuilt together.

## Unreleased

- Fix ARM64 MacroAssembler register-to-memory `add64` operand order, restoring DFG typed-array allocation accounting and preserving the source register; cover the operation in testmasm and native ARM64 qualification.

- Cache source-relative stack line and column lookups on demand, including syntax-selected positions.
- Build both fork engine artifacts at the exact pull-request head before landing, with native Linux qualification and a Linux-hosted macOS arm64 compilation check.
- Keep syntax-selected stack positions separate from exception ranges for calls, constructors, property reads, and async continuations. Preserve the positions across bytecode rewriting, optimization, and cache replay.
Expand Down
Loading