From ee14c083a84cfe37a694d7b32c2866b927a15dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 08:51:27 +0200 Subject: [PATCH 1/8] perf(runtime): group catch-frame savepoints and inline capture --- benchmarks/catch_frames/README.md | 140 ++++++++++ benchmarks/catch_frames/count_frames.py | 32 +++ .../evidence/additional-baseline-checks.json | 20 ++ .../evidence/api-docs-comparison.json | 12 + .../evidence/baseline-gc-artifact.json.gz | Bin 0 -> 12062 bytes .../evidence/baseline-gc-ratchet.json.gz | Bin 0 -> 6787 bytes .../evidence/baseline-public-freshness.log | 1 + .../evidence/baseline-rechecks.json.gz | Bin 0 -> 876 bytes .../evidence/baseline/catch.folded.gz | Bin 0 -> 646 bytes .../catch_frames/evidence/baseline/catch.stat | 3 + .../evidence/baseline/exec1.expected | 1 + .../evidence/baseline/exec1.folded.gz | Bin 0 -> 11656 bytes .../catch_frames/evidence/baseline/exec1.stat | 3 + .../evidence/baseline/hoist.expected | 1 + .../evidence/baseline/hoist.folded.gz | Bin 0 -> 9285 bytes .../evidence/baseline/hoist.frames | 3 + .../catch_frames/evidence/baseline/hoist.stat | 3 + .../evidence/baseline/json.expected | 1 + .../evidence/baseline/json.folded.gz | Bin 0 -> 7854 bytes .../evidence/baseline/json.frames | 3 + .../catch_frames/evidence/baseline/json.stat | 3 + .../evidence/baseline/plain.folded.gz | Bin 0 -> 218 bytes .../catch_frames/evidence/baseline/plain.stat | 3 + .../evidence/baseline/promises.expected | 1 + .../evidence/baseline/promises.folded.gz | Bin 0 -> 2380 bytes .../evidence/baseline/promises.frames | 3 + .../evidence/baseline/promises.stat | 3 + .../evidence/baseline/unwind.folded.gz | Bin 0 -> 478 bytes .../evidence/baseline/unwind.stat | 3 + .../evidence/candidate-artifacts.json | 5 + .../evidence/candidate/catch.folded.gz | Bin 0 -> 511 bytes .../evidence/candidate/catch.profile.out | 1 + .../evidence/candidate/catch.stat | 3 + .../evidence/candidate/catch.stat.out | 3 + .../evidence/candidate/exec1.expected | 1 + .../evidence/candidate/exec1.folded.gz | Bin 0 -> 11012 bytes .../catch_frames/evidence/candidate/exec1.out | 1 + .../evidence/candidate/exec1.profile.out | 1 + .../evidence/candidate/exec1.stat | 3 + .../evidence/candidate/exec1.stat.out | 3 + .../evidence/candidate/hoist.expected | 1 + .../evidence/candidate/hoist.folded.gz | Bin 0 -> 9539 bytes .../catch_frames/evidence/candidate/hoist.out | 1 + .../evidence/candidate/hoist.profile.out | 1 + .../evidence/candidate/hoist.stat | 3 + .../evidence/candidate/hoist.stat.out | 3 + .../evidence/candidate/json.expected | 1 + .../evidence/candidate/json.folded.gz | Bin 0 -> 7397 bytes .../catch_frames/evidence/candidate/json.out | 1 + .../evidence/candidate/json.profile.out | 1 + .../catch_frames/evidence/candidate/json.stat | 3 + .../evidence/candidate/json.stat.out | 3 + .../evidence/candidate/plain.folded.gz | Bin 0 -> 244 bytes .../evidence/candidate/plain.profile.out | 1 + .../evidence/candidate/plain.stat | 3 + .../evidence/candidate/plain.stat.out | 3 + .../evidence/candidate/promises.expected | 1 + .../evidence/candidate/promises.folded.gz | Bin 0 -> 2110 bytes .../evidence/candidate/promises.out | 1 + .../evidence/candidate/promises.profile.out | 1 + .../evidence/candidate/promises.stat | 3 + .../evidence/candidate/promises.stat.out | 3 + .../evidence/candidate/results.json | 51 ++++ .../evidence/candidate/unwind.folded.gz | Bin 0 -> 369 bytes .../evidence/candidate/unwind.profile.out | 1 + .../evidence/candidate/unwind.stat | 3 + .../evidence/candidate/unwind.stat.out | 3 + .../evidence/clippy-comparison.json | 5 + .../evidence/constructor-identity.md | 56 ++++ .../constructor-identity/parent-identity.gdb | 21 ++ .../parent-identity.gdb.log | 67 +++++ .../evidence/constructor-identity/parent.gdb | 16 ++ .../constructor-identity/parent.gdb.log | 17 ++ .../constructor-identity/rechecks.json.gz | Bin 0 -> 511 bytes .../catch_frames/evidence/fault-results.json | 80 ++++++ .../catch_frames/evidence/fault-witnesses.txt | 132 +++++++++ .../catch_frames/evidence/fix-full-lint.log | 104 ++++++++ benchmarks/catch_frames/evidence/gap.json.gz | Bin 0 -> 9807 bytes .../catch_frames/evidence/gc-comparison.json | 11 + .../catch_frames/evidence/gc-stress.json.gz | Bin 0 -> 15105 bytes .../evidence/guard-gc-artifacts.json | 7 + .../evidence/guard-gc-ratchet-check.log | 193 ++++++++++++++ .../evidence/guard-gc-ratchet.json.gz | Bin 0 -> 7034 bytes .../evidence/guard-gc-stress-summary.txt | 16 ++ .../evidence/guard-gc-stress.json.gz | Bin 0 -> 7263 bytes .../evidence/host-warnings-comparison.json | 20 ++ .../catch_frames/evidence/instructions.json | 167 ++++++++++++ .../evidence/integration-allowlist-diff.json | 16 ++ .../evidence/integration-checks.json | 77 ++++++ .../evidence/integration-coverage.json | 26 ++ .../evidence/integration-gap-snapshot.log | 9 + .../evidence/integration-known-failures.log | 9 + .../evidence/integration-matrix-trend.md | 130 +++++++++ .../evidence/integration-threshold.md | 133 +++++++++ ...egration-unlisted-baseline-comparison.json | 42 +++ .../catch_frames/evidence/local-checks.json | 18 ++ .../evidence/mac-gc-baseline-pinned-check.log | 235 ++++++++++++++++ .../evidence/mac-gc-baseline.json.gz | Bin 0 -> 5958 bytes .../evidence/mac-gc-guard-pinned-check.log | 235 ++++++++++++++++ .../evidence/mac-gc-guard.json.gz | Bin 0 -> 6067 bytes .../evidence/mac-gc-harness-tests.log | 23 ++ .../evidence/mac-gc-structural.log | 1 + .../evidence/matrix-trend.json.gz | Bin 0 -> 2746 bytes .../catch_frames/evidence/parity.json.gz | Bin 0 -> 19671 bytes .../evidence/pinned-gc-comparison.json | 24 ++ .../evidence/pre-edit/promises.expected | 1 + .../evidence/pre-edit/promises.folded.gz | Bin 0 -> 36311 bytes .../evidence/pre-edit/promises.frames | 3 + .../pre-edit/promises.no-inline.folded.gz | Bin 0 -> 3055 bytes .../evidence/pre-edit/promises.stat | 3 + .../evidence/pre-marker-gc-artifacts.json | 7 + .../evidence/socket-isolated-output.txt | 4 + .../evidence/socket-isolated-recheck.json | 23 ++ .../catch_frames/evidence/socket-recheck.md | 20 ++ .../catch_frames/evidence/source-files.json | 22 ++ .../catch_frames/evidence/threshold.json.gz | Bin 0 -> 2077 bytes .../catch_frames/evidence/validation.md | 148 ++++++++++ benchmarks/catch_frames/exec1.ts | 1 + benchmarks/catch_frames/fault_restore.py | 66 +++++ benchmarks/catch_frames/hoist.ts | 1 + benchmarks/catch_frames/json.ts | 10 + benchmarks/catch_frames/measure.py | 83 ++++++ benchmarks/catch_frames/promises.ts | 9 + changelog.d/catch-frames.md | 5 + crates/perry-runtime/examples/catch_frames.rs | 26 ++ crates/perry-runtime/src/dyn_eval/mod.rs | 2 + crates/perry-runtime/src/exception.rs | 252 ++++-------------- .../perry-runtime/src/exception/savepoints.rs | 97 +++++++ .../src/exception/savepoints/tests.rs | 136 ++++++++++ .../src/gc/roots/runtime_handles.rs | 1 + .../src/gc/roots/shadow_stack.rs | 3 +- .../perry-runtime/src/gc/roots/temp_roots.rs | 1 + crates/perry-runtime/src/lib.rs | 6 + crates/perry-runtime/src/map.rs | 6 + .../src/object/call_method_depth.rs | 6 + .../perry-runtime/src/object/field_get_set.rs | 4 +- .../src/object/field_get_set/ic_miss.rs | 1 + .../ic_miss/private_member_access.rs | 14 + .../src/object/global_this/fetch_globals.rs | 7 + crates/perry-runtime/src/object/mod.rs | 4 + .../src/object/prototype_chain.rs | 1 + .../perry-runtime/src/object/this_binding.rs | 2 + crates/perry-runtime/src/regex/site_test.rs | 6 + crates/perry-runtime/src/set.rs | 6 + 144 files changed, 3019 insertions(+), 210 deletions(-) create mode 100644 benchmarks/catch_frames/README.md create mode 100644 benchmarks/catch_frames/count_frames.py create mode 100644 benchmarks/catch_frames/evidence/additional-baseline-checks.json create mode 100644 benchmarks/catch_frames/evidence/api-docs-comparison.json create mode 100644 benchmarks/catch_frames/evidence/baseline-gc-artifact.json.gz create mode 100644 benchmarks/catch_frames/evidence/baseline-gc-ratchet.json.gz create mode 100644 benchmarks/catch_frames/evidence/baseline-public-freshness.log create mode 100644 benchmarks/catch_frames/evidence/baseline-rechecks.json.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/catch.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/catch.stat create mode 100644 benchmarks/catch_frames/evidence/baseline/exec1.expected create mode 100644 benchmarks/catch_frames/evidence/baseline/exec1.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/exec1.stat create mode 100644 benchmarks/catch_frames/evidence/baseline/hoist.expected create mode 100644 benchmarks/catch_frames/evidence/baseline/hoist.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/hoist.frames create mode 100644 benchmarks/catch_frames/evidence/baseline/hoist.stat create mode 100644 benchmarks/catch_frames/evidence/baseline/json.expected create mode 100644 benchmarks/catch_frames/evidence/baseline/json.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/json.frames create mode 100644 benchmarks/catch_frames/evidence/baseline/json.stat create mode 100644 benchmarks/catch_frames/evidence/baseline/plain.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/plain.stat create mode 100644 benchmarks/catch_frames/evidence/baseline/promises.expected create mode 100644 benchmarks/catch_frames/evidence/baseline/promises.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/promises.frames create mode 100644 benchmarks/catch_frames/evidence/baseline/promises.stat create mode 100644 benchmarks/catch_frames/evidence/baseline/unwind.folded.gz create mode 100644 benchmarks/catch_frames/evidence/baseline/unwind.stat create mode 100644 benchmarks/catch_frames/evidence/candidate-artifacts.json create mode 100644 benchmarks/catch_frames/evidence/candidate/catch.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/catch.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/catch.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/catch.stat.out create mode 100644 benchmarks/catch_frames/evidence/candidate/exec1.expected create mode 100644 benchmarks/catch_frames/evidence/candidate/exec1.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/exec1.out create mode 100644 benchmarks/catch_frames/evidence/candidate/exec1.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/exec1.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/exec1.stat.out create mode 100644 benchmarks/catch_frames/evidence/candidate/hoist.expected create mode 100644 benchmarks/catch_frames/evidence/candidate/hoist.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/hoist.out create mode 100644 benchmarks/catch_frames/evidence/candidate/hoist.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/hoist.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/hoist.stat.out create mode 100644 benchmarks/catch_frames/evidence/candidate/json.expected create mode 100644 benchmarks/catch_frames/evidence/candidate/json.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/json.out create mode 100644 benchmarks/catch_frames/evidence/candidate/json.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/json.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/json.stat.out create mode 100644 benchmarks/catch_frames/evidence/candidate/plain.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/plain.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/plain.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/plain.stat.out create mode 100644 benchmarks/catch_frames/evidence/candidate/promises.expected create mode 100644 benchmarks/catch_frames/evidence/candidate/promises.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/promises.out create mode 100644 benchmarks/catch_frames/evidence/candidate/promises.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/promises.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/promises.stat.out create mode 100644 benchmarks/catch_frames/evidence/candidate/results.json create mode 100644 benchmarks/catch_frames/evidence/candidate/unwind.folded.gz create mode 100644 benchmarks/catch_frames/evidence/candidate/unwind.profile.out create mode 100644 benchmarks/catch_frames/evidence/candidate/unwind.stat create mode 100644 benchmarks/catch_frames/evidence/candidate/unwind.stat.out create mode 100644 benchmarks/catch_frames/evidence/clippy-comparison.json create mode 100644 benchmarks/catch_frames/evidence/constructor-identity.md create mode 100644 benchmarks/catch_frames/evidence/constructor-identity/parent-identity.gdb create mode 100644 benchmarks/catch_frames/evidence/constructor-identity/parent-identity.gdb.log create mode 100644 benchmarks/catch_frames/evidence/constructor-identity/parent.gdb create mode 100644 benchmarks/catch_frames/evidence/constructor-identity/parent.gdb.log create mode 100644 benchmarks/catch_frames/evidence/constructor-identity/rechecks.json.gz create mode 100644 benchmarks/catch_frames/evidence/fault-results.json create mode 100644 benchmarks/catch_frames/evidence/fault-witnesses.txt create mode 100644 benchmarks/catch_frames/evidence/fix-full-lint.log create mode 100644 benchmarks/catch_frames/evidence/gap.json.gz create mode 100644 benchmarks/catch_frames/evidence/gc-comparison.json create mode 100644 benchmarks/catch_frames/evidence/gc-stress.json.gz create mode 100644 benchmarks/catch_frames/evidence/guard-gc-artifacts.json create mode 100644 benchmarks/catch_frames/evidence/guard-gc-ratchet-check.log create mode 100644 benchmarks/catch_frames/evidence/guard-gc-ratchet.json.gz create mode 100644 benchmarks/catch_frames/evidence/guard-gc-stress-summary.txt create mode 100644 benchmarks/catch_frames/evidence/guard-gc-stress.json.gz create mode 100644 benchmarks/catch_frames/evidence/host-warnings-comparison.json create mode 100644 benchmarks/catch_frames/evidence/instructions.json create mode 100644 benchmarks/catch_frames/evidence/integration-allowlist-diff.json create mode 100644 benchmarks/catch_frames/evidence/integration-checks.json create mode 100644 benchmarks/catch_frames/evidence/integration-coverage.json create mode 100644 benchmarks/catch_frames/evidence/integration-gap-snapshot.log create mode 100644 benchmarks/catch_frames/evidence/integration-known-failures.log create mode 100644 benchmarks/catch_frames/evidence/integration-matrix-trend.md create mode 100644 benchmarks/catch_frames/evidence/integration-threshold.md create mode 100644 benchmarks/catch_frames/evidence/integration-unlisted-baseline-comparison.json create mode 100644 benchmarks/catch_frames/evidence/local-checks.json create mode 100644 benchmarks/catch_frames/evidence/mac-gc-baseline-pinned-check.log create mode 100644 benchmarks/catch_frames/evidence/mac-gc-baseline.json.gz create mode 100644 benchmarks/catch_frames/evidence/mac-gc-guard-pinned-check.log create mode 100644 benchmarks/catch_frames/evidence/mac-gc-guard.json.gz create mode 100644 benchmarks/catch_frames/evidence/mac-gc-harness-tests.log create mode 100644 benchmarks/catch_frames/evidence/mac-gc-structural.log create mode 100644 benchmarks/catch_frames/evidence/matrix-trend.json.gz create mode 100644 benchmarks/catch_frames/evidence/parity.json.gz create mode 100644 benchmarks/catch_frames/evidence/pinned-gc-comparison.json create mode 100644 benchmarks/catch_frames/evidence/pre-edit/promises.expected create mode 100644 benchmarks/catch_frames/evidence/pre-edit/promises.folded.gz create mode 100644 benchmarks/catch_frames/evidence/pre-edit/promises.frames create mode 100644 benchmarks/catch_frames/evidence/pre-edit/promises.no-inline.folded.gz create mode 100644 benchmarks/catch_frames/evidence/pre-edit/promises.stat create mode 100644 benchmarks/catch_frames/evidence/pre-marker-gc-artifacts.json create mode 100644 benchmarks/catch_frames/evidence/socket-isolated-output.txt create mode 100644 benchmarks/catch_frames/evidence/socket-isolated-recheck.json create mode 100644 benchmarks/catch_frames/evidence/socket-recheck.md create mode 100644 benchmarks/catch_frames/evidence/source-files.json create mode 100644 benchmarks/catch_frames/evidence/threshold.json.gz create mode 100644 benchmarks/catch_frames/evidence/validation.md create mode 100644 benchmarks/catch_frames/exec1.ts create mode 100644 benchmarks/catch_frames/fault_restore.py create mode 100644 benchmarks/catch_frames/hoist.ts create mode 100644 benchmarks/catch_frames/json.ts create mode 100644 benchmarks/catch_frames/measure.py create mode 100644 benchmarks/catch_frames/promises.ts create mode 100644 changelog.d/catch-frames.md create mode 100644 crates/perry-runtime/examples/catch_frames.rs create mode 100644 crates/perry-runtime/src/exception/savepoints.rs create mode 100644 crates/perry-runtime/src/exception/savepoints/tests.rs diff --git a/benchmarks/catch_frames/README.md b/benchmarks/catch_frames/README.md new file mode 100644 index 0000000000..bf08755316 --- /dev/null +++ b/benchmarks/catch_frames/README.md @@ -0,0 +1,140 @@ +# Catch-frame setup + +Grouping the per-depth exception state and inlining its savepoint providers +reduces non-throwing setup by 121 instructions per runtime catch in this probe. +The existing C trampoline still owns `setjmp`. Generated user `try`/`catch` +calls `js_eh_try_push` in `perry-codegen/src/stmt/try_stmt.rs` and shares the +same snapshot capture, although its exception transport uses the system unwinder. + +## Design and correctness + +`exception::TryFrame` stores the jump buffer, handler kind and `CatchSavepoint` +in one fixed, heap-allocated slab. A depth indexes one allocation instead of +separate boxed arrays. The slab never grows, so jump-buffer addresses remain +stable. The 1,024-handler limit and try-depth accounting are unchanged. + +`exception/savepoints.rs` declares each snapshot field together with its +capture provider, restore provider and required real-throw witness. The macro +generates storage, capture, ordered restoration and the test. This removes +the independently maintained lists, including the incomplete legacy test +replay. The small capture providers inline so the optimizer can reuse hot +TLS accesses; live subsystem state stays with its current owner. This is an +incremental grouping change, without a journal or additional live TLS mirrors. + +Every existing restore remains, in its original order. Async-context cleanup +still runs first, using the unchanged handler depth. No callers lose their +catch frames. A future frame-elision optimization needs separate evidence +that its protected operation cannot throw. + +The generated tests establish nonempty state outside a trap, change it again +inside two nested traps, and throw through `js_throw` and the C trampoline. +They require both catches to recover exactly their enclosing state, and also +verify that normal completion does not replay cleanup. The shadow witness +changes both shadow frames and expression temp roots; the dyn-eval witness +changes both interpreter roots and call depth. + +`fault_restore.py` temporarily omits one registered restore at a time in the +production path. All 13 omissions fail their corresponding test at the +enclosing-state assertion; results are in `evidence/fault-results.json`. +Each mutant runs in a separate process. The expected assertion aborts across +the C callback boundary, so its exit is SIGABRT. An unrelated crash or an empty +test filter does not count as detection. The script restores and rebuilds the +original source in `finally`, then requires the exception suite to pass. + +## Instruction measurements, 2026-09-14 + +Baseline: main `eb13fa188d` (0.5.1564), which already includes the #10215 +large-array corruption fix. Host: perrymaster, AMD Ryzen 7 7700X, Linux +6.17.0-23-generic, perf 6.17.13, Rust nightly 2026-08-20 +(`1.100.0-nightly f7d782a3b`), LLVM 22. Node oracle: 26.5.1. + +Before changing runtime code, the promise/async workload pushed 100,007 frames. +Its initial instruction profile attributed 96 of 4,221 samples (2.27%) to +capture. A later independent baseline sample attributed 29 of 1,098 (2.64%). +The JSON allocation workload pushed only six frames, making it a useful +negative control. The hoisted regex test pushed 3,500,011 frames. Uprobe counts +were collected separately, with the probe removed before performance runs. + +| Workload | Baseline instructions | Candidate instructions | Change | +|---|---:|---:|---:| +| Promise/async loop, 100k | 1,098,667,245 | 1,077,465,852 | -1.93% | +| JSON parse/stringify loop, 100k | 3,182,841,469 | 3,171,165,684 | -0.37% | +| Hoisted regex `test`, 1M | 13,816,754,889 | 13,266,297,479 | -3.98% | +| Regex `exec`, 1M | 31,217,404,185 | 30,183,325,430 | -3.31% | +| Runtime catch microprobe, 1M | 472,151,423 | 351,152,420 | -25.63% | +| Generated-handler setup microprobe, 1M | 366,173,508 | 244,175,238 | -33.32% | +| Plain microprobe control, 1M | 27,068,237 | 27,068,989 | +0.00% | + +Subtracting each build's plain loop gives **445.08 → 324.08 instructions per +runtime catch (-27.19%)**, and **339.11 → 217.11 per generated-handler setup +(-35.98%)**. These include frame entry and exit; they do not measure throwing. +The Rust example has its own Cargo link graph, so its absolute per-frame cost +should not be substituted into compiled-program profiles. + +All four TypeScript outputs match Node. The regex probes are copied from +`/root/claude-regex/repro/tonly/{hoist,exec1}.ts`. No cc application claim is +made. The small JSON delta cannot be attributed to its six catch frames: +provider inlining can also change other call sites and compiler output. + +`evidence/instructions.json` records totals, sampled attribution, frame counts +and archive/compiler hashes. Raw stat outputs and gzip-compressed folded +stacks are alongside it. Symbol attribution is approximate under LTO and +sampling. The verdict uses instruction totals. All retained A/B folded stacks +use `perf script --no-inline` consistently. Raw perf data and build logs are +retained under `/root/js-throw-evidence` on perrymaster. + +Integration exposed a Thin LTO identity hazard: separately linked archives +could give `global_this_builtin_noop_thunk` different addresses, breaking +builtin constructor recognition. The final patch gives this address sentinel +one external symbol and a distinct non-inlined body. The unguarded optimized +build fails the EventTarget subclass fixture; changing only its constructor +pointer to the comparison target in GDB makes that fixture pass. The guarded +build passes that fixture and four related constructor fixtures. The final +measurements above and the full parity sweep both use a fresh, frozen build +including this guard. See `evidence/constructor-identity.md` for the witness. + +## Reproduction + +Use isolated baseline and candidate worktrees, each with its own target. +Keep the package selection and build settings identical on both sides: + +```sh +export LLVM_SYS_221_PREFIX=/usr/lib/llvm-22 +export CARGO_BUILD_JOBS=4 CARGO_INCREMENTAL=0 +export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16 +export CARGO_PROFILE_RELEASE_DEBUG=1 CARGO_PROFILE_RELEASE_STRIP=none +cargo build --release -p perry -p perry-runtime-static -p perry-stdlib-static +cargo build --release -p perry-runtime --example catch_frames +export PERRY_RUNTIME_DIR="$PWD/target/release" +python3 benchmarks/catch_frames/measure.py \ + --perry "$PWD/target/release/perry" \ + --micro "$PWD/target/release/examples/catch_frames" --output /tmp/catch-measure +python3 benchmarks/catch_frames/count_frames.py \ + /tmp/catch-measure/promises /tmp/catch-measure/promises.frames +``` + +Put pinned Node 26.5.1 on PATH. Do not override the repository's unwind-table +and x86 frame-pointer flags. Both measurements use thin LTO and the same +16-codegen-unit override; these are not claims about a separate dist build. +Copy the benchmark sources and example into the baseline worktree without +the runtime patch. Freeze the three compiler/archive outputs before building +any extra package set for other validation. + +The measurement script uses `perf stat -r 3 -e instructions:u` and a separate +`perf record -e instructions:u --call-graph dwarf` run. It retains oracle +outputs and folded stacks. Run fault injection only in a disposable worktree, +with no other builds or source copying in progress: + +```sh +python3 benchmarks/catch_frames/fault_restore.py --output /tmp/catch-faults +``` + +## Validation + +The local replay and its baseline comparisons are recorded in +`evidence/validation.md`. GC ratchet measurements use seven repetitions of +each of 14 probes. The candidate passes against a fresh Linux baseline from +the same main commit, with all 126 heap/collector medians identical. This +does not replace the repository's pinned artifact with a new baseline or +claim equivalence to its different-platform capture. GC wall/RSS observations +are retained by the harness but are not performance evidence for this change. diff --git a/benchmarks/catch_frames/count_frames.py b/benchmarks/catch_frames/count_frames.py new file mode 100644 index 0000000000..4ad2fb6fac --- /dev/null +++ b/benchmarks/catch_frames/count_frames.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +"""Count all try-frame pushes with a temporary uprobe, outside perf A/B runs.""" +import argparse +import json +import os +from pathlib import Path +import subprocess + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("binary", type=Path) + parser.add_argument("output", type=Path) + args = parser.parse_args() + symbols = subprocess.check_output(["nm", "--defined-only", str(args.binary)], text=True) + push = [line.split()[-1] for line in symbols.splitlines() if "try_push_with_kind" in line] + assert len(push) == 1, push + event = f"perry_catch_{os.getpid()}:push" + # Use the DWARF function name: an LTO-generated `.llvm.` suffix in + # the linkage name is parsed as probe syntax by perf. + subprocess.run(["perf", "probe", "-x", str(args.binary), "--add", f"{event}=try_push_with_kind"], stdout=subprocess.DEVNULL, check=True) + try: + with args.output.with_suffix(".out").open("w") as stream: + subprocess.run(["perf", "stat", "-x", ";", "-e", event, "-o", str(args.output), "--", str(args.binary)], stdout=stream, check=True) + finally: + subprocess.run(["perf", "probe", "-q", "--del", event], check=True) + count = next(int(line.split(";")[0]) for line in args.output.read_text().splitlines() if event in line) + print(json.dumps({"binary": str(args.binary), "frame_pushes": count})) + + +if __name__ == "__main__": + main() diff --git a/benchmarks/catch_frames/evidence/additional-baseline-checks.json b/benchmarks/catch_frames/evidence/additional-baseline-checks.json new file mode 100644 index 0000000000..6a09bd6334 --- /dev/null +++ b/benchmarks/catch_frames/evidence/additional-baseline-checks.json @@ -0,0 +1,20 @@ +[ + { + "test": "test_issue_4826_array_headers", + "baseline": "node_fail", + "candidate": "node_fail", + "detail": "Node oracle times out: server fixture never closes" + }, + { + "test": "test_issue_4975_http_agent_keep_alive_connection_options", + "baseline": "crash", + "candidate": "crash", + "detail": "Perry prints true and 1250, then exceeds the 10-second shutdown deadline. Existing Linux allowlist entry cites #8841, which was closed when checked on 2026-09-14." + }, + { + "test": "test_parity_stream_web", + "baseline": "crash", + "candidate": "crash", + "detail": "Both print the Web Streams constructor error and exceed the 10-second deadline. Existing module-inventory entry cites closed roadmap #793." + } +] diff --git a/benchmarks/catch_frames/evidence/api-docs-comparison.json b/benchmarks/catch_frames/evidence/api-docs-comparison.json new file mode 100644 index 0000000000..d3766b16dc --- /dev/null +++ b/benchmarks/catch_frames/evidence/api-docs-comparison.json @@ -0,0 +1,12 @@ +[ + { + "path": "docs/src/api/reference.md", + "baseline_generated_equals_candidate_generated": true, + "baseline_generated_equals_committed": false + }, + { + "path": "docs/api/perry.d.ts", + "baseline_generated_equals_candidate_generated": true, + "baseline_generated_equals_committed": false + } +] diff --git a/benchmarks/catch_frames/evidence/baseline-gc-artifact.json.gz b/benchmarks/catch_frames/evidence/baseline-gc-artifact.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..c2a1343ee565d876fc8298fd2ef1693eb9aabc84 GIT binary patch literal 12062 zcmV+(FX7N1iwFP!00002|LuMMlN+~@@9+65rj$xadT%+x_b;ouA7o|Y_!3Jl$-caM z&sV%5IozeiB{v*$S9^EP-~PIRnc)xsX<4%?G4iG=veX!2fbK@4`-4W$fB!Da9#!Lu z^0F9Sm#b>FTs%6>=n0bF%@z~*$D{M{U{$Q)ne|{)RONiOC?B~8iq(2HEynBNEPU>o z`X?64^>BSr4zD(&`D{FFe-2N7vsjm_MKRC5D_5)A!F4rof62annbp1I+4mP^=6{;K zT29JmUu_myc|Dtyi*cFFs%!**xwtG=@2Y33vf9ko)ieM2U;&R0Mw$;eE>5!L z&7z!SquZSyZ5H9s^6DbbUX{R$Y*n6@ixLJ?X3IsHO;^jy3?`E;;g41BCpcbSUe4Ay zpK?U`w4laJnwCj9T(3$uS<9)G#fZtm+No4Zl8G48awNqFs0{vM&4`Sp|7r8u$*^!; zGs4t>*Z~#a6LBiUDOLZQkW)hZ<5%-yJzcIY@llw<=KbKkQ9~ts>&3FdPW~JI{!7o+ zPcMo~H)!Bs~y zn=zD^%hm00bh|Dqct9zk4CTa7e9S%cXuVv{#}~zH(P0~^W@mwTLPm0#Q@NeTYE!Mp z(7f2p=griL)%h|Y;Un;8_T&f9(Df#xJmJs|6n2~BBxL5hNkzc+x3NiJI^W0 zc|$K3*IoX6clPGZzYkx%9=`bD``5$Q-+lkhx8MBVvz;NdPknv%YWVfbblczFeDnR; z@T(VZ-h6ZR=577V4lhTuMX{PWKDKXnjOh@NRID#>)c<()Q#Dv$td=)}W)VMYmffJS zC9r~B4=3B-SF`^@1rS_OZaG)ori+3}g`EpEE()B;FoXl1qKKgdtu)0QGYwCXTq8C>Z z-Nh{8LU5riNwY|)DIbl?$&^YBbLIsVqtQqc#tTwT%CVAD;Ekmt$;gxuOUaas1QATB zLQFW1S=0`yT2J8bcQwVfw|ItzTFE)tF7#a`7*PX;R8FT;CTTh5Oo)QgVlpm?HkOYk zMolKnOw@!+HdfOK8yPY-l$K&*Cbpg7@0vfoMZkSxyj)CY=UbDoDzD07jk>Sv<#1E1 zE;m=r_KAjMRRFtDV)z(qmhoyia%<-QHEbkwxY(?!5~e=B*sK;?B_eECZC2N_>*Z<) zzq?$nXUlFgAC6bcsv3f!9p0>FXw$ZhVh9EtOz0FgTKH>u1&l4m?>bM&;ds7;7nH+s zakYm3cG?s?y_zk~hpTd3E`s;!VX;~jx5IOg>9D*m#v9nKI_+k7S-|Vc^{@hYuZz)q zXJi&OMwlyZ^TXA0*IJ}<%hDAq8$D^Rs< zBOA`a?v}$j^nktpgX9b)5q85j1`j5{3Fo#VElz40S9>H*niQ6_? zslF-C!70HFBO4WqNtMCA>->kUhjZc_3m9Jpil2dir?YvPXJ;_&Tlb?3B(@_|{5|N? zV7(l`f3j<^zlC##*4a%_WfRzLuffehU&Xsmm#`~?U@t+0=r6(kJHbIz9ce8#mm}EO zvSL+cJc9>7v*C}$8b;>EUuEwzoz)7TJz*4wP(5u1JwpEoJKc79HCv#!_4myT=7v7S zNp>~gRGG~Dns6O-e&1n@^8;Ww&v$!Vj$nP@)T%3FwI40$$Z|CS;>^82YivojDBrKM z^)f3RC;bHTZD-rRp;p~E4*pAaS-gMpKaE}bpX`5SSL5|FO2|o8jH;)31{(pW8_M(X zY%yM;yYm?N3o}_R=G!gn5$ezS0v*%>oyb}Xo@bBC8M=ypr>)MsY-0Wbu21S=*9JHxmgwSZFf^x+2!gA z7Wg__PF;8Pa)Qo5J7JhWEEe$l3f@~LnfIMn*eWaE&#HCz-7rHi9^-6UT+Zg;A!L(f z2C+Z}rW(eySkB3j(buha2k*E$)FXOF#pEb;YU&(?q5j0UJgUT?sqthwVkJef_W zK*{zw{^iAM(r&(+4GL%C{9Xm@9)_w(VjCox_6a_yX zpJd+4bba7vT~9yH9{Ytc#F0FP;dcZAd@o=IAQ1S!i#~9LFF;Oi$kk@HZq`{=frnl% zuF>*6aswF9d1+^`_;wr{1S(g>3JtLv6_U;|#7GMEv0IhHC9Iwm*zf9bwl3a*6koqO z%bvKllUl-0vvE0}XUk2iM$jvc*-8Gk)BB6YzIhb~9^RnBKEAmq)+osJ1^iJ0V!87+`qTx6Oe6 z_WI3V{`&gGA5S_~!7aum%Jyanj4rFSGlMs!nwpY zJK4^*Q*#BzGcD#7uy5g>S+6$mcYIy_@8t&eg{rj#r_ctgYdqhem2<4_Dh&(^D7A^7 zoMisrUex$+zk?vnt#l;8M)4CwDWLTWT#%sof$9EfIRf3AG`kS22KW=A7QDfQZ4^FBgOVDpyP3#uB9McvepqHky`~&bC}^7UPSKj^c)i(J_oC zav}1I5?mTs?-L(9`mWsej#dP=*yXhc7*HWhr`O+GaLJoD`@JGddrT=cNr?x1CPETEa$%GH@IM%hqbE>l1v6XDjbNb$b0{IWO0ZWxSe$M}huL);KQX+j@tcbe^lqt;DLN)kC>i zP}}T97RuV`CH@;%@T=F~qbe2NIdg9YmEEADbCX?ey1RC;uev$mY(1}w362eIA6Qr5 zE;{OdN@!xi{4H-5+4=a%(~fEK8{gLQ7^i&>mO@t&Hwm{SK#kGQ@&j0)?*wwY?s|Rh z-vbvCz#d;Lyt()ZJZ;!a3yc-O*{e2}&ed8JwQ{}w)1Tg+egD?2u4Q+xh3CPx`|fT) zd9vCEEIV-p87k+a1;a?y=*>U^$(3ya8k~s=@&6A8asP zUkW#65Fc(QH|6}=Z?IFhEiSfzA#NpkEwaW~I7#8QbsBll?acA%0Z!gq$VN4~LTy#4 z{5#mdDnnkvS|8)yxg(<|=i^}mu3p{xU3NCTJ;9X$rXeFaA%AeD5eDxk^VCT?Tn~%o zO?MB*wdVJ6aPffUdG?=8-~WmF?e`#L#dNlUT>xCUD{p~EFm%voSah@X&ejHRfKkA! zod%;-sksIJM2=+_MddafP#)YXcdX9utzkB>xO)OWZ`RjK(B8)Ex@8CoR=zLC8@KUy zWIc83%pqU5F8uN~pE>PbqRP~93b>WUcm{69%?x9KMr|_OPcjcb?)V$X@(N_U=z5)K zDS&@7KUG*tGc@+LR zQuOw;j+{_KRwbA}JUYMt2%Z^?R)ep_)XAFj9XiU4s3_?O^SaMC)52 zXwcb|z|99$DZJYVk+~O}=cilp?jiJ->sST&x^zweY(Q&oda-X8Z#Yv0Z7||_S?iAP z;AXj*gW+GzuDp`?*LX>^6V{oCb$}w4hw)?uPf*0j;HVNXC=n>Yh1()Fwru@ zsbh6DN5=peS*|cz=V5awW#NOZ z2^a?WQ8}F=Z0DQ<3|3r!wR`5!Z|@=$yFMK{p&m4al``;Sa>Ib1?-#~iD=dHQetv(_ z$ieDM&a## z*J^uIGr{BzYV^TMeb^(rH){ZK8W;o0YFqFEJlo|}4c~<5iQ@-!HZQxVz6;&A$P_5+ z-#3U+26lN;PG^gm2hBY2yLE=^#ZX*c6`<1DYF532(Cbfb)zl7h2Lnkkd{tHZ*-caY zHryCR%tv{^9zx#3azv-Te)0X;AG1H7y*UFHDiA?!FX|1=9f`~^@)yMX;UpVv)_cxe z_8hi&5TV(@w#~IbFiLftn-{lemR+RVd8|E&dGq#djo6O-smb}px`X1ovtk$ULaf#i zoOh?ut!pOcX4Jf3jG6)BgH_!e6?S1q|3U`~WYq;mR4rI>J*#H0@}Af6*R0DmcYM~9Y4!hqjlQXVqtsC~0>I;3Y&f@+SI zo0SjxpTmE=%8n4~_PCOBMhdU(PIJqu(cQ0KW)*~#ljY3`Wjg!DRJL#THJZ+3^jqbNlc;<$(Yse?F$<|GC&*Mb=-dP{eHpbll4TR(FOp21}1&J~L$I`Ih& z?nmf8%ogFV{G*!x!9^1M59s);FoKxhX8OIyGa81~CpOTd@GZV$kJtwtBM$AJVSK<1 z1ghCKes%6}xf`T#&Em|gxo>eOF#ZPyRF4Z{K1SQ8xkH{hIbhMvlAFvbFaTG@Vhm&XOIcoZaQGH-suR62Tj6AjB%kRMDS3PEjaY%v$+XL{Joj!YZ4%T)v%0Z!@xtVMZF6J$Ky0Cc`zvdzL{MEC-I)vW_^X8bt*-> z<({{=XuJG{LzJRp@JTmA$Q_AeWSjlE4|yeR^_p7!I8RYcTM7UMI`=G?->bfM2)?Jo8&g9R$y+<=k7Sm*1c` zGtRBC(okb)_r4-b3>#pj zJ?m@$K54#aFE7+N61#Tw4VVc=-G$Be0*yN{a(eo#T5cdnsqM;X#{$Fh7~o9|O#Dt* ziMzF|j93kZ@dJ&kLJn=qM*x@Rn4aTiJ>jaL#gvTQ?u)k5&Gr%vqDyS>hV+@g<_+r| z$k*<)ac33#sLJ!`1eao+J=j_KZkg1T3|7}reU-r9Z0pDDXp zrOGP|>&g{B2iN&h8_}LKJse|!E?)OSz5k!!MvEYx_;j=m=|4{5;kM;Y^iHG4Qe3f% zuwy(s+tX0IPd9*Kl*nMROKnzsiahkF7D>hzzvL0@lLQsYkSMnMJk*|YNp)UJCf(#@ zlWe+c>7*gw17eYugU*B|Us`6U2)%4+sT6`o&r&Tcjj2GhDx?ZaI1wS0SY|EjDVEeL zYq2zMNQfmhq*g4HNkT-&6917oN}cp<02`p12FvonJKE65j5bfqEb_$ zSx6N^5F0%!l-N0;s;LGZB_UPQSn7&$!<1A#WtMtnEwkng37Msaw3QjriizBEV2Ir# zGfwsHjO)SvK%5Z%aiijn{9Gv zuL`z}59Jx#vtOh(iqsBquUo^ujFsOS9}Z-_9J0B}hISDsJsA>q+E~7b>=#i;z9-K7 zItN=RZiBtS(|YnI?znM&6Aj+^jT`QoLkAOd4sa<@oxXaLQks;;kWa&mU!^c#Br6Ua zy6m;BlqhXNC$6FPwX})O8-tr{@^&}XbSJDz9)_pu+8x3)Qa|Vb8&qj@6_^q~E)cpq z6$JkG#bX>yLO2lm=bxI`)2&Q&UF&PI#i?tm7FlYRwa8MF>WGXBo(n^W+=EXs8-jC@$jF}1`By?6n&iX? zZg~(VnVf;H>VOPS3nlq()DKTYHl64gAle4>kvjVMfZ!#LeGro2dv`(>$o?p1JfGB`i8v^2EM66L;NcPO8Q0Pom`k^>{!%juiDU+RDhis);>$lIXhTOtQuCC)IL~ zfJdTI{~@>|e!K&AF!1~+cmltHBn}xJlid@cZ%D>c+80rMAjZsb0vAjg7Mn?7)SvnraqCtHK(sYFDGT5fgc(T|4_QMvLs$%-42gQ65OtF1 zZCsJwP+!wc>S!l1nr6KuCbd2C=ZX`W8>P6}bKE z{Br}#kQ~me;rlXcekFFnMJ_1B^E?cDaw~0+?*L?(b14-IT&dZ%QCDKhTe0N?MojmuGK5PsQHS6Qqq(pT=*0tiabM_# zpu0NnDSfjMXmTONWS@x;l8*wofR!0$ka=2PWr;d&G$zsD)h2Fuz$_jxizCG>z}X@s z#4KuJPo5;Yt~rxzar{ZO+#_bO?*oE|fQvo9>7W-DPuYG0xfwD%qP#CcUk^WdDj89| zU(eNXLKntp!BwzOKM%Dpbdl)1*;JEFep^j7eg2#arId-l1gWI3aVCa>_`!tG1w3mL z_fC|?PXI+dXcC5vNHtU{+Iy8GrqV2x#K@cVQonrP4HKnR&M`@0&us-kA^c{Cu?x-A zT_#;9i2t~X?tBQ1Qw;NbHWo?K? zz|*i(gOWyMV4hMe?nE2Vk-qCJHO407O3k(f2@|8;TEN_DYM9!GT~MY7=lf-*a?pJx z#GQc`L73V%Mok5%spwQ68+h?W^5Nsa3$RDQ3PegzhJ>9qnYAjJb`g<}0=%G<^C(vy zX}vS$!;afL`M9CZl8+jW1-wuu+_6pHYdArd&CY33<~O7s2aLfq58XjW>bt1IZktsV z)BUoF=tlr;X!MS3cqrIV``Y0|=Z!f|HhHU@YPv^!Lk`FDC6+fC*53d>h-^epcQ6fZ zt<^&O7Eq0_+{Jwn`udT{>KQUwIzv9x&Bz|=X8ekrB!Nj1Q4W#hGOl{TIH57B0ncKT z7*e%XQ4NN@&r&K_?^TlMyv<#TN8Tnd#RJ_&$dW-6mK$T06?;$(4I%cyt0WdLZScE9 zH6XkbBusWu1VTm`0(n5yB*r?3W;&9uA`%gXxL+P;df=5E$#w6#8HuShzFFeEjf0jL z{`Oh|hj^allt`uY9#q5FP#Hp*X)Ue3liMUTXN(aWUc~{j6h_+cGJX!bFC+175)O+* z+34!y74hnZpWA`(nCnKYK2dgl}&Aq11#scS*363*EEEVD?;6Vh@zg z!0SJf-d#dQm_XC_&Oj=AC6%>uY?#Iu$%l`_H1M9CJc&ttBlob|)|H6pwI31Ej{(?_ z987h%uRB^#_QV~xhk9{CeXbWZ91XBRrHHCs^}TKrcG}jRk|J5cNQz@bHyBl+XX$Bu z@r|hC2H;3Ec!VQvI0A@+X=8PihTBkkgFtcTEe@1ws-d7n(>+2QYKY&bUz`uy8oUQF zj`;CzjSUJx&u`$)NnAh=%di=b`qkXp-o>wVq0tyW zs7RIH*VN;lXBJ)?`<5m#6UY~H$obk8@zwA?=pjAOdc*0$_Txa+b4?V z5)>@Ti(&W)G#Xw?0W!19hM0{>Os}ZWfOola?kkt2lIqbGMT#o5=RURsivrq<&&f9upV@Y5viHaQ| zsL?M(V*eB&(nmlU=x3_frK_pE6Mf>&+iagyQ=RgYXu3xz8TE5NSZ54OjNLjV$Be(Vlssphgm$*K;K-O@OvsY2jND=UzN?7;;>Zv zR=7zGy{#CK7-+N3n)mPdu1#*Z-2+xJlT$|0SXOg=1uLr(Zte{H2=4^-J+Mw;MJX)y z*ual3k`EvGl@v`P5SjG8f)I4tLcb)L;}(*S0Re$!9e*aJCicGE!}okBCD~G6@!?1N zsg#FQkG-`s1tsB@8f$ zd&Eb~@DgIrs$37N*`!<-qxmn?7)||PC*6ZsA(WEp$HjEEfQZ(8Rr-{ieEGLr;(O}% zMCcvVB~yyi_u7qlxaIP2%jLtfQz_>>`mPCQibN4JQU#Arl=nPKq!clgS`mM7g;NZ2 zN$(0bap&!cbUd0iCpMl`D;6z)Iatt;>pjp1MBv6A%pm|b>@I;1#f6j++^V=VjD;nv z6z5Dtg;^A5Qbfg(fhtsV16y$l^Rv<0n5)6k*R0juB(F=v?`;fRVyd0255o=1C9`_p zmtk#KQYNZ7%BV1RfqO8@b7rUxD+mdZOIR^FEa@l-&;?gItT-fcCP}zzn2xA=-$&p$`A@w9K>+7*G=fKi?xW zE~q|?br@#koq!z_VsApEl{)%HbQGoyn;Xdb@hvjOR+-U9oX^k zt(7mB4=01*zxeKmD-pR!gy4St)ce50Tg%M-U3QB)i;3>P4@?JP%^C6%T+mCmE&@DU9N_O z{|YQPT+8txxa06Icc2dg{;(xP{1%`O6@5YR)6sfEA7RHW^bt4I&_~qpP}?J>KGgQ; zs(cC5=D0r5}$NgGR3!{pjWt^H2 z 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 I2E#M~0GXYNhX4Qo literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline-gc-ratchet.json.gz b/benchmarks/catch_frames/evidence/baseline-gc-ratchet.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..fe557844e8844afe19b7f6723da81a413046681d GIT binary patch literal 6787 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline-public-freshness.log b/benchmarks/catch_frames/evidence/baseline-public-freshness.log new file mode 100644 index 0000000000..83c413f461 --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline-public-freshness.log @@ -0,0 +1 @@ +public baseline error: public artifact benchmark inputs changed; regenerate it with ./benchmarks/run_public_baseline.sh diff --git a/benchmarks/catch_frames/evidence/baseline-rechecks.json.gz b/benchmarks/catch_frames/evidence/baseline-rechecks.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..71777e09a416b582fa7590b302f6e59da4047c06 GIT binary patch literal 876 zcmV-y1C#t8iwFn+00002|6*ZtWo&6~Wi4`LV`yb#YjZAYb8l_{?V4Y2;xG)r-}w|1 z&)X^KKh}PZd%Dvp3dMtn^pBEs2b%WX&*9*JQA$eLtw?=g;JS`u|71Ju-bN1(V*}bS zp>+j}5*migz{DVJ)^hDw(8hj^F;?acC zALGZrx~1girBIpGLo3y4cR^QK#?|_tRjbRDFl$zFtx-%KKgeIWkVo>g$Vwq$cY*FN zD6SW$`gt*fQ>k8xvV_@@%oK)8rmDQoj}lZ0x#4pg67r2~F28TLWzAO#^y$7(@^dRe z*?9Z)*T>x)tGQ+7)RqmvnFWvBMNcbf^nvQz{uW__;^@NT{x)s6sjSK41Z@@GM>{Vz zJ{+14;z`IB#*_?Wn;W(Sz^_ug0!xcLht!B7XGLlMXjdHlAfeG$;7ICmq#bdjUx}j= zX;)|T286a-upZjYj+$tl^O8lrAF)&-8w^&ZV$(`UBXXog;ks^chKUy>;b+!L+7eFE zOE_JFenW=4vFPAyEqaH^yId~!3oK!+k#8x5My^{lYR?7Mf2b3V6E2 z79!{ce+v$_UAP5wwz67k~C5 z#+Bl0wg5hJepnhM9(Ki`M-SoaL8ABZ?>ztQ6<|%iYw_8~@RXs^`{)l_ysi-*CIA5H C?6Um; literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline/catch.folded.gz b/benchmarks/catch_frames/evidence/baseline/catch.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..e5cf0b2ee440a87033374309f010dbf9b9e8bc99 GIT binary patch literal 646 zcmV;10(t!(iwFP!00002|Ls_9Z`v>r{?4zkG-+xjG%XZ$n~6}nwi{KuA_3h#Ow-9Y zh6EftvK<(j`rmg+s76QHsiWO0ntVvGeR=NXIbH4m>zHvZ02vKAhJ8fDgD8vwy6;> zUSAbrc3~+UGCp;NaX~47Nv(sS7)J_hs1bMN)E}vx-8w<27H5u!FfuF_h>#gY_8NON z*lr(Ni7;k??<*I@C@j8nk+?`JN(hJJ*NBZa07WFXPma(vxD73z;buqa*y` zBPp6wIum&NEO_Qj8?X9qyPdg;lxb8&_AA0SCEQ61p+;vq-N8EB-lMX8sVp0bobX$% z(rzGa3H8lqLj84FCsp&i;fJw`;N$jgYo%q3#oK7@5ZZ<;(DN)3d`fA*b9mhS@^q@r z?S|&7ezw4y6D4)1ny)tQSBu%|AdwEE`QQ`qzauC?!vqUpEHGD`0hO$1Xb`Vjt4KP+n+AmG9`Jnp8}UrL$nzH0JHrsdH?_b literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline/catch.stat b/benchmarks/catch_frames/evidence/baseline/catch.stat new file mode 100644 index 0000000000..64e02e697d --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/catch.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:34:13 2026 + +472151423;;instructions:u;0.00%;45711787;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/exec1.expected b/benchmarks/catch_frames/evidence/baseline/exec1.expected new file mode 100644 index 0000000000..7a908ccedf --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/exec1.expected @@ -0,0 +1 @@ +5888890 diff --git a/benchmarks/catch_frames/evidence/baseline/exec1.folded.gz b/benchmarks/catch_frames/evidence/baseline/exec1.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..f36cfa49e1736f3595171450b10f08166cef5a30 GIT binary patch literal 11656 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 z zHpXq=w3pvPkwR}x-tN~lmz&g`kC6|QujO^Q&!aL(AjePvzbqDNt6I6*a2_C-B1S=* zQr~sza9i)No%po|Mgf(tO(pv7{P_-w#dCe!&6L?Q;mXR`j;#fE$ssL^dac3_QuqWV z-(?6jT#F%SFpc8r{{}BzY+IJEJR@8$T(zZoDdMtF z3Vzi)XYpYaaE^#asLL`3-h(#hy&+W2{R}_yxB^3wJe*)F#F*~6WFdj(}G^&XHaOP2D-uDKpIRa%$^(Ac+PI7 zbJVgAy;^3GNQKw8-LtK2d-eYfg=%CvL~hexNwo4m`AwS=9%hjTU~3j@7RxfsDM198 zX|f;?>!>FuQ|6;A<1%!2P1>h9<-a&+N$RrY81?^%h;te&f=H?paBxNFH?QyIK&{r? z9fmnN{wbTqKkRzf*@dZ+)N-ex&?&#zZ*7zgR1aUU`Jx>L$2HScca@7Pwa_1?q_SZ4 z*~j(r3+VanAaaqeIY@JUp=2yVnW#-oOQ#RJYVeY=yWxv)@LJ)Q7wL7=b28u9P}wU* zl+uKn2nAcCb-YLyJ00shhZxovG(NvJrmnlOzBZ)b6H^X6;=_v&J{;*-$hng{h&e1& z{k2>TMUQxs+((!TUqS$s7pt+er>fjSL%s114=ao#dvxuo!Zi@N&+Nk2ww9xXS5oZh z)}!5*!g|_vf)0jSEtVoa2G7@cvGM()eODIKV>#2bZO7ToxEYb62)}IwGvpX3j13HYx~;Pc);>EZ2bxbY#d%e;Y!~?pL8LHqj?XeCa*tL z(~^1E-mbaI7x&won3YKuvK!AyX>DuoC1xI4Zh;l78%T>8zv=xyZ~}HFk_Scp^a)zG zc5({-3H5lnanjjs%&xf3Rq8yu&n_Tq_2&Q#3T{`x%`+^5|LpFF7?m^kEpEuq(ZKhcR+jug zZBFMp>?D1GEu zC<0hcL@TTWl>$|f;vgwVzwT%$45A)?gqFfjnQDe0`roFxKUT?=b*Be*p^I56mj;Fd ztDXgGGbRa=+a*(Rm6^(4bWPyb51d5nNr*^@d-~wSt%GJEN+IQ-!_etaR0s++F05L}aQ^5`cEcn2)Sj61O3Efi5(=3Zt2u`q>nga4(Jz{b?j&Ozo5S zUVi4tynbH8GYfpyS+}LfNv8JdVpP~QWCy3cd|>M!#CzUQ47{c)(Sv*GYw=wR0}gfT z@Z0e5Fsj`$+&^bL#7EKQzrmYk4^XW<(f4C-krJ3~=qO)?&hM)A@W-2FqD{2%q3#xu zMCdh8D~MEh3tU9@f~*P4>^B)GiWk4de4FEmHy7KssqYPhSvb;_{(}w>@m)tiFUXZx z26LcgSK0Guh}#bj0S%MA_b(aP1U2>Wme`QqZksGet58p=Aq_n|j{|6%$R7)QEpJ=Z zC(XjwS{9ik>Nk9h@CxNkRrye)F;_6!dDU(^>A8OK`gEmB;&)M z+EgYTO9R22{@BgyeT%L9At$w8Ce^Bb?jUZvGRW)nIeBpRD6n1K5CVmT9tkTx;mS7bM1q{1$RXrTn2UO8N_bRV! zFK*4)%byA=8RjJ0wAC3<+f=xCgumhhsI0v*re+dbEw&5};H6I1R5+&L46~K8beH%l9Hj43B; zhXQ#Hs}`eP2!lRO$T=7VAgkhkp>OHHJgZ*LkkPL!`kjoH?FzsZ{X$d0L@;E*#*pDt zqQEkf4$i_MTDVJ~^nD;&5uTH|(D-Io1xmKbqdL4mDDBVx#%&%W^>lNifgGvc3P(Dp za)W+1JGBOC&K5ZdQ6>x;EV#pTPAND?(G=k!ub(ErBV+j~Gb6mQw`WZMI$jvS+)oo5 zm2@A~M~Y@zbQ`lPz9jWp6N8h?==jS8sU=E0WQsCJ45*{`!6K#4lP=su9BgI zlx30fVe|147@ZdqGogY^RZxdGI70u!oMRd3kdiMZ>z$kpMpDl)=o{0e=jYuEM59*p z2Gj=(u(T6tzdy|X0;I93X4^I>Sc!tLE93_5`$%!bAJ{sTUWhLd9JL-(-q(oU0JPkQ z1n;Z8Ek!KDn&h%nJ27DRbBcrr_L_?qY4`f{Kuz+egrOnPO_*F0iXCzm;#ld>8QjOQ z8vf7`!Uo*_nJQccxINd)0At%MRMJTKGZBd|k|1nsEe#!2lhojU!zM#@#fiS^n-q-n zO9CyqvRGc20D?E>E5bF^uIwhm?l0KuU2w9>Y@@_E)`*dv!Durp`&m=UQgW20Z}7_z zjPzw*AJex+3;qLaL5UQU%MOe#2gDQsg~)_HbtN_7&S!caKNK0s;}xlrJT}GjT%L8{b6 z52}iRiHV3F*ZwCP7SNR92a>`KFZ%>_DH;L`SK4iytm0vlf`FQ}F$R|f__~dKkcKHn zooTx{9jlp@rcA1tD!gKN`LnyOJW`KmYElHP`)9O`PM-+l_OlVH^N}^4s2jGk-fh@) z@4f2I*^G>5+G)33)=0iXjY6d;Gb~Qx;_z>+soWwMX17*%N8N~gqk?fMQNGPC<+5(I zAJOR-FU@bBKT9Qwn{q4$HB+tm<83=KkQF#aqaJ4-bAVD`w9e&~u!(xW&*16s-mS{EF&|Q7L;zx&HN4l_DE2& zqQa_BqDh8ZgVRyb2SuW6`hs83Htp0|^{_3h69ZU?;joJ87Xu|Qsdpt))R$hC;OH7g zY0)~(ny_ipMEd~}4xaVyqG*AFr>`MDl1FR^gCY*yISddU8^wcJT^ly2P=Qg!>@%-9 zUg?mz4EqWAMtYk@jl##n;{!Pf{r?Kp(H`o6GR8RZnbOfNHskciDOXbQHO8w_ERPxe z>Zt1ERKHc*DA{ic53g9pHAct&eWU?$9q%;s81G0VA0iJjGU4El)HRJGew z%ErF%sPy~e#dl?0W3KcSOAdA3o(qW|UsfH?w;Gqp-Ve}7qi@$u^NY;_$k(pD)polq zJkRXuqPp0aDo#Yq_>^2dmMi`KtZ)ZjDDXC>$=L3!FVEG$nwfbTKJf!r{DUI3CAugS z&7|YCV0|{=yO%h+F;uy0#cV3J6WOQikKCYnr#m zI>8wf%$V<2vN<{v!Yj|fo#aj-B==!=rpGPW)_Ze7C%Uwwde$Sac*s% z)G}*{PkTX@N9%c|-#KxNbW|W!f(@%x=42!WC>1?e9*+(tljvBr5hF@InX4(~$5T=h zr6S*N*!j|BAyv9U@k?(gid`GHK{6SP_BhaZn5$;`n|*|O1bf(Hoqa8V!R+UUxPa(_ zzC`W&1Nb-eX?wvF$ataL#}{0PZrJWB>@J`zBD!tMC*z3! z2!BB=?tdq@+x~60ee$s7u)m|wj=cp98Oe9_&rB#PdW?`O>hbN^B%i!AGq9gtLfWF`|uj0C$+B9@gl3}{jf1mSDK^ELkWlQt6t>Y)S;FZ(Z2fn;zY{w31mvmSJIJQ_Xg`KRh>402-(ELf&HYBa1g#uxcizU;w!1qC1Iha7uF&In(o) zMLE6S-oD!Pq`m!yuQC5HyfYwwNrK?r7Ed`S@p50Tq%+SR44PK$08nHB9d8873EbB8w)@7RZC%+ zZASiQ7ps_sx{x}#qoP76>pSb<+ZtGOCz*KF zQ6z`_eaOx@H6!)@TLBZJ!RONUIsqYk8U91e3E9=N!tuzS**on_#cH0M0597Z5_lPB zjwDH!!3*G<%Uy3ZyZ7_}`E6%ETQ^VE-n^ul8_lx>tM*$Kpvd^^Dkgz&~?-(oKD{>oR8ki@h+*U)rX~hAtsf3H% zVOrvQRu~-k?)?6AB7JqVMoQY_hh=$ivHsEXsqivdcxPWVf@<9J`x7RozSWN@m8P0# z$IM`MV-_Aw`o^4GETgvS)pWpbF&&(NMiO#H+fVshf$wxNnij9?rW;IZs{3s(Vq2c4 z_H+}V1XVMkM&iFu_|7RYF@U8)DgP_)6x*@jgX z=aPM=wS9K3dvgTAQ3Rbj)|eSI2$T6(j#LwR)FpN0Fq8(3IrRezx%uFo!TQ(gPG^#? zpY8Lb{-WndF2)HjAv!+0J!B8CkKe%QFM0B7#K~b&#N+bm045Qu{@O5{>gUA%>~d6W zFGSY%;_QX?Z26@YhCy{C*8aG34B-ZEiBOc7q}%Mngp>M!t^AFJM{+;vyd5o_KwE#w zCP775?&GW74Ptvk5L%i*a<9p{QqSb3L2r~|po3ZB9)qj{NAZ$uhi`wbPzCf<_Cr^< z_qXk?*8NlC%vU~FJko_t;zQSc&Q!VQEz4P;q-WLhnZC!MQ^7#ACaSE}DRTaIoOU^+ zkA899b4+Kg@p=J&6ipi>2A}Yu_G>}}bR5QkQUzujXyaakdyFnI8RS>42jr-gUj^4^ z^!e|{u&1;2@`KDM{J8%GKY#X4x1c!<^a_YzbSQEdF;+Z47&;)h4xpjKq0(b`b=2G*h}RZL~9o#?i(XILlV5czgbTHF~CFFI;Ue%zg~ z01loxPe=!=$z$}fW;5nu1~&n^SffQ=;jjeIME=nP(G?AC{-1FUFg(Q>C}$)tGTskU zZy?~|#5cqH-sqsXWmgBr67^!5f0c^;H*iQtl`DcwM`p+C0c8{eMjp8zn$I9j!&oeSmZ3N^z9u4RfzRtx4ktZp0L) zuqG@3U(scx0i#VR>3=^#bpYRXM-cbJfCz0O3O$-suj$(^6MZsNJAupRU7OK`gsT2> za&7TixE`@uqfa@0TO5YB@Vrr}$`^@Uu5S}fDwaf*BP_}x1Wn-i69Cb}f;JHZkcORv z{Szf9h%9kY*Xh&IlS;EdLy12+YapNC1`)&CUA0?4-m;v&0C-|rv>;RjJ{T1$6OIqy zhJHxaxAda%D^wzCv&K?2(3hYQEfRjn(WvdKrWRK)y=a!QM;4XRGb5D^UV9FAK8t#~ z_0gnlcMmeWGiF0C=ggZJEIiAiAbVPtfH|Wu3R)NJy2CcYM(fv@-{?EgIjkUH8P|JQ zr6Ih!iuNI7i)?UEVBZHv*heGcgs36G3phD}Cv#5NOFQ;AGEI2eJwA;udxH&&lkg^e z-*a0~Qvma0O^ z#GaaVa=fL+@}cZ6OK(ia;R9?mO=j)CjFrJJt~JNnn^zM)I# z$sWkhIsVVI!kXzDnHMjdQ9UyY+8s{8j#4v?aaf{3mNKrVc62N$rdm`&V3UM}j18vv zqhWiKc2X(@nYMj`uh`*&>h}U`H)vJ$U@^TsqKuSbGDzl1#OoR~)khM$iP` z!NGR^11IJlJOv_9_BaUGIUm;2K=>;E@~-9atKg+uh7e=*$ERPl1{h_4C$}a)rCdsb z>QEdH%nSWB9;IZSJxcJ1HQg)d@}NP#)?YN*EnY#|2E`D!<9zY49HK60>5NWkDghB4 zHuAh)_5J;BWWRgz|8IW_l`mxIAr4hCm&N%@|-!_!o%qCs6#Os6z$gl($4p zrZietlv8QtlcL1KTPKV0P(=L3q_ChzQg`v)&we2pu4&vvBcZXAeBC7IXUI1c-M1f9 zYmOh1;^U_;M@LU9Wfe?6s|Ib{hqxzQ{#1`1D%>W2HOK0JWa3xnC`X0(v5+*4j_(=Z z84ua59Wh`*Z*abcYR$!U9t&#P;ScR*u%fpbH0P<{DRb^Yd#F2!j848?aGWz*cg3}& z@AWWjJ^!d&*n&InW?-DcjQ^X$$UCu9U5Uw%gm2F|pm<7G2_NU0=53>I} zE0q_pcUhZQORw1~FiD(w_rX`BfnlRiWA9k`r63U%OZi#7-kbTmM0$%g*tgavmQFDO zzgyiy2~6G6P#o_7YuKexT^&DbG+#=~-yV~kiAwW^8NK~_A*-z1*})(!iqRS=Q@dQd zf~if8?BeY3zuzku`tF4>&5PdP~_ zE49N3-fZg4Me=xAjdr+kgJvM76QcoO9M+LpnZnhTXesJk_qalLz zq~6FrcK5`D_O2poiZb{8Zw7A!v}2zZyC_OTDw)Wg=eH9rebnMbo#npv){VRSlL>y} zx&Ts7oJQTw^Sd{sSz)`7s;?Zc5Zu;wo=@>F5xS&3Xugk{AV!a@BUx<|_ZkYBCiK3H zP#GuGNw8>DXU9s?M|?wAqrjNc#{opSD4wYOJ+QS09728`A9*lb{2WomZN}ZO_>eh$ z2RB~bc0xgFDR;PD^z)pygF!Zpbchqt5}+7yisPIFlx{o!X&!uy2YylzXY+QSL1I8r z0@uqJ9N+KuerMAuPv;%=iKVJzY5aIds>_d`` zc)Em9>*_3h_2y^Xj|-DZH{yoms7FSPa%(PXK#oq+EV_pc@O%evW-2}o8jGv*v2#Zvms zeev3&BuNq>81AdG=i3V6OlIdJ2-wBHE+U;U$_Uj3`PbGbuR#=Z)3U)QM;in3_I0Sv zak_aP;AOve+90xcZd}Too586>;=_6nS?FKFEFt4tDdsJ$5~Xi`5Id7{{=Zo@7Spck z?E0D{mwv)c`9<3{R`i}M4L~-;Ro;y{F1oWYv|4)d;}*GucQxWM=n(w%2Uy=MIc~{5 zW8LTZOJ(~q;BE5ZpgoJya(3uu8qso;^7?mhGlvz2Zl9IHnzuu`^8v1nL;9Guq1x)L zq3;@OJnIWU0PR0@aR=VjPDH;<;bvH*PtN$71MuyC6iob2r`gvVGc!?{rPv5%iz-{K zV#rkZzal92xSW+*Cb@V9p~LY0@~T2`UNAC9hw2F6avxnUrPQnObCzKovQ}~a>naym zp4||ttSCNj#f(tRxs0x_vmAqlw7bXDfk4W~83nVwTKi+EG5mc3f1zMp+l>;FMfj7$NB1;oi~-@)YY$4O)%Cx zdDX?I3@H!s*D^#JD|zR^nkveWcNhRk3#9vZ4n5!;K!4b6?&`;9$7fFVo z!S`CAx_Lfx__df~?O1AsfA6S)MYgg4P>Arpr#I>p!+GKL^z5#qn#H(fs|uqAj*Q~Ob(b0^iGcXqj9KKxP!#eQhH0(ffjCHjbg z-87K_7mja5#aEu#Ho!OV(WUD)_mD-*HaWoALW*FldbiY1Ju|s8{_|1=ZB*hTdGFqS z@=332@_xv#;J*YhllArbYV~h@?B4QtmA`;OO&9l-Xu0AKCxTUz0)UD@>(<`OsS6vw z?f3&^?A5p4s&(JzgD{KlQLb@VZ%^_dTI@8x!SZbtq`(Vcuv*bF{+}aO;1?zFO^vzw zE@`Z6{q^(8(}5?T()${d3KI&&`M_kPqtrtz(KYue>;ryIA!xa1gFvZ-SJ&}YKjr|( zykidDJ#Oi_K=^~_+$^rkXDa%!=ZT@?0|$;r z45EndywKb6Pd>Cjk&%^|g1^(b9g)~hb2Ve6uIfSUnO(i`?KMzE=^v9!1v$=HQ!?p( zEjk@tR}Onm{R>QEP>Zf8w2LdpT6W@^i4ng1JHSm?dbClqg9es!PTq!$GDByht0902 zS2m0gFA(yO@vl>LnTjS97ENtE`4B5Hc^rbD#8Y5>^#kMOo3Q&y4?~jYb$LQwwJ(K| z9+*+;)|qeK5_VJo9h_SYvKQQcq{IbG z(}6)_20I`}qw?%$?ErGC$TAX*9$L3Cp1b(5mA*Pe3z&a2^Zv@`9=)9yS+Fi}TLD7X zu$(H0p_3Np93*X?JUbg^9CG}kuAwFp|2%Jie~6nN=)3KpR8h-yc3&4Rl-Mc1uyo^(^&WpUN4T^KFEaJ|phi(0syY@tp)k<{}W6E8ny zd=e4<^3LFN(LgKvLEA_UP0Ry|Ay#yaV0^bc{{Sg%9>qY{uQ&&#AAXI$xHs2@Ce^RZ z#>ftC6j2P8cEo5}X@Ut}6{1jzF)mP8P*8X^rHBHyfgTHKMc2+qt>^Z!SGGsSI_9I0 zc!QJPEm2|RWU79Upeu1 zTqjg|;ke6JfgnX0hld34I~B26Ic%$?KC?qW-3Nh(&d#E^iFhW-Qa9_g?5@jiQFRgZ zb8&SoZc!pMQwo;bLKq3~--Zb2tldZ)_h*Q_cWH?aGv|qu<$=9udSqlP;{$h%;+R1R zJr0o?Q2+e)WNK-V9TRo+fG;dXf7ay8u#?ux23e1))0^IH|EWHC(h{6(Dq5GuGVvwI zk!Uu(DN4_fNfiRpLmA4W)g2m#%AtxNKZ1(3{;k8$QVr%&jgZ+&1rbSVh2od4!RE$i zhe^?DLMh$+UGJM2>F0}Lwm)w7`(;mx!^495d!fotBi-FeTyAeZYUvP9qWF)TBkIuEw@==S_2Mpm3iWmr%~_fS){^BKXMi8osz zKy9vzuG>>Nh;vVafSSZS-?nxcad)RD0m*O8(9iH&7xuFNO6wtpY%sg-veGZBXGW#m zg!>*=EkfEeqrD=T9in~djA8B>^CnrBC-7L>XKnC5=ZEGCW^2dO0S6QoqsEZCDZw)P z?-K1aPIlj8+O|;zg=MOsJE<4zeL2qW0Qgr|ImYdfT0fa4ZMa zrq-8IQ@5|Kh{rdYR4FwB%KoiR!H{9SAW{u(VR>^4_$)RS#u!!W0D~1qCcjAjqk4`tl5^v zDCS$cSvs)V%XQ;Fb(vnFGoC~;j`%Fe=j2ITB1N)SM6#vhQkUzUjC;rbtKlv%&n`p^ zf_o+k9f>t-g@XK6+!iy&1!Z{DSRned5&O~7(f_|r{a}d3U}jZ&X|_90lOc3PLWY0c zfV@6Dq$}`YFZ%KFYW1nyn|;0L#A(N7$JP*3k)Wa(n?ZA^>M5(_=N{r~h*zjYkp{~fz?OJ5ovJs^bDvN} zsRaEjLgBIQqk;`{i%0EJm1=8TewSBJUi;NSmIM9O(K>}I?YuqxpNnVYa+{zBtiV|Y z8VX(;CA5s>*Z8D5);|uk*B1@^I^5ho0w31k84;kB-)wubvNlk^RJD={Q#v%U`Z=yH i^16kOSnJS7%30;YOAqeLs21o0{u*H7b6E-v@&5p9koRf; literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline/hoist.frames b/benchmarks/catch_frames/evidence/baseline/hoist.frames new file mode 100644 index 0000000000..ef30c01d3f --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/hoist.frames @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:35:34 2026 + +3500011;;perry_catch_201827:push;3490348955;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/hoist.stat b/benchmarks/catch_frames/evidence/baseline/hoist.stat new file mode 100644 index 0000000000..d9d6adbd11 --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/hoist.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:30:55 2026 + +13816754889;;instructions:u;0.00%;862134599;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/json.expected b/benchmarks/catch_frames/evidence/baseline/json.expected new file mode 100644 index 0000000000..de404fe14d --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/json.expected @@ -0,0 +1 @@ +5008938890 diff --git a/benchmarks/catch_frames/evidence/baseline/json.folded.gz b/benchmarks/catch_frames/evidence/baseline/json.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..44ee1c4d29d64c18c46e31d2741a67ce12be04d1 GIT binary patch literal 7854 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 Mf0D;m+)mj60Do*hR{#J2 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline/json.frames b/benchmarks/catch_frames/evidence/baseline/json.frames new file mode 100644 index 0000000000..93a971d359 --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/json.frames @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:32:53 2026 + +6;;perry_catch_192702:push;228354174;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/json.stat b/benchmarks/catch_frames/evidence/baseline/json.stat new file mode 100644 index 0000000000..154d76b12a --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/json.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:29:53 2026 + +3182841469;;instructions:u;0.00%;190945873;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/plain.folded.gz b/benchmarks/catch_frames/evidence/baseline/plain.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..03cf1b0556e22dd54009245e7273b57c4f3ec98c GIT binary patch literal 218 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline/promises.frames b/benchmarks/catch_frames/evidence/baseline/promises.frames new file mode 100644 index 0000000000..771d12c385 --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/promises.frames @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:35:33 2026 + +100007;;perry_catch_201756:push;150141188;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/promises.stat b/benchmarks/catch_frames/evidence/baseline/promises.stat new file mode 100644 index 0000000000..9116c73379 --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/promises.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:29:25 2026 + +1098667245;;instructions:u;0.00%;106550647;100.00;; diff --git a/benchmarks/catch_frames/evidence/baseline/unwind.folded.gz b/benchmarks/catch_frames/evidence/baseline/unwind.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..dda52eee60ed70342dceaa0aa1e7d6dfe15bb8ad GIT binary patch literal 478 zcmV<40U`b$iwFP!00002|Ls;$Yuhjoe$THk6iNbRGFKBb)p-~F z4?*WoEoV}eCgEM7rb;i=eOQXtjRA}UkW5W}8t2LhqnNBx0z}PL4Dg*xZ3`pz4j6WjM{%*gH9?eLbST3gV>2OjGP$GNjPg6m%nl z_M^wF$F(6#JtrS&q4>IdA625bh?>8Y>)oV$M*FkEd6k;=CKplyd{LIAqD$}3XQkax z+Bl96S}~QTthJ`NUb|*c)diR19iwb8$`e>8oO0IMku#gIv0kha=Tm?|@9ZMEeLqM) zpJ*u!RstB0BmjLzW@LL literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/baseline/unwind.stat b/benchmarks/catch_frames/evidence/baseline/unwind.stat new file mode 100644 index 0000000000..de638f1e9b --- /dev/null +++ b/benchmarks/catch_frames/evidence/baseline/unwind.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:34:32 2026 + +366173508;;instructions:u;0.00%;25498367;100.00;; diff --git a/benchmarks/catch_frames/evidence/candidate-artifacts.json b/benchmarks/catch_frames/evidence/candidate-artifacts.json new file mode 100644 index 0000000000..80c7a3f1bd --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate-artifacts.json @@ -0,0 +1,5 @@ +{ + "perry": "08a1aff537958e855fbdf5b9f25ccd22deb3cc3fc1a97c2f3063ed98dd2cbd9d", + "libperry_runtime.a": "2c0b05fbad66bb569241ccf742831504c9ef8c4819a31845c3d92c70d0efaa72", + "libperry_stdlib.a": "86ffd21fcd187c748661fd85015d6824998a43f70610b98b98cb7e8fd86a0206" +} diff --git a/benchmarks/catch_frames/evidence/candidate/catch.folded.gz b/benchmarks/catch_frames/evidence/candidate/catch.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..bce3d191c99d5bdf93246043752e08168362415e GIT binary patch literal 511 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/candidate/exec1.out b/benchmarks/catch_frames/evidence/candidate/exec1.out new file mode 100644 index 0000000000..7a908ccedf --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/exec1.out @@ -0,0 +1 @@ +5888890 diff --git a/benchmarks/catch_frames/evidence/candidate/exec1.profile.out b/benchmarks/catch_frames/evidence/candidate/exec1.profile.out new file mode 100644 index 0000000000..7a908ccedf --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/exec1.profile.out @@ -0,0 +1 @@ +5888890 diff --git a/benchmarks/catch_frames/evidence/candidate/exec1.stat b/benchmarks/catch_frames/evidence/candidate/exec1.stat new file mode 100644 index 0000000000..7b0f84974f --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/exec1.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 05:47:42 2026 + +30183325430;;instructions:u;0.00%;3248216039;100.00;; diff --git a/benchmarks/catch_frames/evidence/candidate/exec1.stat.out b/benchmarks/catch_frames/evidence/candidate/exec1.stat.out new file mode 100644 index 0000000000..78ac85679b --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/exec1.stat.out @@ -0,0 +1,3 @@ +5888890 +5888890 +5888890 diff --git a/benchmarks/catch_frames/evidence/candidate/hoist.expected b/benchmarks/catch_frames/evidence/candidate/hoist.expected new file mode 100644 index 0000000000..354b2529b2 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/hoist.expected @@ -0,0 +1 @@ +500000 diff --git a/benchmarks/catch_frames/evidence/candidate/hoist.folded.gz b/benchmarks/catch_frames/evidence/candidate/hoist.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..8f64777ea711d37ba0a1c3b8d070378e455a09ba GIT binary patch literal 9539 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/candidate/hoist.out b/benchmarks/catch_frames/evidence/candidate/hoist.out new file mode 100644 index 0000000000..354b2529b2 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/hoist.out @@ -0,0 +1 @@ +500000 diff --git a/benchmarks/catch_frames/evidence/candidate/hoist.profile.out b/benchmarks/catch_frames/evidence/candidate/hoist.profile.out new file mode 100644 index 0000000000..354b2529b2 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/hoist.profile.out @@ -0,0 +1 @@ +500000 diff --git a/benchmarks/catch_frames/evidence/candidate/hoist.stat b/benchmarks/catch_frames/evidence/candidate/hoist.stat new file mode 100644 index 0000000000..d1a7784571 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/hoist.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 05:46:49 2026 + +13266297479;;instructions:u;0.00%;830465765;100.00;; diff --git a/benchmarks/catch_frames/evidence/candidate/hoist.stat.out b/benchmarks/catch_frames/evidence/candidate/hoist.stat.out new file mode 100644 index 0000000000..010112db02 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/hoist.stat.out @@ -0,0 +1,3 @@ +500000 +500000 +500000 diff --git a/benchmarks/catch_frames/evidence/candidate/json.expected b/benchmarks/catch_frames/evidence/candidate/json.expected new file mode 100644 index 0000000000..de404fe14d --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/json.expected @@ -0,0 +1 @@ +5008938890 diff --git a/benchmarks/catch_frames/evidence/candidate/json.folded.gz b/benchmarks/catch_frames/evidence/candidate/json.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..fb9e563eef380e8a059257b33e99cb34f92f93f2 GIT binary patch literal 7397 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/candidate/plain.profile.out b/benchmarks/catch_frames/evidence/candidate/plain.profile.out new file mode 100644 index 0000000000..ad629e2d59 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/plain.profile.out @@ -0,0 +1 @@ +499999500000 diff --git a/benchmarks/catch_frames/evidence/candidate/plain.stat b/benchmarks/catch_frames/evidence/candidate/plain.stat new file mode 100644 index 0000000000..93d3ea43c4 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/plain.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 05:49:18 2026 + +27068989;;instructions:u;0.00%;3532580;100.00;; diff --git a/benchmarks/catch_frames/evidence/candidate/plain.stat.out b/benchmarks/catch_frames/evidence/candidate/plain.stat.out new file mode 100644 index 0000000000..f8922fcfd0 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/plain.stat.out @@ -0,0 +1,3 @@ +499999500000 +499999500000 +499999500000 diff --git a/benchmarks/catch_frames/evidence/candidate/promises.expected b/benchmarks/catch_frames/evidence/candidate/promises.expected new file mode 100644 index 0000000000..90ee71a089 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/promises.expected @@ -0,0 +1 @@ +5000050000 diff --git a/benchmarks/catch_frames/evidence/candidate/promises.folded.gz b/benchmarks/catch_frames/evidence/candidate/promises.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..0ce633ab1a568cba9bf8c7866017834628a50ee6 GIT binary patch literal 2110 zcmV-E2*LLsiwFn+00002|8R0|ZE165b1r6YY-D9*0PS7tZ{s!+|Gs~PfC9xX5FFM{ zdfiiupx0opEq2>oY|^6N2wEChTuYRWq>{LY{_i(K%8&SwIEj-e$$YUTiZ9J?IGhJb z3G1YBhe8x;mzZPGGGn3^S;39$AsY=JOG$rPcwU9cc3~{XVSvAH?gPS)S z$Nx);$~FeR>HobKy?%4FRp0BTtOY)CkT^)A-u}N{38vXiXtuG4v=dDff;x^ph2{xj zSf$gqYh}koxM}+s%^XPzubSK7QwEvEQc+x`A<)Cq@OUAWyNlpW-Dcr`Alsk?W2BdUO zVzC^_TY$0AK2MUJ;fLvy5fF)MN7qB;Y}DsTtTP}j&1|WlAr|#ntUeS%QJ+N?Phs;Z z>_6m?$9ET=^k>{eWly+1H_Ex2+ zJ2U&TS?Uf4xwQGvROd+EQeve)f9RJfYNriLOg%eiG+U8q`sn^SL$@jml2IUgn9*4V=w$8oCmwmGr zS(l;+^AgEmFRL<+zxe+Xha-k$lhPK2S=3|mhgtcKtjtW*K}Uzza-tsF&NoG7frdng zUesg%`mVS;K^x92%aO;P2@RCh8O)UQ!@<=>B59+!Bl+O!KE@&#ld-EMhxS*pNZZj0)AxFtQzz z%7lq+fsA@@8JMmBqi8Kxh+h&w5eF67P5St23J+J7hk=&(#&QIr1Sd&rqFFqfh#Zg` zMxen+ViD2kL?$_;%*oH%d9qx(8h*u>APQGbB?2yLGTG?fUx=V(BY%VtJu}B0nIo_O zxq~rla0myC#!9CVFM#Oaip%vYnT$+eI-tS10vNoGt}EIwDf(v;Cu7?twIYsTWS`V+ zeNtqqd5;tayE~^u&18ZZF+3gL*>FEgP#E_$s2FCyhhx8`EwTNGSBtaxcUykyS`* zA`tCuRvB_`2iAxVUhQHxKX0t;Qa}0s!MA1OqP0(Uw#H!Z4Y9FD zx5ADvZ|roBqs(ZX)ODlzgaA7eaL#UuFywauJiyD~>;h)DM()N=X}w8IWFH z*jb?yAME=`s=5xJFmZD1y=}+>TlB~k7I_He!q1=92&~?{3asC?l^Lv)S@T|1?zFIL zkFmTHroqkt4yp2Uo#OyWn6xnlG}$8 zP}X9}i5P;=jlr@j1J|3_h+di+;m-yMCLE0v8pX*NWi`?@d|>LP$BWpSHpwe3&%Q!}S;D>72<1YA17DQH&N2NRwYSV}-8?In zlv{6eGe8}d2kX`zFkYP(%uAiMb)%de&wt(UO)$O|*Ee2>2wg<43W-Mm+ZPAq3 o?&-1Jy=z{(J5!dq>%qBen+j;s@%BK7Nh3`E2LQmKhD(_M0Ica6yZ`_I literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/candidate/promises.out b/benchmarks/catch_frames/evidence/candidate/promises.out new file mode 100644 index 0000000000..90ee71a089 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/promises.out @@ -0,0 +1 @@ +5000050000 diff --git a/benchmarks/catch_frames/evidence/candidate/promises.profile.out b/benchmarks/catch_frames/evidence/candidate/promises.profile.out new file mode 100644 index 0000000000..90ee71a089 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/promises.profile.out @@ -0,0 +1 @@ +5000050000 diff --git a/benchmarks/catch_frames/evidence/candidate/promises.stat b/benchmarks/catch_frames/evidence/candidate/promises.stat new file mode 100644 index 0000000000..4eff7d0354 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/promises.stat @@ -0,0 +1,3 @@ +# started on Mon Sep 14 05:46:01 2026 + +1077465852;;instructions:u;0.00%;67069381;100.00;; diff --git a/benchmarks/catch_frames/evidence/candidate/promises.stat.out b/benchmarks/catch_frames/evidence/candidate/promises.stat.out new file mode 100644 index 0000000000..0ef867f027 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/promises.stat.out @@ -0,0 +1,3 @@ +5000050000 +5000050000 +5000050000 diff --git a/benchmarks/catch_frames/evidence/candidate/results.json b/benchmarks/catch_frames/evidence/candidate/results.json new file mode 100644 index 0000000000..5b6c2704b1 --- /dev/null +++ b/benchmarks/catch_frames/evidence/candidate/results.json @@ -0,0 +1,51 @@ +{ + "promises": { + "instructions": 1077465852.0, + "samples": 1077, + "capture_samples": 4, + "transport_leaf_samples": 0, + "capture_percent": 0.3714020427112349 + }, + "json": { + "instructions": 3171165684.0, + "samples": 3168, + "capture_samples": 0, + "transport_leaf_samples": 0, + "capture_percent": 0.0 + }, + "hoist": { + "instructions": 13266297479.0, + "samples": 13263, + "capture_samples": 447, + "transport_leaf_samples": 483, + "capture_percent": 3.3702782175978285 + }, + "exec1": { + "instructions": 30183325430.0, + "samples": 30182, + "capture_samples": 999, + "transport_leaf_samples": 1080, + "capture_percent": 3.309919819760122 + }, + "plain": { + "instructions": 27068989.0, + "samples": 26, + "capture_samples": 0, + "transport_leaf_samples": 0, + "capture_percent": 0.0 + }, + "catch": { + "instructions": 351152420.0, + "samples": 351, + "capture_samples": 6, + "transport_leaf_samples": 43, + "capture_percent": 1.7094017094017093 + }, + "unwind": { + "instructions": 244175238.0, + "samples": 244, + "capture_samples": 129, + "transport_leaf_samples": 0, + "capture_percent": 52.868852459016395 + } +} diff --git a/benchmarks/catch_frames/evidence/candidate/unwind.folded.gz b/benchmarks/catch_frames/evidence/candidate/unwind.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..6d863c3a451c7f5aacabdbe831100cceace08feb GIT binary patch literal 369 zcmV-%0gnD3iwFn+00002|8;J6X>MdLW^Zg{Wn=)|Q%y?)F%Z4?S1bt9LXmb`5wgot zEck&!FZCocq-nMrnw>1kthGr0yW_4(m3r{vp{Hc#y}UPhBoIh?N&u``C};{OrNPPM z`u_HE3h~)!{2f)&+J=%m*0@Hu!Kb7t11*K{B!rc?`XC!5?NQo8pb%-dmkIHztP8c* zCxcx}3)>*XLaH@+sk9IPz77Nny)p=)aICwBra5+d{fMO!B}o;Kds%8$cpoYn4lX)y z+;>bW?fsU|Bbk!P`bFuAj6)%a`&AtZ*cd8cZE(qfoF7*pf4Y4?{s@F@fWoo& z&1}xrcWk;h!EhJJ5Gm)G=_=O9YgBD~S2#nZ)9xqOc4y6+o|ZL52a&d^w6#J!V34_< z^8WX!9L;UWvaH|BIGQGF$G*}3{o9HPujLX}nk112to9sYb}+%IcmyFRi8> 48) == 0x7ffd +set $header = $bits & 0xffffffffffff +set $func = *(unsigned long long*)$header +printf "closure function=%llx\n", $func +info symbol $func +set $base = (unsigned long long)&js_register_class_parent_dynamic - 0x747380 +if $func == $base + 0x6e2b00 +set *(unsigned long long*)$header = $base + 0x41de30 +printf "replaced only the duplicated noop identity with the comparison target\n" +end +end +continue +end +run diff --git a/benchmarks/catch_frames/evidence/constructor-identity/parent-identity.gdb.log b/benchmarks/catch_frames/evidence/constructor-identity/parent-identity.gdb.log new file mode 100644 index 0000000000..bf5dd9cf97 --- /dev/null +++ b/benchmarks/catch_frames/evidence/constructor-identity/parent-identity.gdb.log @@ -0,0 +1,67 @@ +Breakpoint 1 at 0x74739d: file crates/perry-runtime/src/object/class_registry/parent_static.rs, line 75. +[Thread debugging using libthread_db enabled] +Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". +plain typeof addEventListener: function +plain typeof removeEventListener: function +plain typeof dispatchEvent: function +plain listener fired +plain dispatch returned: true +Warning: the current language does not match this frame. +register parent: class=1 bits=7ffd0200002742d8 +closure function=555555c36b00 +perry_runtime::object::global_this::fetch_globals::global_this_builtin_noop_thunk in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +replaced only the duplicated noop identity with the comparison target +sub typeof addEventListener: function +sub typeof dispatchEvent: function +sub listener fired: go +sub dispatch returned: true +register parent: class=2 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +two-level typeof dispatchEvent: function +two-level listener fired +register parent: class=4 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +ctor-subclass listener fired, detail.count: 7 +ctor-subclass field survived super(): 7 +bound-read listener fired +removed listener did not fire +busB has no busA listener +busA listener fired +register parent: class=5 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +override-subclass inherits addEventListener: function +override ran for: x +override returned: true +once listener call count: 1 +plain instanceof EventTarget: true +sub instanceof EventTarget: true +two-level instanceof EventTarget: true +plain object instanceof EventTarget: false +register parent: class=6 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +empty-ctor subclass: function function +dynamic-new subclass: function +Reflect.construct subclass: function +register parent: class=12 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +class-expression subclass: function +class-expression listener fired +register parent: class=13 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +fn-local subclass: function +fn-local listener fired +register parent: class=7 bits=7ffd0200002742d8 +closure function=555555971e30 +perry_runtime::node_stream::pipeline::collected_pipeline_error_noop in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +deleted-own-prop subclass: function function +deleted-own-prop listener fired +frozen subclass: function function +event type: basic cancelable: false +custom event type: custom detail.n: 42 +[Inferior 1 (process 812179) exited normally] diff --git a/benchmarks/catch_frames/evidence/constructor-identity/parent.gdb b/benchmarks/catch_frames/evidence/constructor-identity/parent.gdb new file mode 100644 index 0000000000..6d74e05f37 --- /dev/null +++ b/benchmarks/catch_frames/evidence/constructor-identity/parent.gdb @@ -0,0 +1,16 @@ +set pagination off +set language c +break js_register_class_parent_dynamic +commands +silent +set $bits = (unsigned long long)$xmm0.v2_int64[0] +printf "register parent: class=%u bits=%llx\n", $edi, $bits +if ($bits >> 48) == 0x7ffd +set $header = $bits & 0xffffffffffff +set $func = *(unsigned long long*)$header +printf "closure function=%llx\n", $func +info symbol $func +end +continue +end +run diff --git a/benchmarks/catch_frames/evidence/constructor-identity/parent.gdb.log b/benchmarks/catch_frames/evidence/constructor-identity/parent.gdb.log new file mode 100644 index 0000000000..22b90a1e4a --- /dev/null +++ b/benchmarks/catch_frames/evidence/constructor-identity/parent.gdb.log @@ -0,0 +1,17 @@ +Breakpoint 1 at 0x74739d: file crates/perry-runtime/src/object/class_registry/parent_static.rs, line 75. +[Thread debugging using libthread_db enabled] +Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". +plain typeof addEventListener: function +plain typeof removeEventListener: function +plain typeof dispatchEvent: function +plain listener fired +plain dispatch returned: true +Warning: the current language does not match this frame. +register parent: class=1 bits=7ffd0200002742d8 +closure function=555555c36b00 +perry_runtime::object::global_this::fetch_globals::global_this_builtin_noop_thunk in section .text of /root/js-throw-evidence/eventtarget-triage/fix-debug +sub typeof addEventListener: undefined +sub typeof dispatchEvent: undefined +TypeError: addEventListener is not a function + at makeLocal () +[Inferior 1 (process 782006) exited with code 01] diff --git a/benchmarks/catch_frames/evidence/constructor-identity/rechecks.json.gz b/benchmarks/catch_frames/evidence/constructor-identity/rechecks.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..9da2af9caa69706e782f13256b1713bb232a0a36 GIT binary patch literal 511 zcmVGz(uh+bOHgPrE zI;*oIH^^3?SV3vQY6-?L{-QKnS|L$%Oo8Sd4heoK-f<1c8wTDUrz9;Fq+BG~SCUs* zS<&QMJb#T=67Z?lt&fzVvoA-Nv26=_Gg{lngBG}P+ZtbGGC%P=fsoEaMxMHFm5_YW zrNOMH99`c`CYWcT6mR~pVviu1w%v41itE~)60ErQ6Y_~1LUu#5ek-fFnd;Wrz7IBM zjfa;Xr(Iqc?E8Kr^rSvlnw4mNOWBT-g+G&vd6|z>4FX!fbiBXT!L^IV)f{R$ZqaNy zXhl6NUH6?qZEIwWFbc3ymc0mz33 z@+>L0z_6esVf?2%Qih;c9GS7p{ZPINM4AT>|AP)*0^>6JXNAUa<3N9ZD2I>jCa zZqP+{ql-wD2B98w(TD4zG^z3;fEaYqJ?J9$nNEW)3cBcBx+vO3zW}FxpFIQ`0075m B^hf{z literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/fault-results.json b/benchmarks/catch_frames/evidence/fault-results.json new file mode 100644 index 0000000000..ad17d80912 --- /dev/null +++ b/benchmarks/catch_frames/evidence/fault-results.json @@ -0,0 +1,80 @@ +[ + { + "restore": "shadow", + "test": "exception::savepoints::restore_tests::shadow", + "exit_code": -6, + "detected": true + }, + { + "restore": "runtime_handles", + "test": "exception::savepoints::restore_tests::runtime_handles", + "exit_code": -6, + "detected": true + }, + { + "restore": "call_method", + "test": "exception::savepoints::restore_tests::call_method", + "exit_code": -6, + "detected": true + }, + { + "restore": "pump", + "test": "exception::savepoints::restore_tests::pump", + "exit_code": -6, + "detected": true + }, + { + "restore": "set_foreach", + "test": "exception::savepoints::restore_tests::set_foreach", + "exit_code": -6, + "detected": true + }, + { + "restore": "map_foreach", + "test": "exception::savepoints::restore_tests::map_foreach", + "exit_code": -6, + "detected": true + }, + { + "restore": "prototype_resolution", + "test": "exception::savepoints::restore_tests::prototype_resolution", + "exit_code": -6, + "detected": true + }, + { + "restore": "static_private_owner", + "test": "exception::savepoints::restore_tests::static_private_owner", + "exit_code": -6, + "detected": true + }, + { + "restore": "private_lexical_brand", + "test": "exception::savepoints::restore_tests::private_lexical_brand", + "exit_code": -6, + "detected": true + }, + { + "restore": "derived_super_binding", + "test": "exception::savepoints::restore_tests::derived_super_binding", + "exit_code": -6, + "detected": true + }, + { + "restore": "private_member_access_hints", + "test": "exception::savepoints::restore_tests::private_member_access_hints", + "exit_code": -6, + "detected": true + }, + { + "restore": "regex_factory", + "test": "exception::savepoints::restore_tests::regex_factory", + "exit_code": -6, + "detected": true + }, + { + "restore": "dyn_eval", + "test": "exception::savepoints::restore_tests::dyn_eval", + "exit_code": -6, + "detected": true + } +] diff --git a/benchmarks/catch_frames/evidence/fault-witnesses.txt b/benchmarks/catch_frames/evidence/fault-witnesses.txt new file mode 100644 index 0000000000..f435382458 --- /dev/null +++ b/benchmarks/catch_frames/evidence/fault-witnesses.txt @@ -0,0 +1,132 @@ +Missing-restore fault injections, 2026-09-14, macOS arm64. +Each excerpt is from a separate process; every exit was SIGABRT (-6). + +shadow +running 1 test +test exception::savepoints::restore_tests::shadow ... +thread 'exception::savepoints::restore_tests::shadow' (140782386) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: ShadowSavepoint { frame_top: 6, len: 9, temp_roots: 3 } + right: ShadowSavepoint { frame_top: 3, len: 5, temp_roots: 2 } + +runtime_handles +running 1 test +test exception::savepoints::restore_tests::runtime_handles ... +thread 'exception::savepoints::restore_tests::runtime_handles' (140782392) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +call_method +running 1 test +test exception::savepoints::restore_tests::call_method ... +thread 'exception::savepoints::restore_tests::call_method' (140782397) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +pump +running 1 test +test exception::savepoints::restore_tests::pump ... +thread 'exception::savepoints::restore_tests::pump' (140782403) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +set_foreach +running 1 test +test exception::savepoints::restore_tests::set_foreach ... +thread 'exception::savepoints::restore_tests::set_foreach' (140782408) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +map_foreach +running 1 test +test exception::savepoints::restore_tests::map_foreach ... +thread 'exception::savepoints::restore_tests::map_foreach' (140782417) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +prototype_resolution +running 1 test +test exception::savepoints::restore_tests::prototype_resolution ... +thread 'exception::savepoints::restore_tests::prototype_resolution' (140782423) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +static_private_owner +running 1 test +test exception::savepoints::restore_tests::static_private_owner ... +thread 'exception::savepoints::restore_tests::static_private_owner' (140782428) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +private_lexical_brand +running 1 test +test exception::savepoints::restore_tests::private_lexical_brand ... +thread 'exception::savepoints::restore_tests::private_lexical_brand' (140782432) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +derived_super_binding +running 1 test +test exception::savepoints::restore_tests::derived_super_binding ... +thread 'exception::savepoints::restore_tests::derived_super_binding' (140782439) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +private_member_access_hints +running 1 test +test exception::savepoints::restore_tests::private_member_access_hints ... +thread 'exception::savepoints::restore_tests::private_member_access_hints' (140782443) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +regex_factory +running 1 test +test exception::savepoints::restore_tests::regex_factory ... +thread 'exception::savepoints::restore_tests::regex_factory' (140782449) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3 + right: 2 + +dyn_eval +running 1 test +test exception::savepoints::restore_tests::dyn_eval ... +thread 'exception::savepoints::restore_tests::dyn_eval' (140782452) panicked at crates/perry-runtime/src/exception/savepoints/tests.rs:51:9: +assertion `left == right` failed: inner catch must preserve its enclosing scope + left: 3298534883331 + right: 2199023255554 + +Restored production source: + +running 20 tests +test exception::savepoints::restore_tests::call_method ... ok +test exception::savepoints::restore_tests::derived_super_binding ... ok +test exception::savepoints::restore_tests::dyn_eval ... ok +test exception::savepoints::restore_tests::map_foreach ... ok +test exception::savepoints::restore_tests::private_lexical_brand ... ok +test exception::savepoints::restore_tests::private_member_access_hints ... ok +test exception::savepoints::restore_tests::prototype_resolution ... ok +test exception::savepoints::restore_tests::pump ... ok +test exception::savepoints::restore_tests::regex_factory ... ok +test exception::savepoints::restore_tests::runtime_handles ... ok +test exception::savepoints::restore_tests::set_foreach ... ok +test exception::savepoints::restore_tests::shadow ... ok +test exception::savepoints::restore_tests::static_private_owner ... ok +test exception::tests::arm_trap_and_run_catches_a_real_throw ... ok +test exception::tests::catch_js_throw_err_clears_exception ... ok +test exception::tests::js_throw_path_restores_runtime_handles_across_unwound_frames ... ok +test exception::tests::js_throw_path_restores_shadow_stack_across_unwound_frames ... ok +test exception::tests::nested_trampoline_arms_unwind_innermost_first ... ok +test exception::tests::the_uncaught_report_carries_the_error_code_and_the_frames ... ok +test exception::tests::try_push_pop_beyond_old_limit_does_not_panic ... ok + +test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 3795 filtered out; finished in 0.03s diff --git a/benchmarks/catch_frames/evidence/fix-full-lint.log b/benchmarks/catch_frames/evidence/fix-full-lint.log new file mode 100644 index 0000000000..7d6fed20d2 --- /dev/null +++ b/benchmarks/catch_frames/evidence/fix-full-lint.log @@ -0,0 +1,104 @@ +run_lint_gates: 79 gate commands derived from 45 lint run steps + + ok [Changeset gate self-test] ./scripts/check_changeset_fragment.sh --self-test + skip [Require a changelog.d/ fragment for crates/ changes] ./scripts/check_changeset_fragment.sh "${{ github.repository }}" "${{ github.event.pull_request.number }}" + (needs GitHub API repository/PR context) + ok [Validate benchmark artifact and fallback gates] python3 -m unittest discover -s tests -p 'test_benchmark_*.py' -v + ok [Validate benchmark artifact and fallback gates] ./tests/test_benchmark_peer_fallback.sh + ok [Validate benchmark artifact and fallback gates] ./tests/test_benchmark_output_verifier.sh + ok [Validate benchmark artifact and fallback gates] bash -n benchmarks/compare.sh benchmarks/quick.sh benchmarks/suite/run_benchmarks.sh benchmarks/honest_bench/run.sh benchmarks/honest_bench/harness/run_http_bench.sh tests/test_benchmark_peer_fallback.sh + ok [Validate Windows LLVM runtime npm staging] ./tests/test_stage_npm_windows_llvm.sh + ok [Release pipeline failure-path regressions] python3 tests/test_release_pipeline.py + ok [Release pipeline failure-path regressions] node --test scripts/publish/platform-visibility.test.mjs + ok [Install Rust toolchain] rustup toolchain install nightly-2026-08-20 --profile minimal --component rustfmt --component clippy + ok [Check formatting] cargo fmt --all -- --check + ok [CI plan policy self-test + docs table freshness] python3 scripts/ci_plan.py --self-test + ok [CI plan policy self-test + docs table freshness] python3 scripts/ci_pr_files.py --self-test + ok [CI plan policy self-test + docs table freshness] python3 scripts/ci_cargo_test_shard.py --self-test + skip [CI plan policy self-test + docs table freshness] python3 scripts/ci_cargo_test_shard.py --package perry --total-shards "${{ fromJSON(needs.plan.outputs.plan).cargo_test_perry.total }}" --validate + (needs the CI plan's shard count) + ok [Compiler-output gate liveness] python3 scripts/compiler_output_step_liveness.py --self-test + ok [Compiler-output gate liveness] python3 scripts/compiler_output_step_liveness.py + ok [Audit workspace architecture] python3 scripts/workspace_architecture.py --self-test + ok [Audit workspace architecture] python3 scripts/workspace_architecture.py --check --print-summary + ok [Linux incident collector fixtures] python3 scripts/test_capture_linux_incident.py + ok [Public benchmark evidence freshness] PYTHONPATH=. python3 tests/test_public_baseline.py + FAIL [Public benchmark evidence freshness] python3 benchmarks/ci_public_baseline_check.py + public baseline error: public artifact benchmark inputs changed; regenerate it with ./benchmarks/run_public_baseline.sh + ok [File size limit] ./scripts/check_file_size.sh + ok [Local binding type-proof audit] python3 scripts/local_binding_type_audit.py --self-test + ok [Local binding type-proof audit] python3 scripts/local_binding_type_audit.py + ok [Binding upstream pins (lock-step)] node scripts/binding_pins.mjs --check + ok [Bundled binding governance] python3 scripts/binding_governance.py --check + ok [GC store-site inventory] python3 scripts/gc_store_site_inventory.py --self-test + ok [GC store-site inventory] python3 scripts/gc_store_site_inventory.py + ok [Address-classification audit] python3 scripts/addr_class_inventory.py --self-test + ok [Address-classification audit] python3 scripts/addr_class_inventory.py + ok [String payload-access inventory] python3 scripts/string_payload_access_inventory.py --self-test + ok [String payload-access inventory] python3 scripts/string_payload_access_inventory.py + ok [Class-id collision audit] python3 scripts/class_id_collisions.py + ok [Object-header shape-descriptor census] python3 scripts/shape_descriptor_census.py + ok [GC pin-site custody audit] python3 scripts/gc_pin_sites.py --self-test + ok [GC pin-site custody audit] python3 scripts/gc_pin_sites.py + ok [Cross-thread promise provenance (#9552)] python3 scripts/check_cross_thread_promise_provenance.py --self-test + ok [Cross-thread promise provenance (#9552)] python3 scripts/check_cross_thread_promise_provenance.py + ok [Runtime GC-pointer holder custody audit] python3 scripts/gc_runtime_root_holders.py --self-test + ok [Runtime GC-pointer holder custody audit] python3 scripts/gc_runtime_root_holders.py + ok [Poll-capable reach audit (GC root dominance)] python3 scripts/gc_root_dominance_check.py --self-test + ok [Poll-capable reach audit (GC root dominance)] python3 scripts/gc_root_dominance_check.py --audit-poll-reach + ok [Thread-local GC scanner registration audit] python3 scripts/check_gc_scanner_latches.py --self-test + ok [Thread-local GC scanner registration audit] python3 scripts/check_gc_scanner_latches.py + ok [Rekeyed side-table custody audit] python3 scripts/gc_rekeyed_key_tables.py --self-test + ok [Rekeyed side-table custody audit] python3 scripts/gc_rekeyed_key_tables.py + ok [GC environment-knob drift audit] python3 scripts/check_gc_env_knobs.py --self-test + ok [GC environment-knob drift audit] python3 scripts/check_gc_env_knobs.py + ok [llvm-inprocess corpus currency] python3 scripts/check_llvm_corpus_currency.py --self-test + ok [llvm-inprocess corpus currency] python3 scripts/check_llvm_corpus_currency.py + ok [Statepoint pass source reader] python3 scripts/read_statepoint_rewrite_passes.py --self-test + ok [Statepoint pass source reader] python3 scripts/read_statepoint_rewrite_passes.py --check + ok [GC documentation claim audit] python3 scripts/check_gc_doc_claims.py --self-test + ok [GC documentation claim audit] python3 scripts/check_gc_doc_claims.py + ok [Windows-portable text I/O in the Windows-CI audits] python3 scripts/check_locale_independent_io.py --self-test + ok [Windows-portable text I/O in the Windows-CI audits] python3 scripts/check_locale_independent_io.py + ok [GC evacuation-liveness assert can say no] python3 scripts/gc_evacuation_liveness_assert.py --self-test + ok [Node version consistency] python3 scripts/check_node_version_consistency.py --self-test + ok [Node version consistency] python3 scripts/check_node_version_consistency.py + ok [Raw-handle debt ratchet] python3 scripts/raw_handle_debt.py --self-test + ok [Raw-handle debt ratchet] python3 scripts/raw_handle_debt.py + ok [Unrooted-local shape ratchet] python3 scripts/unrooted_local_shape.py --self-test + ok [Unrooted-local shape ratchet] python3 scripts/unrooted_local_shape.py --check + ok [Unrooted-local shape ratchet vs. merge base] python3 scripts/unrooted_local_shape.py --no-raise-vs "$BASE_SHA" + ok [Raw-handle debt ratchet vs. merge base] python3 scripts/raw_handle_debt.py --no-raise-vs "$BASE_SHA" + ok [Gap snapshot checker self-test] python3 scripts/gap_snapshot.py --self-test + ok [Platform-aware parity allowlist self-test] python3 scripts/parity_known_failures.py --self-test + ok [Parity allowlist ratchet (provenance + stale entries)] python3 scripts/parity_known_failures.py --audit + ok [Moving-GC gate wiring] python3 scripts/gc_gate_wiring_check.py --self-test + ok [Moving-GC gate wiring] python3 scripts/gc_gate_wiring_check.py + ok [GC matrix liveness gate] ./scripts/gc_repsel_matrix.sh --self-test-liveness-parser + ok [GC matrix liveness gate] python3 scripts/gc_repsel_matrix_merge.py --self-test + ok [GC matrix liveness gate] python3 scripts/gc_matrix_liveness_check.py --self-test + ok [GC matrix liveness gate] python3 scripts/gc_matrix_liveness_check.py --check-registry + ok [Test registration (dark tests)] python3 scripts/check_test_registration.py --self-test + ok [Test registration (dark tests)] python3 scripts/check_test_registration.py + ok [Per-test global sinks] python3 scripts/global_sink_isolation.py --self-test + ok [Per-test global sinks] python3 scripts/global_sink_isolation.py + +run_lint_gates: 6 compile commands derived from warnings + check (18 exclude args) + ok [warnings: rustc warnings (product)] RUSTFLAGS="-D warnings" cargo check -p perry --bins + FAIL [warnings: rustc warnings (host-compatible, all targets)] RUSTFLAGS="-D warnings" cargo check --workspace --all-targets --exclude perry-ui-android --exclude perry-ui-gtk4 --exclude perry-ui-ios --exclude perry-ui-macos --exclude perry-ui-tvos --exclude perry-ui-visionos --exclude perry-ui-watchos --exclude perry-ui-windows --exclude perry-ui-windows-winui + --> crates/perry-runtime/src/object/global_this_webassembly.rs:201:15 + | + 201 | pub(crate) fn registered_extern_handle(wrapper: usize, expected_kind: &[u8]) -> Option { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + + error: could not compile `perry-runtime` (lib test) due to 4 previous errors + ok [check: Clippy (product)] cargo clippy -p perry --bins + ok [check: Clippy (host-compatible)] cargo clippy --workspace --exclude perry-ui-android --exclude perry-ui-gtk4 --exclude perry-ui-ios --exclude perry-ui-macos --exclude perry-ui-tvos --exclude perry-ui-visionos --exclude perry-ui-watchos --exclude perry-ui-windows --exclude perry-ui-windows-winui + ok [check: Regenerate API docs] ./scripts/regen_api_docs.sh + FAIL [check: Check for API docs drift] git diff --quiet -- docs/src/api/reference.md docs/api/perry.d.ts + + +run_lint_gates: 3 of 83 FAILED; 2 CI-only skipped + [Public benchmark evidence freshness] python3 benchmarks/ci_public_baseline_check.py + [warnings: rustc warnings (host-compatible, all targets)] RUSTFLAGS="-D warnings" cargo check --workspace --all-targets --exclude perry-ui-android --exclude perry-ui-gtk4 --exclude perry-ui-ios --exclude perry-ui-macos --exclude perry-ui-tvos --exclude perry-ui-visionos --exclude perry-ui-watchos --exclude perry-ui-windows --exclude perry-ui-windows-winui + [check: Check for API docs drift] git diff --quiet -- docs/src/api/reference.md docs/api/perry.d.ts diff --git a/benchmarks/catch_frames/evidence/gap.json.gz b/benchmarks/catch_frames/evidence/gap.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..6053e55c9d6ba26099e1f1a0fd23b592a691ad01 GIT binary patch literal 9807 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/gc-comparison.json b/benchmarks/catch_frames/evidence/gc-comparison.json new file mode 100644 index 0000000000..25ee34e655 --- /dev/null +++ b/benchmarks/catch_frames/evidence/gc-comparison.json @@ -0,0 +1,11 @@ +{ + "baseline_commit": "eb13fa188d", + "probes": 14, + "repeats": 7, + "heap_and_collector_medians_compared": 126, + "changed_medians": [], + "ratchet_profile": "shared_ci", + "ratchet_result": "pass", + "baseline_kind": "fresh same-host main; does not replace the committed artifact", + "candidate_scope": "final guarded three-package artifacts" +} diff --git a/benchmarks/catch_frames/evidence/gc-stress.json.gz b/benchmarks/catch_frames/evidence/gc-stress.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..351a03f4d6650941af50699f0e121364b26701d0 GIT binary patch literal 15105 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/guard-gc-artifacts.json b/benchmarks/catch_frames/evidence/guard-gc-artifacts.json new file mode 100644 index 0000000000..1536fb3124 --- /dev/null +++ b/benchmarks/catch_frames/evidence/guard-gc-artifacts.json @@ -0,0 +1,7 @@ +{ + "perry": "30410e4e815b93ffd1c7d4bc65aa2ff66111c5b79ff3ce18e466fb3d8a63fbc0", + "libperry_runtime.a": "2c0b05fbad66bb569241ccf742831504c9ef8c4819a31845c3d92c70d0efaa72", + "libperry_stdlib.a": "547c3758646fb5f0b33fd298e6954746b251e2d23dd4cd5c65403431616ac620", + "libperry_ext_net.a": "df818833d44021acd73b33c39c9b23a5b3b90d680c6f0b6af4c275a9abb8340b", + "libperry_ext_http.a": "c64f8d7ce7f9e53fdc09f3ded8f23db12d1a9e509876fa419ef9c5c496ce81ea" +} diff --git a/benchmarks/catch_frames/evidence/guard-gc-ratchet-check.log b/benchmarks/catch_frames/evidence/guard-gc-ratchet-check.log new file mode 100644 index 0000000000..6d8780f371 --- /dev/null +++ b/benchmarks/catch_frames/evidence/guard-gc-ratchet-check.log @@ -0,0 +1,193 @@ +## GC ratchet + +- Profile: `shared_ci` +- Baseline commit: `eb13fa188d` +- Baseline captured: 2026-09-14T04:44:16+00:00 on `linux-x86_64` +- Baseline host: x86_64, 16 cores, load at capture 10.89 + +Only rows marked gating can fail the job. Non-gating rows are recorded so a +drift that is real but unmeasurable on this runner is still visible. + +Probes pinned under a non-default collector configuration: + +- `13_large_eden_survivors` — `PERRY_GC_SCAVENGE_NURSERY_MB=64` +- `14_grow_then_churn` — `PERRY_GC_MAJOR_PACING_FLOOR_MB=1 PERRY_GC_SCAVENGE_NURSERY_MB=1` + +| Probe | Metric | Baseline | Current | Δ | Allowance | Gating | Status | +|-------|--------|---------:|--------:|---:|----------:|:------:|--------| +| `01_nursery_churn` | heap_used_bytes | 438,744 | 438,744 | +0.00% | 65,536 | yes | ok | +| `01_nursery_churn` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `01_nursery_churn` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `01_nursery_churn` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `01_nursery_churn` | copied_objects | 6,690 | 6,690 | +0.00% | 334 | yes | ok | +| `01_nursery_churn` | copied_bytes | 466,392 | 466,392 | +0.00% | 65,536 | yes | ok | +| `01_nursery_churn` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `01_nursery_churn` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `01_nursery_churn` | freed_bytes | 11,067,816 | 11,067,816 | +0.00% | 1,048,576 | yes | ok | +| `01_nursery_churn` | rss_bytes | 59,191,296 | 60,506,112 | +2.22% | 8,878,694 | no | ok | +| `01_nursery_churn` | peak_rss_bytes | 61,480,960 | 62,861,312 | +2.25% | 9,222,144 | no | ok | +| `01_nursery_churn` | wall_ms | 57 | 69 | +20.64% | 100 | no | ok | +| `02_survivor_promotion` | heap_used_bytes | 2,562,832 | 2,562,832 | +0.00% | 65,536 | yes | ok | +| `02_survivor_promotion` | heap_total_bytes | 15,728,640 | 15,728,640 | +0.00% | 1,048,576 | yes | ok | +| `02_survivor_promotion` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `02_survivor_promotion` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `02_survivor_promotion` | copied_objects | 37,366 | 37,366 | +0.00% | 1,868 | yes | ok | +| `02_survivor_promotion` | copied_bytes | 1,690,264 | 1,690,264 | +0.00% | 84,513 | yes | ok | +| `02_survivor_promotion` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `02_survivor_promotion` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `02_survivor_promotion` | freed_bytes | 8,795,408 | 8,795,408 | +0.00% | 1,048,576 | yes | ok | +| `02_survivor_promotion` | rss_bytes | 59,736,064 | 61,808,640 | +3.47% | 8,960,410 | no | ok | +| `02_survivor_promotion` | peak_rss_bytes | 72,052,736 | 69,627,904 | -3.37% | 10,807,910 | no | ok | +| `02_survivor_promotion` | wall_ms | 69 | 87 | +26.70% | 100 | no | ok | +| `03_cross_gen_writes` | heap_used_bytes | 528 | 528 | +0.00% | 65,536 | yes | ok | +| `03_cross_gen_writes` | heap_total_bytes | 12,582,912 | 12,582,912 | +0.00% | 1,048,576 | yes | ok | +| `03_cross_gen_writes` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `03_cross_gen_writes` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `03_cross_gen_writes` | copied_objects | 4,107 | 4,107 | +0.00% | 205 | yes | ok | +| `03_cross_gen_writes` | copied_bytes | 197,056 | 197,056 | +0.00% | 65,536 | yes | ok | +| `03_cross_gen_writes` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `03_cross_gen_writes` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `03_cross_gen_writes` | freed_bytes | 9,240,008 | 9,240,008 | +0.00% | 1,048,576 | yes | ok | +| `03_cross_gen_writes` | rss_bytes | 49,836,032 | 41,787,392 | -16.15% | 8,388,608 | no | ok | +| `03_cross_gen_writes` | peak_rss_bytes | 57,798,656 | 50,696,192 | -12.29% | 8,669,798 | no | ok | +| `03_cross_gen_writes` | wall_ms | 36 | 54 | +50.53% | 100 | no | ok | +| `04_dead_after_deep_stack` | heap_used_bytes | 536 | 536 | +0.00% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | heap_total_bytes | 18,874,368 | 18,874,368 | +0.00% | 1,048,576 | yes | ok | +| `04_dead_after_deep_stack` | minor_cycles | 7 | 7 | +0.00% | 1 | yes | ok | +| `04_dead_after_deep_stack` | step_cycles | 7 | 7 | +0.00% | 1 | yes | ok | +| `04_dead_after_deep_stack` | copied_objects | 2,666 | 2,666 | +0.00% | 133 | yes | ok | +| `04_dead_after_deep_stack` | copied_bytes | 111,336 | 111,336 | +0.00% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | promoted_objects | 682 | 682 | +0.00% | 34 | yes | ok | +| `04_dead_after_deep_stack` | promoted_bytes | 27,320 | 27,320 | +0.00% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | freed_bytes | 76,493,952 | 76,493,952 | +0.00% | 3,824,698 | yes | ok | +| `04_dead_after_deep_stack` | rss_bytes | 56,668,160 | 58,011,648 | +2.37% | 8,500,224 | no | ok | +| `04_dead_after_deep_stack` | peak_rss_bytes | 64,937,984 | 62,251,008 | -4.14% | 9,740,698 | no | ok | +| `04_dead_after_deep_stack` | wall_ms | 50 | 67 | +34.21% | 100 | no | ok | +| `05_closure_capture` | heap_used_bytes | 544 | 544 | +0.00% | 65,536 | yes | ok | +| `05_closure_capture` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `05_closure_capture` | minor_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `05_closure_capture` | step_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `05_closure_capture` | copied_objects | 14,285 | 14,285 | +0.00% | 714 | yes | ok | +| `05_closure_capture` | copied_bytes | 534,720 | 534,720 | +0.00% | 65,536 | yes | ok | +| `05_closure_capture` | promoted_objects | 6,154 | 6,154 | +0.00% | 308 | yes | ok | +| `05_closure_capture` | promoted_bytes | 221,624 | 221,624 | +0.00% | 65,536 | yes | ok | +| `05_closure_capture` | freed_bytes | 27,897,872 | 27,897,872 | +0.00% | 1,394,894 | yes | ok | +| `05_closure_capture` | rss_bytes | 52,531,200 | 52,678,656 | +0.28% | 8,388,608 | no | ok | +| `05_closure_capture` | peak_rss_bytes | 60,334,080 | 61,431,808 | +1.82% | 9,050,112 | no | ok | +| `05_closure_capture` | wall_ms | 70 | 77 | +8.58% | 100 | no | ok | +| `06_string_retention` | heap_used_bytes | 1,072 | 1,072 | +0.00% | 65,536 | yes | ok | +| `06_string_retention` | heap_total_bytes | 22,020,096 | 22,020,096 | +0.00% | 1,048,576 | yes | ok | +| `06_string_retention` | minor_cycles | 4 | 4 | +0.00% | 1 | yes | ok | +| `06_string_retention` | step_cycles | 4 | 4 | +0.00% | 1 | yes | ok | +| `06_string_retention` | copied_objects | 270 | 270 | +0.00% | 16 | yes | ok | +| `06_string_retention` | copied_bytes | 70,144 | 70,144 | +0.00% | 65,536 | yes | ok | +| `06_string_retention` | promoted_objects | 14 | 14 | +0.00% | 16 | yes | ok | +| `06_string_retention` | promoted_bytes | 1,072 | 1,072 | +0.00% | 65,536 | yes | ok | +| `06_string_retention` | freed_bytes | 68,136,816 | 68,136,816 | +0.00% | 3,406,841 | yes | ok | +| `06_string_retention` | rss_bytes | 59,215,872 | 50,757,632 | -14.28% | 8,882,381 | no | ok | +| `06_string_retention` | peak_rss_bytes | 67,723,264 | 54,624,256 | -19.34% | 10,158,490 | no | improvement | +| `06_string_retention` | wall_ms | 62 | 137 | +122.65% | 100 | no | ok | +| `07_array_grow_evacuate` | heap_used_bytes | 1,211,232 | 1,211,232 | +0.00% | 65,536 | yes | ok | +| `07_array_grow_evacuate` | heap_total_bytes | 25,165,824 | 25,165,824 | +0.00% | 1,048,576 | yes | ok | +| `07_array_grow_evacuate` | minor_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `07_array_grow_evacuate` | step_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `07_array_grow_evacuate` | copied_objects | 6,702 | 6,702 | +0.00% | 335 | yes | ok | +| `07_array_grow_evacuate` | copied_bytes | 2,636,392 | 2,636,392 | +0.00% | 131,820 | no | ok | +| `07_array_grow_evacuate` | promoted_objects | 6,154 | 6,154 | +0.00% | 308 | yes | ok | +| `07_array_grow_evacuate` | promoted_bytes | 841,048 | 841,048 | +0.00% | 65,536 | yes | ok | +| `07_array_grow_evacuate` | freed_bytes | 83,570,704 | 83,570,704 | +0.00% | 4,178,535 | no | ok | +| `07_array_grow_evacuate` | rss_bytes | 68,734,976 | 66,523,136 | -3.22% | 10,310,246 | no | ok | +| `07_array_grow_evacuate` | peak_rss_bytes | 78,344,192 | 71,229,440 | -9.08% | 11,751,629 | no | ok | +| `07_array_grow_evacuate` | wall_ms | 42 | 87 | +107.81% | 100 | no | ok | +| `08_map_set_sidetables` | heap_used_bytes | 688 | 688 | +0.00% | 65,536 | yes | ok | +| `08_map_set_sidetables` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `08_map_set_sidetables` | minor_cycles | 6 | 6 | +0.00% | 1 | yes | ok | +| `08_map_set_sidetables` | step_cycles | 6 | 6 | +0.00% | 1 | yes | ok | +| `08_map_set_sidetables` | copied_objects | 2,461 | 2,461 | +0.00% | 123 | yes | ok | +| `08_map_set_sidetables` | copied_bytes | 98,472 | 98,472 | +0.00% | 65,536 | yes | ok | +| `08_map_set_sidetables` | promoted_objects | 14 | 14 | +0.00% | 16 | yes | ok | +| `08_map_set_sidetables` | promoted_bytes | 592 | 592 | +0.00% | 65,536 | yes | ok | +| `08_map_set_sidetables` | freed_bytes | 56,598,904 | 56,598,904 | +0.00% | 2,829,945 | yes | ok | +| `08_map_set_sidetables` | rss_bytes | 53,194,752 | 52,191,232 | -1.89% | 8,388,608 | no | ok | +| `08_map_set_sidetables` | peak_rss_bytes | 63,270,912 | 62,234,624 | -1.64% | 9,490,637 | no | ok | +| `08_map_set_sidetables` | wall_ms | 213 | 186 | -12.60% | 100 | no | ok | +| `09_try_catch_roots` | heap_used_bytes | 443,520 | 443,520 | +0.00% | 65,536 | yes | ok | +| `09_try_catch_roots` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `09_try_catch_roots` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `09_try_catch_roots` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `09_try_catch_roots` | copied_objects | 6,673 | 6,673 | +0.00% | 334 | yes | ok | +| `09_try_catch_roots` | copied_bytes | 462,024 | 462,024 | +0.00% | 65,536 | yes | ok | +| `09_try_catch_roots` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `09_try_catch_roots` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `09_try_catch_roots` | freed_bytes | 10,023,568 | 10,023,568 | +0.00% | 1,048,576 | yes | ok | +| `09_try_catch_roots` | rss_bytes | 61,202,432 | 50,925,568 | -16.79% | 9,180,365 | no | improvement | +| `09_try_catch_roots` | peak_rss_bytes | 63,582,208 | 51,298,304 | -19.32% | 9,537,331 | no | improvement | +| `09_try_catch_roots` | wall_ms | 157 | 213 | +35.52% | 100 | no | ok | +| `10_store_receiver_across_alloc` | heap_used_bytes | 446,776 | 446,776 | +0.00% | 65,536 | yes | ok | +| `10_store_receiver_across_alloc` | heap_total_bytes | 22,020,096 | 22,020,096 | +0.00% | 1,048,576 | yes | ok | +| `10_store_receiver_across_alloc` | minor_cycles | 8 | 8 | +0.00% | 1 | yes | ok | +| `10_store_receiver_across_alloc` | step_cycles | 8 | 8 | +0.00% | 1 | yes | ok | +| `10_store_receiver_across_alloc` | copied_objects | 14,625 | 14,625 | +0.00% | 731 | yes | ok | +| `10_store_receiver_across_alloc` | copied_bytes | 787,792 | 787,792 | +0.00% | 65,536 | yes | ok | +| `10_store_receiver_across_alloc` | promoted_objects | 6,107 | 6,107 | +0.00% | 305 | yes | ok | +| `10_store_receiver_across_alloc` | promoted_bytes | 446,368 | 446,368 | +0.00% | 65,536 | yes | ok | +| `10_store_receiver_across_alloc` | freed_bytes | 88,640,584 | 88,640,584 | +0.00% | 4,432,029 | yes | ok | +| `10_store_receiver_across_alloc` | rss_bytes | 67,842,048 | 65,650,688 | -3.23% | 10,176,307 | no | ok | +| `10_store_receiver_across_alloc` | peak_rss_bytes | 74,194,944 | 71,938,048 | -3.04% | 11,129,242 | no | ok | +| `10_store_receiver_across_alloc` | wall_ms | 203 | 214 | +4.96% | 100 | no | ok | +| `11_collect_at_depth` | heap_used_bytes | 444,720 | 444,720 | +0.00% | 65,536 | yes | ok | +| `11_collect_at_depth` | heap_total_bytes | 12,582,912 | 12,582,912 | +0.00% | 1,048,576 | yes | ok | +| `11_collect_at_depth` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `11_collect_at_depth` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `11_collect_at_depth` | copied_objects | 6,686 | 6,686 | +0.00% | 334 | yes | ok | +| `11_collect_at_depth` | copied_bytes | 462,544 | 462,544 | +0.00% | 65,536 | yes | ok | +| `11_collect_at_depth` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `11_collect_at_depth` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `11_collect_at_depth` | freed_bytes | 8,974,576 | 8,974,576 | +0.00% | 1,048,576 | yes | ok | +| `11_collect_at_depth` | rss_bytes | 57,896,960 | 59,953,152 | +3.55% | 8,684,544 | no | ok | +| `11_collect_at_depth` | peak_rss_bytes | 61,542,400 | 62,853,120 | +2.13% | 9,231,360 | no | ok | +| `11_collect_at_depth` | wall_ms | 54 | 58 | +7.71% | 100 | no | ok | +| `12_large_live_set` | heap_used_bytes | 569,448 | 569,448 | +0.00% | 65,536 | yes | ok | +| `12_large_live_set` | heap_total_bytes | 74,448,896 | 74,448,896 | +0.00% | 1,488,978 | yes | ok | +| `12_large_live_set` | minor_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `12_large_live_set` | step_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `12_large_live_set` | copied_objects | 104,050 | 104,050 | +0.00% | 5,202 | yes | ok | +| `12_large_live_set` | copied_bytes | 4,162,008 | 4,162,008 | +0.00% | 208,100 | yes | ok | +| `12_large_live_set` | promoted_objects | 530,030 | 530,030 | +0.00% | 26,502 | yes | ok | +| `12_large_live_set` | promoted_bytes | 21,201,208 | 21,201,208 | +0.00% | 1,060,060 | yes | ok | +| `12_large_live_set` | freed_bytes | 63,732,784 | 63,732,784 | +0.00% | 3,186,639 | yes | ok | +| `12_large_live_set` | rss_bytes | 149,266,432 | 145,145,856 | -2.76% | 22,389,965 | no | ok | +| `12_large_live_set` | peak_rss_bytes | 165,412,864 | 157,700,096 | -4.66% | 24,811,930 | no | ok | +| `12_large_live_set` | wall_ms | 345 | 403 | +16.93% | 103 | no | ok | +| `13_large_eden_survivors` | heap_used_bytes | 444,976 | 444,976 | +0.00% | 65,536 | yes | ok | +| `13_large_eden_survivors` | heap_total_bytes | 61,865,984 | 61,865,984 | +0.00% | 1,237,320 | no | ok | +| `13_large_eden_survivors` | minor_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `13_large_eden_survivors` | step_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `13_large_eden_survivors` | copied_objects | 382,868 | 382,868 | +0.00% | 19,143 | yes | ok | +| `13_large_eden_survivors` | copied_bytes | 21,804,904 | 21,804,904 | +0.00% | 1,090,245 | yes | ok | +| `13_large_eden_survivors` | promoted_objects | 387,152 | 387,152 | +0.00% | 19,358 | yes | ok | +| `13_large_eden_survivors` | promoted_bytes | 21,975,560 | 21,975,560 | +0.00% | 1,098,778 | yes | ok | +| `13_large_eden_survivors` | freed_bytes | 108,045,936 | 108,045,936 | +0.00% | 5,402,297 | yes | ok | +| `13_large_eden_survivors` | rss_bytes | 161,558,528 | 156,545,024 | -3.10% | 24,233,779 | no | ok | +| `13_large_eden_survivors` | peak_rss_bytes | 190,017,536 | 176,799,744 | -6.96% | 28,502,630 | no | ok | +| `13_large_eden_survivors` | wall_ms | 978 | 1,148 | +17.37% | 294 | no | ok | +| `14_grow_then_churn` | heap_used_bytes | 429,408 | 429,408 | +0.00% | 65,536 | yes | ok | +| `14_grow_then_churn` | heap_total_bytes | 23,068,672 | 23,068,672 | +0.00% | 1,048,576 | yes | ok | +| `14_grow_then_churn` | minor_cycles | 22 | 22 | +0.00% | 1 | yes | ok | +| `14_grow_then_churn` | step_cycles | 23 | 23 | +0.00% | 1 | yes | ok | +| `14_grow_then_churn` | copied_objects | 330 | 330 | +0.00% | 16 | yes | ok | +| `14_grow_then_churn` | copied_bytes | 1,277,072 | 1,277,072 | +0.00% | 65,536 | yes | ok | +| `14_grow_then_churn` | promoted_objects | 405,282 | 405,282 | +0.00% | 20,264 | yes | ok | +| `14_grow_then_churn` | promoted_bytes | 147,967,848 | 147,967,848 | +0.00% | 7,398,392 | yes | ok | +| `14_grow_then_churn` | freed_bytes | 119,549,744 | 119,549,744 | +0.00% | 5,977,487 | yes | ok | +| `14_grow_then_churn` | rss_bytes | 154,632,192 | 154,738,688 | +0.07% | 23,194,829 | no | ok | +| `14_grow_then_churn` | peak_rss_bytes | 376,299,520 | 361,336,832 | -3.98% | 56,444,928 | no | ok | +| `14_grow_then_churn` | wall_ms | 464 | 997 | +115.05% | 139 | no | drift (informational) | + +### Cells excluded from the gating family by probe override + +- `07_array_grow_evacuate`.copied_bytes — NOT GATED ON THIS PROBE (#9790). Address-dependent promotion order changes old-block packing and the allocation boundary where nursery pressure is checked. The fifth minor observes a different live cohort: a completed 8,208-byte array or a new 144-byte array. Header-size sums and from-space reclamation account for the byte deltas; this is placement-dependent pacing, not an accounting discrepancy. Keep this cell visible; correctness, retention, cycle counts, object counts and promoted bytes remain gated. See evidence/9790-array-growth-pacing.json and the README investigation. (observed spread 8,064 over 21 runs, 2026-09-05, macOS arm64, Perry 0.5.1520; 21 executions of one unchanged binary. Compiler/runtime hashes and raw counters: benchmarks/gc_ratchet/evidence/9790-array-growth-pacing.json.; https://github.com/PerryTS/perry/issues/9790) +- `07_array_grow_evacuate`.freed_bytes — NOT GATED ON THIS PROBE (#9790). Address-dependent promotion order changes old-block packing and the allocation boundary where nursery pressure is checked. The fifth minor observes a different live cohort: a completed 8,208-byte array or a new 144-byte array. Header-size sums and from-space reclamation account for the byte deltas; this is placement-dependent pacing, not an accounting discrepancy. Keep this cell visible; correctness, retention, cycle counts, object counts and promoted bytes remain gated. See evidence/9790-array-growth-pacing.json and the README investigation. (observed spread 8,208 over 21 runs, 2026-09-05, macOS arm64, Perry 0.5.1520; 21 executions of one unchanged binary. Compiler/runtime hashes and raw counters: benchmarks/gc_ratchet/evidence/9790-array-growth-pacing.json.; https://github.com/PerryTS/perry/issues/9790) +- `13_large_eden_survivors`.heap_total_bytes — NOT GATED ON THIS PROBE (#9829). Total reserved arena capacity varies by 2 MiB across executions of one unchanged binary: 18/21 runs reserve 61865984 bytes and 3/21 reserve 63963136. All 21 report the same 227048 live bytes and identical seven GC counters (including three minors and 377569 copied objects), with Node-equivalent output. js_arena_stats sums reserved block sizes for heapTotal, separately from its exact live-object census for heapUsed. This is spare-capacity/placement variation, not changing live retention or GC work; the precise allocating block/order is not isolated. CI run 33989581881 independently contains the same two capacities. Keep the cell visible, while heapUsed, liveness, copying/promotion/reclamation, and all other probes remain gated. Raw 21-run evidence and binary/source hashes: evidence/9829-recovery.json. (observed spread 2,097,152 over 21 runs, 2026-09-06, linux-x86_64, clean main d36a1af0c compiler and matching runtime/stdlib archives. One unchanged probe binary, 21 traced executions with PERRY_GC_SCAVENGE_NURSERY_MB=64. See evidence/9829-recovery.json capacity_variance.; https://github.com/PerryTS/perry/issues/9829) + +gc-ratchet: OK diff --git a/benchmarks/catch_frames/evidence/guard-gc-ratchet.json.gz b/benchmarks/catch_frames/evidence/guard-gc-ratchet.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..90ceee4278a847a67df2dc872a40632a2f23c9f8 GIT binary patch literal 7034 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 YQgu&&?tE4L`{k?u18YtW8He)#065ow$p8QV literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/guard-gc-stress-summary.txt b/benchmarks/catch_frames/evidence/guard-gc-stress-summary.txt new file mode 100644 index 0000000000..3f01226fb8 --- /dev/null +++ b/benchmarks/catch_frames/evidence/guard-gc-stress-summary.txt @@ -0,0 +1,16 @@ +6 moved-objects 27/86 copy-minor 27/86 + +byte-exact vs node 26.5.1: 602/602 cells (the parity property) +summary: PASS=431 UNVER=171 XFAIL=0 FAIL=0 + (pressure=8MB, node 26.5.1, target/release/perry) + UNVER = output matched but the arm was inert here; see #6942 / #6946 / #6950. +json: /root/js-throw-evidence/guard-gc-stress.json + +liveness gate (#7255): every arm must have exercised what it claims + default requires=scavenge live 48/86 counter=2501055 live + safepoint_minor requires=scavenge live 48/86 counter=2499989 live + evac_minor requires=move live 62/86 counter=2568821 live + verify_evac requires=scavenge live 53/86 counter=2861200 live + force_verify requires=move live 86/86 counter=3726742 live + cons_scan_off requires=scavenge live 48/86 counter=2534812 live + shipped_default requires=none live 0/86 counter=0 n/a diff --git a/benchmarks/catch_frames/evidence/guard-gc-stress.json.gz b/benchmarks/catch_frames/evidence/guard-gc-stress.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..8f883c8a85d2ce8009ec6173614d4eed75660f88 GIT binary patch literal 7263 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/host-warnings-comparison.json b/benchmarks/catch_frames/evidence/host-warnings-comparison.json new file mode 100644 index 0000000000..4c0680be68 --- /dev/null +++ b/benchmarks/catch_frames/evidence/host-warnings-comparison.json @@ -0,0 +1,20 @@ +[ + { + "side": "baseline", + "exit_code": 101, + "errors": [ + "error: function `registered_extern_handle` is never used", + "error: function `wasm_memory_descriptor_maximum` is never used", + "error: could not compile `perry-runtime` (lib) due to 2 previous errors" + ] + }, + { + "side": "fix", + "exit_code": 101, + "errors": [ + "error: function `registered_extern_handle` is never used", + "error: function `wasm_memory_descriptor_maximum` is never used", + "error: could not compile `perry-runtime` (lib) due to 2 previous errors" + ] + } +] diff --git a/benchmarks/catch_frames/evidence/instructions.json b/benchmarks/catch_frames/evidence/instructions.json new file mode 100644 index 0000000000..e06fefd73c --- /dev/null +++ b/benchmarks/catch_frames/evidence/instructions.json @@ -0,0 +1,167 @@ +{ + "date": "2026-09-14", + "baseline_commit": "eb13fa188d", + "instruction_event": "instructions:u", + "stat_repeats": 3, + "record_period": 1000003, + "record_call_graph": "dwarf", + "perf_script_inline_expansion": false, + "node_version": "26.5.1", + "workloads": { + "catch": { + "baseline": { + "instructions": 472151423.0, + "samples": 472, + "capture_samples": 15, + "transport_leaf_samples": 112, + "capture_percent": 3.1779661016949152 + }, + "candidate": { + "instructions": 351152420.0, + "samples": 351, + "capture_samples": 6, + "transport_leaf_samples": 43, + "capture_percent": 1.7094017094017093 + }, + "instruction_change_percent": -25.627160505243253, + "net_instructions_per_iteration": { + "baseline": 445.083186, + "candidate": 324.083431, + "change_percent": -27.18587419296491 + } + }, + "exec1": { + "baseline": { + "instructions": 31217404185.0, + "samples": 31217, + "capture_samples": 1559, + "transport_leaf_samples": 1162, + "capture_percent": 4.994073741871416 + }, + "candidate": { + "instructions": 30183325430.0, + "samples": 30182, + "capture_samples": 999, + "transport_leaf_samples": 1080, + "capture_percent": 3.309919819760122 + }, + "instruction_change_percent": -3.3125071798790873 + }, + "hoist": { + "baseline": { + "instructions": 13816754889.0, + "samples": 13816, + "capture_samples": 1342, + "transport_leaf_samples": 422, + "capture_percent": 9.713375796178344 + }, + "candidate": { + "instructions": 13266297479.0, + "samples": 13263, + "capture_samples": 447, + "transport_leaf_samples": 483, + "capture_percent": 3.3702782175978285 + }, + "instruction_change_percent": -3.9839847664825956, + "baseline_frame_pushes": 3500011 + }, + "json": { + "baseline": { + "instructions": 3182841469.0, + "samples": 3182, + "capture_samples": 0, + "transport_leaf_samples": 0, + "capture_percent": 0.0 + }, + "candidate": { + "instructions": 3171165684.0, + "samples": 3168, + "capture_samples": 0, + "transport_leaf_samples": 0, + "capture_percent": 0.0 + }, + "instruction_change_percent": -0.3668352669688013, + "baseline_frame_pushes": 6 + }, + "plain": { + "baseline": { + "instructions": 27068237.0, + "samples": 27, + "capture_samples": 0, + "transport_leaf_samples": 0, + "capture_percent": 0.0 + }, + "candidate": { + "instructions": 27068989.0, + "samples": 26, + "capture_samples": 0, + "transport_leaf_samples": 0, + "capture_percent": 0.0 + }, + "instruction_change_percent": 0.0027781639417412407 + }, + "promises": { + "baseline": { + "instructions": 1098667245.0, + "samples": 1098, + "capture_samples": 29, + "transport_leaf_samples": 3, + "capture_percent": 2.6411657559198543 + }, + "candidate": { + "instructions": 1077465852.0, + "samples": 1077, + "capture_samples": 4, + "transport_leaf_samples": 0, + "capture_percent": 0.3714020427112349 + }, + "instruction_change_percent": -1.929737424728628, + "baseline_frame_pushes": 100007 + }, + "unwind": { + "baseline": { + "instructions": 366173508.0, + "samples": 364, + "capture_samples": 99, + "transport_leaf_samples": 0, + "capture_percent": 27.197802197802197 + }, + "candidate": { + "instructions": 244175238.0, + "samples": 244, + "capture_samples": 129, + "transport_leaf_samples": 0, + "capture_percent": 52.868852459016395 + }, + "instruction_change_percent": -33.317066181641955, + "net_instructions_per_iteration": { + "baseline": 339.105271, + "candidate": 217.106249, + "change_percent": -35.97674009614554 + } + } + }, + "artifacts": { + "baseline": { + "libperry_runtime.a": "66f3bcedf157f483a14bbb7023a0edec65f7ee91b520f20910f0b404266a4d33", + "libperry_stdlib.a": "4b1898b5fff251ec3244a11adce07893cd86dd28d6d352c6fd2b80c811e4d8d9", + "perry": "46cea1d5ccc54556d0d301641567cf6879a794d2707ee01ba25fa8f60cbf48ab" + }, + "candidate": { + "perry": "08a1aff537958e855fbdf5b9f25ccd22deb3cc3fc1a97c2f3063ed98dd2cbd9d", + "libperry_runtime.a": "2c0b05fbad66bb569241ccf742831504c9ef8c4819a31845c3d92c70d0efaa72", + "libperry_stdlib.a": "86ffd21fcd187c748661fd85015d6824998a43f70610b98b98cb7e8fd86a0206" + } + }, + "folded_stack_format": "semicolon-delimited frames, space, sample count", + "host": { + "cpu": "AMD Ryzen 7 7700X 8-Core Processor", + "logical_cpus": 16, + "kernel": "Linux 6.17.0-23-generic", + "perf": "6.17.13", + "rustc": "1.100.0-nightly (f7d782a3b 2026-08-19)", + "llvm": 22 + }, + "source_provenance_note": "Final measurements and full integration use the same frozen three-package compiler/archive build, including the constructor identity guard. Extra GC extension builds were made only after freezing these artifacts.", + "reviewed_crates_patch_sha256": "1f75da852b8a0f725da2977548ff194ca7833f2e76504d3c389d25bcbc6d43b6" +} diff --git a/benchmarks/catch_frames/evidence/integration-allowlist-diff.json b/benchmarks/catch_frames/evidence/integration-allowlist-diff.json new file mode 100644 index 0000000000..fe2a88b974 --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-allowlist-diff.json @@ -0,0 +1,16 @@ +{ + "platform": "linux", + "unlisted_failures": [ + "test_bun_plugin", + "test_dynamic_import_data_10104", + "test_gap_2899_2779_2777_static_helpers", + "test_gap_disposablestack_2875", + "test_gap_iterator_prototype_next_patch", + "test_issue_10155_textfield_singleline", + "test_issue_336_class_keys_collision", + "test_sock_write_map" + ], + "stale": [], + "schema": [], + "adjudicated": 116 +} diff --git a/benchmarks/catch_frames/evidence/integration-checks.json b/benchmarks/catch_frames/evidence/integration-checks.json new file mode 100644 index 0000000000..4ef81fa642 --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-checks.json @@ -0,0 +1,77 @@ +[ + { + "check": "merge", + "command": [ + "python3", + "scripts/parity_report_merge.py", + "--expect", + "4", + "--output", + "/root/js-throw-evidence/final-integration/parity.json", + "/root/js-throw-evidence/full-parity-1.json", + "/root/js-throw-evidence/full-parity-2.json", + "/root/js-throw-evidence/full-parity-3.json", + "/root/js-throw-evidence/full-parity-4.json" + ], + "exit_code": 0 + }, + { + "check": "known-failures", + "command": [ + "python3", + "scripts/parity_known_failures.py", + "--report", + "/root/js-throw-evidence/final-integration/parity.json", + "--platform", + "linux" + ], + "exit_code": 1 + }, + { + "check": "gap-snapshot", + "command": [ + "python3", + "scripts/gap_snapshot.py", + "check", + "--report", + "/root/js-throw-evidence/final-integration/gap.json", + "--snapshot", + "test-parity/gap_snapshot.json" + ], + "exit_code": 1 + }, + { + "check": "threshold", + "command": [ + "python3", + "scripts/parity_threshold_gate.py", + "--check", + "--report", + "/root/js-throw-evidence/final-integration/parity.json", + "--output-json", + "/root/js-throw-evidence/final-integration/threshold.json", + "--output-md", + "/root/js-throw-evidence/final-integration/threshold.md" + ], + "exit_code": 0 + }, + { + "check": "matrix-trend", + "command": [ + "python3", + "scripts/parity_matrix_trend.py", + "--check", + "--report", + "/root/js-throw-evidence/final-integration/parity.json", + "--platform", + "linux", + "--output-dir", + "/root/js-throw-evidence/final-integration/output", + "--output-json", + "/root/js-throw-evidence/final-integration/matrix-trend.json", + "--output-md", + "/root/js-throw-evidence/final-integration/matrix-trend.md" + ], + "exit_code": 0 + } +] diff --git a/benchmarks/catch_frames/evidence/integration-coverage.json b/benchmarks/catch_frames/evidence/integration-coverage.json new file mode 100644 index 0000000000..e987328c64 --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-coverage.json @@ -0,0 +1,26 @@ +{ + "expected_all": 1633, + "reported_all": 1633, + "expected_gap": 785, + "reported_gap": 785, + "parity_summary": { + "parity_pass": 1472, + "parity_fail": 93, + "compile_fail": 29, + "crash_fail": 2, + "node_fail": 5, + "skipped": 32, + "total_run": 1567, + "parity_percentage": 93.9 + }, + "gap_summary": { + "parity_pass": 776, + "parity_fail": 9, + "compile_fail": 0, + "crash_fail": 0, + "node_fail": 0, + "skipped": 0, + "total_run": 785, + "parity_percentage": 98.8 + } +} diff --git a/benchmarks/catch_frames/evidence/integration-gap-snapshot.log b/benchmarks/catch_frames/evidence/integration-gap-snapshot.log new file mode 100644 index 0000000000..042bd5979d --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-gap-snapshot.log @@ -0,0 +1,9 @@ + +REGRESSIONS — these were expected to pass: + - test_gap_2899_2779_2777_static_helpers: pass -> parity_fail + - test_gap_disposablestack_2875: pass -> parity_fail + - test_gap_iterator_prototype_next_patch: pass -> parity_fail + +Fix the regressions, then accept the rest with: + UPDATE_SNAPSHOT=1 ./scripts/run_gap_tests.sh +and commit test-parity/gap_snapshot.json. diff --git a/benchmarks/catch_frames/evidence/integration-known-failures.log b/benchmarks/catch_frames/evidence/integration-known-failures.log new file mode 100644 index 0000000000..e99f95caa5 --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-known-failures.log @@ -0,0 +1,9 @@ +NEW FAILURES on linux (not allowed for this platform): + - test_bun_plugin + - test_dynamic_import_data_10104 + - test_gap_2899_2779_2777_static_helpers + - test_gap_disposablestack_2875 + - test_gap_iterator_prototype_next_patch + - test_issue_10155_textfield_singleline + - test_issue_336_class_keys_collision + - test_sock_write_map diff --git a/benchmarks/catch_frames/evidence/integration-matrix-trend.md b/benchmarks/catch_frames/evidence/integration-matrix-trend.md new file mode 100644 index 0000000000..df9bf091c1 --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-matrix-trend.md @@ -0,0 +1,130 @@ +# Parity Matrix Trend + +| module | status | known | node_lines | perry_lines | diff_lines | +| --- | --- | --- | ---: | ---: | ---: | +| 684_type_only_namespace_collision | pass | no | 2 | 2 | 0 | +| 9023_transitive_class_collections | pass | no | 4 | 4 | 0 | +| 9023_transitive_class_defaults | pass | no | 6 | 6 | 0 | +| argon2 | pass | no | 19 | 7 | 26 | +| array_property_index_set_4150 | pass | no | 1 | 1 | 0 | +| assert | pass | no | 39 | 39 | 0 | +| async_context | pass | no | 49 | 49 | 0 | +| async_gen_await_in_conditional_6728 | pass | no | 4 | 4 | 0 | +| async_hooks | pass | no | 21 | 21 | 0 | +| async_local_storage | pass | no | 9 | 9 | 0 | +| async_semantic_3583 | pass | no | 7 | 7 | 0 | +| async_try_catch_after_await_4036 | pass | no | 7 | 7 | 0 | +| buffer | pass | no | 137 | 137 | 0 | +| builtin_static_name_length_3655 | pass | no | 1 | 1 | 0 | +| chained_cross_module_getter | pass | no | 2 | 2 | 0 | +| child_process | pass | no | 39 | 39 | 0 | +| class_expr_capture_refresh_6604 | pass | no | 7 | 7 | 0 | +| class_field_async_arrow_6728 | pass | no | 7 | 7 | 0 | +| cluster | parity_fail | yes | 17 | 17 | 4 | +| commander | parity_fail | yes | 19 | 8 | 27 | +| cron | parity_fail | yes | 8 | 7 | 15 | +| cross_module_getter | pass | no | 3 | 3 | 0 | +| crypto | parity_fail | yes | 51 | 51 | 6 | +| ctor_method_self_bind_not_field | pass | no | 1 | 1 | 0 | +| ctor_return_override_standalone | pass | no | 1 | 1 | 0 | +| date_fns | parity_fail | yes | 19 | 13 | 32 | +| dayjs | parity_fail | yes | 26 | 26 | 22 | +| decimal | parity_fail | yes | 19 | 30 | 49 | +| defineproperty_prototype_getter_this | pass | no | 1 | 1 | 0 | +| derived_constructor_arrow_new_4150 | pass | no | 1 | 1 | 0 | +| descriptor_decode | pass | no | 14 | 14 | 0 | +| destructuring_iterator_assignment | pass | no | 1 | 1 | 0 | +| dgram | pass | no | 38 | 38 | 0 | +| diagnostics_channel | pass | no | 23 | 23 | 0 | +| dns | pass | no | 110 | 110 | 0 | +| dns_promises | pass | no | 76 | 76 | 0 | +| dotenv | parity_fail | yes | 19 | 9 | 28 | +| effect_number_isfinite_property_path | pass | no | 1 | 1 | 0 | +| ethers | pass | no | 21 | 9 | 28 | +| export_const_static_field_alias | pass | no | 1 | 1 | 0 | +| fetch_binary_body_round_trip | pass | no | 4 | 4 | 0 | +| function_bind_value_reflect_apply | pass | no | 1 | 1 | 0 | +| headers_handle_field_probe_segfault | pass | no | 1 | 1 | 0 | +| headers_iterator_handle_segfault | pass | no | 1 | 1 | 0 | +| http | pass | no | 162 | 162 | 0 | +| http2 | pass | no | 51 | 51 | 0 | +| https | pass | no | 23 | 23 | 0 | +| imported_function_static_property | pass | no | 1 | 1 | 0 | +| imported_inherited_accessor_datatexture | pass | no | 1 | 1 | 0 | +| inherited_ctor_arg_forwarding | pass | no | 1 | 1 | 0 | +| inline_closure_capturing_local | pass | no | 1 | 1 | 0 | +| lodash | parity_fail | yes | 19 | 5 | 24 | +| lru_cache | parity_fail | yes | 19 | 15 | 34 | +| map_set_semantics_3989 | pass | no | 1 | 1 | 0 | +| math_random_bind_4120 | pass | no | 3 | 3 | 0 | +| method_value_snapshot_bind | pass | no | 13 | 1 | 14 | +| module | pass | no | 38 | 38 | 0 | +| moment | parity_fail | yes | 29 | 2 | 31 | +| multi_await_throw_no_orphan_rejection_6728 | pass | no | 2 | 2 | 0 | +| namespace_const_cross_module | pass | no | 27 | 1 | 28 | +| namespace_import_enumerable | pass | no | 1 | 1 | 0 | +| namespace_reexport_binding | pass | no | 1 | 1 | 0 | +| nanoid | parity_fail | yes | 19 | 9 | 28 | +| native_class_semantics_reduced | pass | no | 1 | 1 | 0 | +| native_value_profile | pass | no | 19 | 1 | 20 | +| net | pass | no | 75 | 75 | 0 | +| new_array_index_set_4150 | pass | no | 1 | 1 | 0 | +| numeric_enum_reverse_mapping_4509 | pass | no | 24 | 1 | 25 | +| object_assign_function_source | pass | no | 1 | 1 | 0 | +| object_ctor_inherited_proto_methods | pass | no | 1 | 1 | 0 | +| object_literal_getter_this_binding | pass | no | 1 | 1 | 0 | +| object_shorthand_imported_binding | pass | no | 1 | 1 | 0 | +| optional_chain_double_member_call | pass | no | 6 | 6 | 0 | +| os | pass | no | 10 | 10 | 0 | +| path | pass | no | 42 | 42 | 0 | +| perf_hooks | pass | no | 32 | 32 | 0 | +| process | pass | no | 60 | 60 | 0 | +| proxy_field_ic_miss | pass | no | 1 | 1 | 0 | +| proxy_fused_method_call | pass | no | 1 | 1 | 0 | +| proxy_getprototypeof_instanceof | pass | no | 1 | 1 | 0 | +| proxy_symbol_property | pass | no | 1 | 1 | 0 | +| querystring | pass | no | 16 | 16 | 0 | +| readline | pass | no | 19 | 19 | 0 | +| readline_promises | pass | no | 4 | 4 | 0 | +| regex_has_indices | pass | no | 10 | 10 | 0 | +| regex_replace_fn_lookahead | pass | no | 1 | 1 | 0 | +| request_subclass_body | pass | no | 7 | 7 | 0 | +| request_subclass_stream_body | pass | no | 13 | 4 | 11 | +| sqlite | pass | no | 51 | 51 | 0 | +| sqlite_backup_file | pass | no | 19 | 19 | 0 | +| sqlite_custom_functions_authorizers | pass | no | 34 | 34 | 0 | +| sqlite_database_sync_core | pass | no | 41 | 41 | 0 | +| sqlite_database_sync_extension_controls | pass | no | 12 | 12 | 0 | +| sqlite_sessions_constants | pass | no | 33 | 33 | 0 | +| sqlite_sqltagstore | pass | no | 21 | 21 | 0 | +| sqlite_statement_sync_core | pass | no | 45 | 45 | 0 | +| stream | pass | no | 80 | 80 | 0 | +| stream_consumers | pass | no | 9 | 9 | 0 | +| stream_promises | pass | no | 4 | 4 | 0 | +| stream_web | crash | yes | 43 | 1 | 44 | +| streams_byob | pass | no | 14 | 14 | 0 | +| string_append_surrogate_repair | pass | no | 7 | 7 | 0 | +| string_decoder | pass | no | 12 | 12 | 0 | +| subclass_builtin_field_init | pass | no | 1 | 1 | 0 | +| subclass_own_field_init_after_super | pass | no | 1 | 1 | 0 | +| sys | pass | no | 7 | 7 | 2 | +| test | pass | no | 80 | 80 | 0 | +| timers | pass | no | 20 | 20 | 0 | +| timers_promises | pass | no | 3 | 3 | 0 | +| tls | pass | no | 17 | 17 | 0 | +| try_block_no_leak_on_return | pass | no | 2 | 2 | 0 | +| try_catch_across_await | pass | no | 5 | 5 | 0 | +| undici_from_char_code_apply | pass | no | 1 | 1 | 0 | +| url | pass | no | 59 | 57 | 2 | +| user_method_named_sort | pass | no | 1 | 1 | 0 | +| util | parity_fail | yes | 275 | 283 | 154 | +| uuid | parity_fail | yes | 19 | 16 | 35 | +| v8_lifecycle | pass | no | 19 | 19 | 0 | +| validator | parity_fail | yes | 19 | 2 | 21 | +| vm | pass | no | 2 | 2 | 0 | +| webassembly_graceful_fail_default | pass | no | 5 | 8 | 11 | +| worker_threads | pass | no | 35 | 35 | 0 | +| xmod_empty_imported_derived_arg_forward | pass | no | 7 | 7 | 0 | +| xmod_imported_multilevel_ctor_state | pass | no | 8 | 8 | 0 | +| xmod_imported_zero_arg_super | pass | no | 4 | 4 | 0 | +| zlib | pass | no | 92 | 92 | 0 | diff --git a/benchmarks/catch_frames/evidence/integration-threshold.md b/benchmarks/catch_frames/evidence/integration-threshold.md new file mode 100644 index 0000000000..d72c87726c --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-threshold.md @@ -0,0 +1,133 @@ +# Parity Threshold Gate + +| category | parity | threshold | pass | parity_fail | compile_fail | node_fail | skipped | source | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | +| legacy/gap | 98.9% | 98.5% | 776 | 9 | 0 | 0 | 0 | configured | +| legacy/issue | 83.7% | 81.0% | 307 | 43 | 17 | 1 | 10 | configured | +| legacy/other | 88.0% | 87.5% | 279 | 26 | 12 | 4 | 22 | configured | +| parity/684_type_only_namespace_collision | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/9023_transitive_class_collections | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/9023_transitive_class_defaults | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/argon2 | 100.0% | 0.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/array_property_index_set_4150 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/assert | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/async_context | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/async_gen_await_in_conditional_6728 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/async_hooks | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/async_local_storage | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/async_semantic_3583 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/async_try_catch_after_await_4036 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/buffer | 100.0% | 0.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/builtin_static_name_length_3655 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/chained_cross_module_getter | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/child_process | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/class_expr_capture_refresh_6604 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/class_field_async_arrow_6728 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/cluster | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/commander | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/cron | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/cross_module_getter | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/crypto | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/ctor_method_self_bind_not_field | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/ctor_return_override_standalone | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/date_fns | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/dayjs | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/decimal | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/defineproperty_prototype_getter_this | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/derived_constructor_arrow_new_4150 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/descriptor_decode | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/destructuring_iterator_assignment | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/dgram | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/diagnostics_channel | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/dns | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/dns_promises | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/dotenv | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/effect_number_isfinite_property_path | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/ethers | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/export_const_static_field_alias | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/fetch_binary_body_round_trip | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/function_bind_value_reflect_apply | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/headers_handle_field_probe_segfault | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/headers_iterator_handle_segfault | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/http | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/http2 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/https | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/imported_function_static_property | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/imported_inherited_accessor_datatexture | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/inherited_ctor_arg_forwarding | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/inline_closure_capturing_local | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/lodash | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/lru_cache | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/map_set_semantics_3989 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/math_random_bind_4120 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/method_value_snapshot_bind | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/module | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/moment | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/multi_await_throw_no_orphan_rejection_6728 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/namespace_const_cross_module | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/namespace_import_enumerable | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/namespace_reexport_binding | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/nanoid | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/native_class_semantics_reduced | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/native_value_profile | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/net | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/new_array_index_set_4150 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/numeric_enum_reverse_mapping_4509 | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/object_assign_function_source | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/object_ctor_inherited_proto_methods | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/object_literal_getter_this_binding | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/object_shorthand_imported_binding | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/optional_chain_double_member_call | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/os | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/path | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/perf_hooks | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/process | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/proxy_field_ic_miss | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/proxy_fused_method_call | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/proxy_getprototypeof_instanceof | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/proxy_symbol_property | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/querystring | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/readline | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/readline_promises | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/regex_has_indices | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/regex_replace_fn_lookahead | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/request_subclass_body | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/request_subclass_stream_body | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/sqlite_backup_file | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite_custom_functions_authorizers | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite_database_sync_core | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite_database_sync_extension_controls | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite_sessions_constants | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite_sqltagstore | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sqlite_statement_sync_core | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/stream | 100.0% | 0.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/stream_consumers | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/stream_promises | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/stream_web | | 0.0% | 0 | 0 | 0 | 0 | 0 | configured | +| parity/streams_byob | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/string_append_surrogate_repair | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/string_decoder | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/subclass_builtin_field_init | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/subclass_own_field_init_after_super | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/sys | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/test | 100.0% | 0.0% | 1 | 0 | 0 | 0 | 0 | configured | +| parity/timers | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/timers_promises | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/tls | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/try_block_no_leak_on_return | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/try_catch_across_await | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/undici_from_char_code_apply | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/url | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/user_method_named_sort | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/util | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/uuid | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/v8_lifecycle | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/validator | 0.0% | 0.0% | 0 | 1 | 0 | 0 | 0 | configured | +| parity/vm | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/webassembly_graceful_fail_default | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/worker_threads | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/xmod_empty_imported_derived_arg_forward | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/xmod_imported_multilevel_ctor_state | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/xmod_imported_zero_arg_super | 100.0% | 100.0% | 1 | 0 | 0 | 0 | 0 | default | +| parity/zlib | 100.0% | 0.0% | 1 | 0 | 0 | 0 | 0 | configured | diff --git a/benchmarks/catch_frames/evidence/integration-unlisted-baseline-comparison.json b/benchmarks/catch_frames/evidence/integration-unlisted-baseline-comparison.json new file mode 100644 index 0000000000..170b095810 --- /dev/null +++ b/benchmarks/catch_frames/evidence/integration-unlisted-baseline-comparison.json @@ -0,0 +1,42 @@ +[ + { + "test": "test_bun_plugin", + "baseline": "parity_fail", + "candidate": "parity_fail" + }, + { + "test": "test_dynamic_import_data_10104", + "baseline": "parity_fail", + "candidate": "parity_fail" + }, + { + "test": "test_gap_2899_2779_2777_static_helpers", + "baseline": "parity_fail", + "candidate": "parity_fail" + }, + { + "test": "test_gap_disposablestack_2875", + "baseline": "parity_fail", + "candidate": "parity_fail" + }, + { + "test": "test_gap_iterator_prototype_next_patch", + "baseline": "parity_fail", + "candidate": "parity_fail" + }, + { + "test": "test_issue_10155_textfield_singleline", + "baseline": "compile_fail", + "candidate": "compile_fail" + }, + { + "test": "test_issue_336_class_keys_collision", + "baseline": "parity_fail", + "candidate": "parity_fail" + }, + { + "test": "test_sock_write_map", + "baseline": "pass", + "candidate": "parity_fail" + } +] diff --git a/benchmarks/catch_frames/evidence/local-checks.json b/benchmarks/catch_frames/evidence/local-checks.json new file mode 100644 index 0000000000..b027f41efc --- /dev/null +++ b/benchmarks/catch_frames/evidence/local-checks.json @@ -0,0 +1,18 @@ +[ + { + "check": "runtime-tests", + "exit": 0 + }, + { + "check": "regex-off", + "exit": 0 + }, + { + "check": "clippy", + "exit": 101 + }, + { + "check": "lint", + "exit": 1 + } +] diff --git a/benchmarks/catch_frames/evidence/mac-gc-baseline-pinned-check.log b/benchmarks/catch_frames/evidence/mac-gc-baseline-pinned-check.log new file mode 100644 index 0000000000..5bce2c49cc --- /dev/null +++ b/benchmarks/catch_frames/evidence/mac-gc-baseline-pinned-check.log @@ -0,0 +1,235 @@ +gc-ratchet: FAILED + - 01_nursery_churn: heap_used_bytes 212,168 -> 438,744 (+106.79%), allowance 65,536 [increase] + - 01_nursery_churn: copied_objects 4,977 -> 6,690 (+34.42%), allowance 249 [either] + - 01_nursery_churn: copied_bytes 234,536 -> 466,392 (+98.86%), allowance 65,536 [either] + - 02_survivor_promotion: copied_objects 34,550 -> 37,366 (+8.15%), allowance 1,728 [either] + - 02_survivor_promotion: copied_bytes 1,450,992 -> 1,690,264 (+16.49%), allowance 72,550 [either] + - 04_dead_after_deep_stack: copied_objects 3,622 -> 2,666 (-26.39%), allowance 181 [either] + - 05_closure_capture: copied_objects 20,079 -> 14,285 (-28.86%), allowance 1,004 [either] + - 05_closure_capture: copied_bytes 743,384 -> 534,720 (-28.07%), allowance 65,536 [either] + - 05_closure_capture: promoted_objects 3,390 -> 6,154 (+81.53%), allowance 170 [either] + - 05_closure_capture: promoted_bytes 122,120 -> 221,624 (+81.48%), allowance 65,536 [either] + - 06_string_retention: copied_objects 298 -> 270 (-9.40%), allowance 16 [either] + - 07_array_grow_evacuate: heap_used_bytes 1,072,456 -> 1,211,232 (+12.94%), allowance 65,536 [increase] + - 07_array_grow_evacuate: copied_objects 4,991 -> 6,702 (+34.28%), allowance 250 [either] + - 07_array_grow_evacuate: promoted_objects 4,879 -> 6,154 (+26.13%), allowance 244 [either] + - 07_array_grow_evacuate: promoted_bytes 615,696 -> 841,048 (+36.60%), allowance 65,536 [either] + - 09_try_catch_roots: heap_used_bytes 212,168 -> 443,520 (+109.04%), allowance 65,536 [increase] + - 09_try_catch_roots: copied_objects 4,962 -> 6,673 (+34.48%), allowance 248 [either] + - 09_try_catch_roots: copied_bytes 230,352 -> 462,024 (+100.57%), allowance 65,536 [either] + - 09_try_catch_roots: freed_bytes 11,112,472 -> 10,023,568 (-9.80%), allowance 1,048,576 [either] + - 10_store_receiver_across_alloc: heap_used_bytes 220,384 -> 446,776 (+102.73%), allowance 65,536 [increase] + - 10_store_receiver_across_alloc: heap_total_bytes 16,777,216 -> 22,020,096 (+31.25%), allowance 1,048,576 [increase] + - 10_store_receiver_across_alloc: copied_objects 18,660 -> 14,625 (-21.62%), allowance 933 [either] + - 10_store_receiver_across_alloc: promoted_objects 4,722 -> 6,107 (+29.33%), allowance 236 [either] + - 10_store_receiver_across_alloc: promoted_bytes 228,440 -> 446,368 (+95.40%), allowance 65,536 [either] + - 11_collect_at_depth: heap_used_bytes 212,168 -> 444,720 (+109.61%), allowance 65,536 [increase] + - 11_collect_at_depth: copied_objects 4,975 -> 6,686 (+34.39%), allowance 249 [either] + - 11_collect_at_depth: copied_bytes 230,872 -> 462,544 (+100.35%), allowance 65,536 [either] + - 11_collect_at_depth: freed_bytes 10,062,936 -> 8,974,576 (-10.82%), allowance 1,048,576 [either] + - 12_large_live_set: copied_objects 59,405 -> 104,050 (+75.15%), allowance 2,970 [either] + - 12_large_live_set: copied_bytes 2,327,008 -> 4,162,008 (+78.86%), allowance 116,350 [either] +## GC ratchet + +- Profile: `shared_ci` +- Baseline commit: `f2ab19447194eeaa3cb47d968877745614024451` +- Baseline captured: 2026-08-16T09:38:07+00:00 on `darwin-arm64` +- Baseline host: Apple M1, 8 cores, load at capture 2.18 + +Only rows marked gating can fail the job. Non-gating rows are recorded so a +drift that is real but unmeasurable on this runner is still visible. + +Probes pinned under a non-default collector configuration: + +- `13_large_eden_survivors` — `PERRY_GC_SCAVENGE_NURSERY_MB=64` +- `14_grow_then_churn` — `PERRY_GC_MAJOR_PACING_FLOOR_MB=1 PERRY_GC_SCAVENGE_NURSERY_MB=1` + +Accepted deterministic baseline deltas: + +- `46` cells measured at `3e3e652e007ac853bf934daa86fa36c870b0e3e2` (2026-09-06T04:12:57+00:00) +- `06e1ab349c8c6e40587bb3ce2ee9f1c58b20522b` / PR #8657 — measured: array growth targets keep their generation +- `22c07ac5b44c5ff6a988257067110c7451da0223` / PR #9833 — measured: included receiver-store workload repair +- `5196d830fd0689937db94598d94662d531d4ee92` / PR #9706 — bracketed: Sep-4 shape storage and array packing +- `aa8d2ade03970ac7eb2065f3eb0e18bb4d2df1c7` / PR #9628 — bracketed: Sep-3 liveness and retention repair +- `b3e88f1fb3378fe30b065ed328b73ea0527ab18a` / PR #8806 — measured: cache exact shape transitions +- `d923b8dcf08f2afed71777c33423362411039cf0` / PR #9373 — measured: short-concat memo changes large-Eden occupancy +- `e18b24c420c7c2f389607537618699ffc6aa9d1d` / PR #8900 — measured: weak shape-transition target edges +- `e2e6f4a1cfded098ca05afe7e1b4e5ce783a5140` / PR #8313 — measured: smaller common objects +- `fc8c9e9a15902f889df2b1aeb280ca6223f6948a` / PR #8887 — bracketed: Aug-27/28 allocation and rooting specializations + +| Probe | Metric | Baseline | Current | Δ | Allowance | Gating | Status | +|-------|--------|---------:|--------:|---:|----------:|:------:|--------| +| `01_nursery_churn` | heap_used_bytes | 212,168 | 438,744 | +106.79% | 65,536 | yes | REGRESSION | +| `01_nursery_churn` | heap_total_bytes | 16,777,216 | 14,680,064 | -12.50% | 1,048,576 | yes | improvement | +| `01_nursery_churn` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `01_nursery_churn` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `01_nursery_churn` | copied_objects | 4,977 | 6,690 | +34.42% | 249 | yes | REGRESSION | +| `01_nursery_churn` | copied_bytes | 234,536 | 466,392 | +98.86% | 65,536 | yes | REGRESSION | +| `01_nursery_churn` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `01_nursery_churn` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `01_nursery_churn` | freed_bytes | 11,299,648 | 11,067,816 | -2.05% | 1,048,576 | yes | ok | +| `01_nursery_churn` | rss_bytes | 28,950,528 | 28,508,160 | -1.53% | 8,388,608 | no | ok | +| `01_nursery_churn` | peak_rss_bytes | 29,491,200 | 29,114,368 | -1.28% | 8,388,608 | no | ok | +| `01_nursery_churn` | wall_ms | 54 | 43 | -20.11% | 100 | no | ok | +| `02_survivor_promotion` | heap_used_bytes | 2,656,440 | 2,562,832 | -3.52% | 65,536 | yes | improvement | +| `02_survivor_promotion` | heap_total_bytes | 16,777,216 | 15,728,640 | -6.25% | 1,048,576 | yes | ok | +| `02_survivor_promotion` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `02_survivor_promotion` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `02_survivor_promotion` | copied_objects | 34,550 | 37,366 | +8.15% | 1,728 | yes | REGRESSION | +| `02_survivor_promotion` | copied_bytes | 1,450,992 | 1,690,264 | +16.49% | 72,550 | yes | REGRESSION | +| `02_survivor_promotion` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `02_survivor_promotion` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `02_survivor_promotion` | freed_bytes | 9,754,128 | 8,795,408 | -9.83% | 1,048,576 | yes | ok | +| `02_survivor_promotion` | rss_bytes | 32,522,240 | 31,358,976 | -3.58% | 8,388,608 | no | ok | +| `02_survivor_promotion` | peak_rss_bytes | 33,095,680 | 31,932,416 | -3.51% | 8,388,608 | no | ok | +| `02_survivor_promotion` | wall_ms | 57 | 48 | -15.94% | 100 | no | ok | +| `03_cross_gen_writes` | heap_used_bytes | 528 | 528 | +0.00% | 65,536 | yes | ok | +| `03_cross_gen_writes` | heap_total_bytes | 14,680,064 | 12,582,912 | -14.29% | 1,048,576 | yes | improvement | +| `03_cross_gen_writes` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `03_cross_gen_writes` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `03_cross_gen_writes` | copied_objects | 4,107 | 4,107 | +0.00% | 205 | yes | ok | +| `03_cross_gen_writes` | copied_bytes | 229,824 | 197,056 | -14.26% | 65,536 | yes | ok | +| `03_cross_gen_writes` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `03_cross_gen_writes` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `03_cross_gen_writes` | freed_bytes | 9,240,008 | 9,240,008 | +0.00% | 1,048,576 | yes | ok | +| `03_cross_gen_writes` | rss_bytes | 21,708,800 | 22,888,448 | +5.43% | 8,388,608 | no | ok | +| `03_cross_gen_writes` | peak_rss_bytes | 26,542,080 | 26,968,064 | +1.60% | 8,388,608 | no | ok | +| `03_cross_gen_writes` | wall_ms | 37 | 29 | -21.51% | 100 | no | ok | +| `04_dead_after_deep_stack` | heap_used_bytes | 536 | 536 | +0.00% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | heap_total_bytes | 20,971,520 | 18,874,368 | -10.00% | 1,048,576 | yes | improvement | +| `04_dead_after_deep_stack` | minor_cycles | 6 | 7 | +16.67% | 1 | yes | ok | +| `04_dead_after_deep_stack` | step_cycles | 6 | 7 | +16.67% | 1 | yes | ok | +| `04_dead_after_deep_stack` | copied_objects | 3,622 | 2,666 | -26.39% | 181 | yes | REGRESSION | +| `04_dead_after_deep_stack` | copied_bytes | 149,400 | 111,336 | -25.48% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | promoted_objects | 682 | 682 | +0.00% | 34 | yes | ok | +| `04_dead_after_deep_stack` | promoted_bytes | 440 | 27,320 | +6109.09% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | freed_bytes | 73,346,416 | 76,493,952 | +4.29% | 3,667,321 | yes | ok | +| `04_dead_after_deep_stack` | rss_bytes | 24,100,864 | 25,100,288 | +4.15% | 8,388,608 | no | ok | +| `04_dead_after_deep_stack` | peak_rss_bytes | 28,950,528 | 29,130,752 | +0.62% | 8,388,608 | no | ok | +| `04_dead_after_deep_stack` | wall_ms | 69 | 38 | -44.42% | 100 | no | ok | +| `05_closure_capture` | heap_used_bytes | 5,664 | 544 | -90.40% | 65,536 | yes | ok | +| `05_closure_capture` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `05_closure_capture` | minor_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `05_closure_capture` | step_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `05_closure_capture` | copied_objects | 20,079 | 14,285 | -28.86% | 1,004 | yes | REGRESSION | +| `05_closure_capture` | copied_bytes | 743,384 | 534,720 | -28.07% | 65,536 | yes | REGRESSION | +| `05_closure_capture` | promoted_objects | 3,390 | 6,154 | +81.53% | 170 | yes | REGRESSION | +| `05_closure_capture` | promoted_bytes | 122,120 | 221,624 | +81.48% | 65,536 | yes | REGRESSION | +| `05_closure_capture` | freed_bytes | 26,862,320 | 27,897,872 | +3.86% | 1,343,116 | yes | ok | +| `05_closure_capture` | rss_bytes | 19,169,280 | 23,265,280 | +21.37% | 8,388,608 | no | ok | +| `05_closure_capture` | peak_rss_bytes | 24,248,320 | 26,853,376 | +10.74% | 8,388,608 | no | ok | +| `05_closure_capture` | wall_ms | 68 | 50 | -26.11% | 100 | no | ok | +| `06_string_retention` | heap_used_bytes | 212,640 | 1,072 | -99.50% | 65,536 | yes | improvement | +| `06_string_retention` | heap_total_bytes | 23,068,672 | 22,020,096 | -4.55% | 1,048,576 | yes | ok | +| `06_string_retention` | minor_cycles | 5 | 4 | -20.00% | 1 | yes | ok | +| `06_string_retention` | step_cycles | 5 | 4 | -20.00% | 1 | yes | ok | +| `06_string_retention` | copied_objects | 298 | 270 | -9.40% | 16 | yes | REGRESSION | +| `06_string_retention` | copied_bytes | 72,288 | 70,144 | -2.97% | 65,536 | yes | ok | +| `06_string_retention` | promoted_objects | 14 | 14 | +0.00% | 16 | yes | ok | +| `06_string_retention` | promoted_bytes | 1,072 | 1,072 | +0.00% | 65,536 | yes | ok | +| `06_string_retention` | freed_bytes | 68,136,816 | 68,136,816 | +0.00% | 3,406,841 | yes | ok | +| `06_string_retention` | rss_bytes | 32,964,608 | 28,459,008 | -13.67% | 8,388,608 | no | ok | +| `06_string_retention` | peak_rss_bytes | 33,488,896 | 33,030,144 | -1.37% | 8,388,608 | no | ok | +| `06_string_retention` | wall_ms | 76 | 46 | -39.42% | 100 | no | ok | +| `07_array_grow_evacuate` | heap_used_bytes | 1,072,456 | 1,211,232 | +12.94% | 65,536 | yes | REGRESSION | +| `07_array_grow_evacuate` | heap_total_bytes | 25,165,824 | 25,165,824 | +0.00% | 1,048,576 | yes | ok | +| `07_array_grow_evacuate` | minor_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `07_array_grow_evacuate` | step_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `07_array_grow_evacuate` | copied_objects | 4,991 | 6,702 | +34.28% | 250 | yes | REGRESSION | +| `07_array_grow_evacuate` | copied_bytes | 2,671,936 | 2,636,392 | -1.33% | 133,597 | no | ok | +| `07_array_grow_evacuate` | promoted_objects | 4,879 | 6,154 | +26.13% | 244 | yes | REGRESSION | +| `07_array_grow_evacuate` | promoted_bytes | 615,696 | 841,048 | +36.60% | 65,536 | yes | REGRESSION | +| `07_array_grow_evacuate` | freed_bytes | 83,727,056 | 83,570,704 | -0.19% | 4,186,353 | no | ok | +| `07_array_grow_evacuate` | rss_bytes | 34,029,568 | 37,879,808 | +11.31% | 8,388,608 | no | ok | +| `07_array_grow_evacuate` | peak_rss_bytes | 34,553,856 | 38,486,016 | +11.38% | 8,388,608 | no | ok | +| `07_array_grow_evacuate` | wall_ms | 144 | 50 | -65.05% | 100 | no | ok | +| `08_map_set_sidetables` | heap_used_bytes | 672 | 688 | +2.38% | 65,536 | yes | ok | +| `08_map_set_sidetables` | heap_total_bytes | 16,777,216 | 14,680,064 | -12.50% | 1,048,576 | yes | improvement | +| `08_map_set_sidetables` | minor_cycles | 5 | 6 | +20.00% | 1 | yes | ok | +| `08_map_set_sidetables` | step_cycles | 5 | 6 | +20.00% | 1 | yes | ok | +| `08_map_set_sidetables` | copied_objects | 2,489 | 2,461 | -1.12% | 124 | yes | ok | +| `08_map_set_sidetables` | copied_bytes | 144,384 | 98,472 | -31.80% | 65,536 | yes | ok | +| `08_map_set_sidetables` | promoted_objects | 15 | 14 | -6.67% | 16 | yes | ok | +| `08_map_set_sidetables` | promoted_bytes | 576 | 592 | +2.78% | 65,536 | yes | ok | +| `08_map_set_sidetables` | freed_bytes | 57,655,296 | 56,598,904 | -1.83% | 2,882,765 | yes | ok | +| `08_map_set_sidetables` | rss_bytes | 21,037,056 | 19,906,560 | -5.37% | 8,388,608 | no | ok | +| `08_map_set_sidetables` | peak_rss_bytes | 25,329,664 | 24,608,768 | -2.85% | 8,388,608 | no | ok | +| `08_map_set_sidetables` | wall_ms | 171 | 176 | +3.17% | 100 | no | ok | +| `09_try_catch_roots` | heap_used_bytes | 212,168 | 443,520 | +109.04% | 65,536 | yes | REGRESSION | +| `09_try_catch_roots` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `09_try_catch_roots` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `09_try_catch_roots` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `09_try_catch_roots` | copied_objects | 4,962 | 6,673 | +34.48% | 248 | yes | REGRESSION | +| `09_try_catch_roots` | copied_bytes | 230,352 | 462,024 | +100.57% | 65,536 | yes | REGRESSION | +| `09_try_catch_roots` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `09_try_catch_roots` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `09_try_catch_roots` | freed_bytes | 11,112,472 | 10,023,568 | -9.80% | 1,048,576 | yes | REGRESSION | +| `09_try_catch_roots` | rss_bytes | 30,015,488 | 30,261,248 | +0.82% | 8,388,608 | no | ok | +| `09_try_catch_roots` | peak_rss_bytes | 30,457,856 | 30,736,384 | +0.91% | 8,388,608 | no | ok | +| `09_try_catch_roots` | wall_ms | 744 | 106 | -85.79% | 223 | no | improvement | +| `10_store_receiver_across_alloc` | heap_used_bytes | 220,384 | 446,776 | +102.73% | 65,536 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | heap_total_bytes | 16,777,216 | 22,020,096 | +31.25% | 1,048,576 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | minor_cycles | 9 | 8 | -11.11% | 1 | yes | ok | +| `10_store_receiver_across_alloc` | step_cycles | 9 | 8 | -11.11% | 1 | yes | ok | +| `10_store_receiver_across_alloc` | copied_objects | 18,660 | 14,625 | -21.62% | 933 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | copied_bytes | 825,520 | 787,792 | -4.57% | 65,536 | yes | ok | +| `10_store_receiver_across_alloc` | promoted_objects | 4,722 | 6,107 | +29.33% | 236 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | promoted_bytes | 228,440 | 446,368 | +95.40% | 65,536 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | freed_bytes | 88,858,544 | 88,640,584 | -0.25% | 4,442,927 | yes | ok | +| `10_store_receiver_across_alloc` | rss_bytes | 24,756,224 | 35,045,376 | +41.56% | 8,388,608 | no | drift (informational) | +| `10_store_receiver_across_alloc` | peak_rss_bytes | 25,296,896 | 35,569,664 | +40.61% | 8,388,608 | no | drift (informational) | +| `10_store_receiver_across_alloc` | wall_ms | 43 | 159 | +268.47% | 100 | no | drift (informational) | +| `11_collect_at_depth` | heap_used_bytes | 212,168 | 444,720 | +109.61% | 65,536 | yes | REGRESSION | +| `11_collect_at_depth` | heap_total_bytes | 13,631,488 | 12,582,912 | -7.69% | 1,048,576 | yes | ok | +| `11_collect_at_depth` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `11_collect_at_depth` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `11_collect_at_depth` | copied_objects | 4,975 | 6,686 | +34.39% | 249 | yes | REGRESSION | +| `11_collect_at_depth` | copied_bytes | 230,872 | 462,544 | +100.35% | 65,536 | yes | REGRESSION | +| `11_collect_at_depth` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `11_collect_at_depth` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `11_collect_at_depth` | freed_bytes | 10,062,936 | 8,974,576 | -10.82% | 1,048,576 | yes | REGRESSION | +| `11_collect_at_depth` | rss_bytes | 26,525,696 | 26,656,768 | +0.49% | 8,388,608 | no | ok | +| `11_collect_at_depth` | peak_rss_bytes | 26,984,448 | 27,295,744 | +1.15% | 8,388,608 | no | ok | +| `11_collect_at_depth` | wall_ms | 48 | 46 | -4.41% | 100 | no | ok | +| `12_large_live_set` | heap_used_bytes | 1,104,848 | 569,448 | -48.46% | 65,536 | yes | improvement | +| `12_large_live_set` | heap_total_bytes | 82,837,504 | 74,448,896 | -10.13% | 1,656,750 | yes | improvement | +| `12_large_live_set` | minor_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `12_large_live_set` | step_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `12_large_live_set` | copied_objects | 59,405 | 104,050 | +75.15% | 2,970 | yes | REGRESSION | +| `12_large_live_set` | copied_bytes | 2,327,008 | 4,162,008 | +78.86% | 116,350 | yes | REGRESSION | +| `12_large_live_set` | promoted_objects | 529,075 | 530,030 | +0.18% | 26,454 | yes | ok | +| `12_large_live_set` | promoted_bytes | 21,201,208 | 21,201,208 | +0.00% | 1,060,060 | yes | ok | +| `12_large_live_set` | freed_bytes | 63,732,784 | 63,732,784 | +0.00% | 3,186,639 | yes | ok | +| `12_large_live_set` | rss_bytes | 122,044,416 | 117,211,136 | -3.96% | 18,306,662 | no | ok | +| `12_large_live_set` | peak_rss_bytes | 124,665,856 | 120,307,712 | -3.50% | 18,699,878 | no | ok | +| `12_large_live_set` | wall_ms | 1,955 | 287 | -85.33% | 586 | no | improvement | +| `13_large_eden_survivors` | heap_used_bytes | 499,576 | 444,976 | -10.93% | 65,536 | yes | ok | +| `13_large_eden_survivors` | heap_total_bytes | 59,768,832 | 61,865,984 | +3.51% | 1,195,377 | no | drift (informational) | +| `13_large_eden_survivors` | minor_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `13_large_eden_survivors` | step_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `13_large_eden_survivors` | copied_objects | 377,569 | 382,868 | +1.40% | 18,878 | yes | ok | +| `13_large_eden_survivors` | copied_bytes | 21,429,712 | 21,804,904 | +1.75% | 1,071,486 | yes | ok | +| `13_large_eden_survivors` | promoted_objects | 386,271 | 387,152 | +0.23% | 19,314 | yes | ok | +| `13_large_eden_survivors` | promoted_bytes | 21,777,792 | 21,975,560 | +0.91% | 1,088,890 | yes | ok | +| `13_large_eden_survivors` | freed_bytes | 108,243,696 | 108,045,936 | -0.18% | 5,412,185 | yes | ok | +| `13_large_eden_survivors` | rss_bytes | 145,522,688 | 143,179,776 | -1.61% | 21,828,403 | no | ok | +| `13_large_eden_survivors` | peak_rss_bytes | 145,850,368 | 143,687,680 | -1.48% | 21,877,555 | no | ok | +| `13_large_eden_survivors` | wall_ms | 965 | 873 | -9.58% | 290 | no | ok | +| `14_grow_then_churn` | heap_used_bytes | 402,968 | 429,408 | +6.56% | 65,536 | yes | ok | +| `14_grow_then_churn` | heap_total_bytes | 23,068,672 | 23,068,672 | +0.00% | 1,048,576 | yes | ok | +| `14_grow_then_churn` | minor_cycles | 21 | 22 | +4.76% | 1 | yes | ok | +| `14_grow_then_churn` | step_cycles | 22 | 23 | +4.55% | 1 | yes | ok | +| `14_grow_then_churn` | copied_objects | 330 | 330 | +0.00% | 16 | yes | ok | +| `14_grow_then_churn` | copied_bytes | 1,222,176 | 1,277,072 | +4.49% | 65,536 | yes | ok | +| `14_grow_then_churn` | promoted_objects | 404,022 | 405,282 | +0.31% | 20,201 | yes | ok | +| `14_grow_then_churn` | promoted_bytes | 147,516,064 | 147,967,848 | +0.31% | 7,375,803 | yes | ok | +| `14_grow_then_churn` | freed_bytes | 118,903,288 | 119,549,744 | +0.54% | 5,945,164 | yes | ok | +| `14_grow_then_churn` | rss_bytes | 286,490,624 | 297,271,296 | +3.76% | 42,973,594 | no | ok | +| `14_grow_then_churn` | peak_rss_bytes | 286,834,688 | 297,779,200 | +3.82% | 43,025,203 | no | ok | +| `14_grow_then_churn` | wall_ms | 403 | 575 | +42.59% | 121 | no | drift (informational) | + +### Cells excluded from the gating family by probe override + +- `07_array_grow_evacuate`.copied_bytes — NOT GATED ON THIS PROBE (#9790). Address-dependent promotion order changes old-block packing and the allocation boundary where nursery pressure is checked. The fifth minor observes a different live cohort: a completed 8,208-byte array or a new 144-byte array. Header-size sums and from-space reclamation account for the byte deltas; this is placement-dependent pacing, not an accounting discrepancy. Keep this cell visible; correctness, retention, cycle counts, object counts and promoted bytes remain gated. See evidence/9790-array-growth-pacing.json and the README investigation. (observed spread 8,064 over 21 runs, 2026-09-05, macOS arm64, Perry 0.5.1520; 21 executions of one unchanged binary. Compiler/runtime hashes and raw counters: benchmarks/gc_ratchet/evidence/9790-array-growth-pacing.json.; https://github.com/PerryTS/perry/issues/9790) +- `07_array_grow_evacuate`.freed_bytes — NOT GATED ON THIS PROBE (#9790). Address-dependent promotion order changes old-block packing and the allocation boundary where nursery pressure is checked. The fifth minor observes a different live cohort: a completed 8,208-byte array or a new 144-byte array. Header-size sums and from-space reclamation account for the byte deltas; this is placement-dependent pacing, not an accounting discrepancy. Keep this cell visible; correctness, retention, cycle counts, object counts and promoted bytes remain gated. See evidence/9790-array-growth-pacing.json and the README investigation. (observed spread 8,208 over 21 runs, 2026-09-05, macOS arm64, Perry 0.5.1520; 21 executions of one unchanged binary. Compiler/runtime hashes and raw counters: benchmarks/gc_ratchet/evidence/9790-array-growth-pacing.json.; https://github.com/PerryTS/perry/issues/9790) +- `13_large_eden_survivors`.heap_total_bytes — NOT GATED ON THIS PROBE (#9829). Total reserved arena capacity varies by 2 MiB across executions of one unchanged binary: 18/21 runs reserve 61865984 bytes and 3/21 reserve 63963136. All 21 report the same 227048 live bytes and identical seven GC counters (including three minors and 377569 copied objects), with Node-equivalent output. js_arena_stats sums reserved block sizes for heapTotal, separately from its exact live-object census for heapUsed. This is spare-capacity/placement variation, not changing live retention or GC work; the precise allocating block/order is not isolated. CI run 33989581881 independently contains the same two capacities. Keep the cell visible, while heapUsed, liveness, copying/promotion/reclamation, and all other probes remain gated. Raw 21-run evidence and binary/source hashes: evidence/9829-recovery.json. (observed spread 2,097,152 over 21 runs, 2026-09-06, linux-x86_64, clean main d36a1af0c compiler and matching runtime/stdlib archives. One unchanged probe binary, 21 traced executions with PERRY_GC_SCAVENGE_NURSERY_MB=64. See evidence/9829-recovery.json capacity_variance.; https://github.com/PerryTS/perry/issues/9829) diff --git a/benchmarks/catch_frames/evidence/mac-gc-baseline.json.gz b/benchmarks/catch_frames/evidence/mac-gc-baseline.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..2fbc1069713d266555d10fbcfe82308a2afc3547 GIT binary patch literal 5958 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/mac-gc-guard-pinned-check.log b/benchmarks/catch_frames/evidence/mac-gc-guard-pinned-check.log new file mode 100644 index 0000000000..fe71e4e222 --- /dev/null +++ b/benchmarks/catch_frames/evidence/mac-gc-guard-pinned-check.log @@ -0,0 +1,235 @@ +gc-ratchet: FAILED + - 01_nursery_churn: heap_used_bytes 212,168 -> 438,744 (+106.79%), allowance 65,536 [increase] + - 01_nursery_churn: copied_objects 4,977 -> 6,690 (+34.42%), allowance 249 [either] + - 01_nursery_churn: copied_bytes 234,536 -> 466,392 (+98.86%), allowance 65,536 [either] + - 02_survivor_promotion: copied_objects 34,550 -> 37,366 (+8.15%), allowance 1,728 [either] + - 02_survivor_promotion: copied_bytes 1,450,992 -> 1,690,264 (+16.49%), allowance 72,550 [either] + - 04_dead_after_deep_stack: copied_objects 3,622 -> 2,666 (-26.39%), allowance 181 [either] + - 05_closure_capture: copied_objects 20,079 -> 14,285 (-28.86%), allowance 1,004 [either] + - 05_closure_capture: copied_bytes 743,384 -> 534,720 (-28.07%), allowance 65,536 [either] + - 05_closure_capture: promoted_objects 3,390 -> 6,154 (+81.53%), allowance 170 [either] + - 05_closure_capture: promoted_bytes 122,120 -> 221,624 (+81.48%), allowance 65,536 [either] + - 06_string_retention: copied_objects 298 -> 270 (-9.40%), allowance 16 [either] + - 07_array_grow_evacuate: heap_used_bytes 1,072,456 -> 1,211,232 (+12.94%), allowance 65,536 [increase] + - 07_array_grow_evacuate: copied_objects 4,991 -> 6,702 (+34.28%), allowance 250 [either] + - 07_array_grow_evacuate: promoted_objects 4,879 -> 6,154 (+26.13%), allowance 244 [either] + - 07_array_grow_evacuate: promoted_bytes 615,696 -> 841,048 (+36.60%), allowance 65,536 [either] + - 09_try_catch_roots: heap_used_bytes 212,168 -> 443,520 (+109.04%), allowance 65,536 [increase] + - 09_try_catch_roots: copied_objects 4,962 -> 6,673 (+34.48%), allowance 248 [either] + - 09_try_catch_roots: copied_bytes 230,352 -> 462,024 (+100.57%), allowance 65,536 [either] + - 09_try_catch_roots: freed_bytes 11,112,472 -> 10,023,568 (-9.80%), allowance 1,048,576 [either] + - 10_store_receiver_across_alloc: heap_used_bytes 220,384 -> 446,776 (+102.73%), allowance 65,536 [increase] + - 10_store_receiver_across_alloc: heap_total_bytes 16,777,216 -> 22,020,096 (+31.25%), allowance 1,048,576 [increase] + - 10_store_receiver_across_alloc: copied_objects 18,660 -> 14,625 (-21.62%), allowance 933 [either] + - 10_store_receiver_across_alloc: promoted_objects 4,722 -> 6,107 (+29.33%), allowance 236 [either] + - 10_store_receiver_across_alloc: promoted_bytes 228,440 -> 446,368 (+95.40%), allowance 65,536 [either] + - 11_collect_at_depth: heap_used_bytes 212,168 -> 444,720 (+109.61%), allowance 65,536 [increase] + - 11_collect_at_depth: copied_objects 4,975 -> 6,686 (+34.39%), allowance 249 [either] + - 11_collect_at_depth: copied_bytes 230,872 -> 462,544 (+100.35%), allowance 65,536 [either] + - 11_collect_at_depth: freed_bytes 10,062,936 -> 8,974,576 (-10.82%), allowance 1,048,576 [either] + - 12_large_live_set: copied_objects 59,405 -> 104,050 (+75.15%), allowance 2,970 [either] + - 12_large_live_set: copied_bytes 2,327,008 -> 4,162,008 (+78.86%), allowance 116,350 [either] +## GC ratchet + +- Profile: `shared_ci` +- Baseline commit: `f2ab19447194eeaa3cb47d968877745614024451` +- Baseline captured: 2026-08-16T09:38:07+00:00 on `darwin-arm64` +- Baseline host: Apple M1, 8 cores, load at capture 2.18 + +Only rows marked gating can fail the job. Non-gating rows are recorded so a +drift that is real but unmeasurable on this runner is still visible. + +Probes pinned under a non-default collector configuration: + +- `13_large_eden_survivors` — `PERRY_GC_SCAVENGE_NURSERY_MB=64` +- `14_grow_then_churn` — `PERRY_GC_MAJOR_PACING_FLOOR_MB=1 PERRY_GC_SCAVENGE_NURSERY_MB=1` + +Accepted deterministic baseline deltas: + +- `46` cells measured at `3e3e652e007ac853bf934daa86fa36c870b0e3e2` (2026-09-06T04:12:57+00:00) +- `06e1ab349c8c6e40587bb3ce2ee9f1c58b20522b` / PR #8657 — measured: array growth targets keep their generation +- `22c07ac5b44c5ff6a988257067110c7451da0223` / PR #9833 — measured: included receiver-store workload repair +- `5196d830fd0689937db94598d94662d531d4ee92` / PR #9706 — bracketed: Sep-4 shape storage and array packing +- `aa8d2ade03970ac7eb2065f3eb0e18bb4d2df1c7` / PR #9628 — bracketed: Sep-3 liveness and retention repair +- `b3e88f1fb3378fe30b065ed328b73ea0527ab18a` / PR #8806 — measured: cache exact shape transitions +- `d923b8dcf08f2afed71777c33423362411039cf0` / PR #9373 — measured: short-concat memo changes large-Eden occupancy +- `e18b24c420c7c2f389607537618699ffc6aa9d1d` / PR #8900 — measured: weak shape-transition target edges +- `e2e6f4a1cfded098ca05afe7e1b4e5ce783a5140` / PR #8313 — measured: smaller common objects +- `fc8c9e9a15902f889df2b1aeb280ca6223f6948a` / PR #8887 — bracketed: Aug-27/28 allocation and rooting specializations + +| Probe | Metric | Baseline | Current | Δ | Allowance | Gating | Status | +|-------|--------|---------:|--------:|---:|----------:|:------:|--------| +| `01_nursery_churn` | heap_used_bytes | 212,168 | 438,744 | +106.79% | 65,536 | yes | REGRESSION | +| `01_nursery_churn` | heap_total_bytes | 16,777,216 | 14,680,064 | -12.50% | 1,048,576 | yes | improvement | +| `01_nursery_churn` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `01_nursery_churn` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `01_nursery_churn` | copied_objects | 4,977 | 6,690 | +34.42% | 249 | yes | REGRESSION | +| `01_nursery_churn` | copied_bytes | 234,536 | 466,392 | +98.86% | 65,536 | yes | REGRESSION | +| `01_nursery_churn` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `01_nursery_churn` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `01_nursery_churn` | freed_bytes | 11,299,648 | 11,067,816 | -2.05% | 1,048,576 | yes | ok | +| `01_nursery_churn` | rss_bytes | 28,950,528 | 28,540,928 | -1.41% | 8,388,608 | no | ok | +| `01_nursery_churn` | peak_rss_bytes | 29,491,200 | 29,097,984 | -1.33% | 8,388,608 | no | ok | +| `01_nursery_churn` | wall_ms | 54 | 57 | +5.70% | 100 | no | ok | +| `02_survivor_promotion` | heap_used_bytes | 2,656,440 | 2,562,832 | -3.52% | 65,536 | yes | improvement | +| `02_survivor_promotion` | heap_total_bytes | 16,777,216 | 15,728,640 | -6.25% | 1,048,576 | yes | ok | +| `02_survivor_promotion` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `02_survivor_promotion` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `02_survivor_promotion` | copied_objects | 34,550 | 37,366 | +8.15% | 1,728 | yes | REGRESSION | +| `02_survivor_promotion` | copied_bytes | 1,450,992 | 1,690,264 | +16.49% | 72,550 | yes | REGRESSION | +| `02_survivor_promotion` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `02_survivor_promotion` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `02_survivor_promotion` | freed_bytes | 9,754,128 | 8,795,408 | -9.83% | 1,048,576 | yes | ok | +| `02_survivor_promotion` | rss_bytes | 32,522,240 | 31,375,360 | -3.53% | 8,388,608 | no | ok | +| `02_survivor_promotion` | peak_rss_bytes | 33,095,680 | 31,899,648 | -3.61% | 8,388,608 | no | ok | +| `02_survivor_promotion` | wall_ms | 57 | 54 | -5.68% | 100 | no | ok | +| `03_cross_gen_writes` | heap_used_bytes | 528 | 528 | +0.00% | 65,536 | yes | ok | +| `03_cross_gen_writes` | heap_total_bytes | 14,680,064 | 12,582,912 | -14.29% | 1,048,576 | yes | improvement | +| `03_cross_gen_writes` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `03_cross_gen_writes` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `03_cross_gen_writes` | copied_objects | 4,107 | 4,107 | +0.00% | 205 | yes | ok | +| `03_cross_gen_writes` | copied_bytes | 229,824 | 197,056 | -14.26% | 65,536 | yes | ok | +| `03_cross_gen_writes` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `03_cross_gen_writes` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `03_cross_gen_writes` | freed_bytes | 9,240,008 | 9,240,008 | +0.00% | 1,048,576 | yes | ok | +| `03_cross_gen_writes` | rss_bytes | 21,708,800 | 22,921,216 | +5.58% | 8,388,608 | no | ok | +| `03_cross_gen_writes` | peak_rss_bytes | 26,542,080 | 26,984,448 | +1.67% | 8,388,608 | no | ok | +| `03_cross_gen_writes` | wall_ms | 37 | 30 | -18.35% | 100 | no | ok | +| `04_dead_after_deep_stack` | heap_used_bytes | 536 | 536 | +0.00% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | heap_total_bytes | 20,971,520 | 18,874,368 | -10.00% | 1,048,576 | yes | improvement | +| `04_dead_after_deep_stack` | minor_cycles | 6 | 7 | +16.67% | 1 | yes | ok | +| `04_dead_after_deep_stack` | step_cycles | 6 | 7 | +16.67% | 1 | yes | ok | +| `04_dead_after_deep_stack` | copied_objects | 3,622 | 2,666 | -26.39% | 181 | yes | REGRESSION | +| `04_dead_after_deep_stack` | copied_bytes | 149,400 | 111,336 | -25.48% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | promoted_objects | 682 | 682 | +0.00% | 34 | yes | ok | +| `04_dead_after_deep_stack` | promoted_bytes | 440 | 27,320 | +6109.09% | 65,536 | yes | ok | +| `04_dead_after_deep_stack` | freed_bytes | 73,346,416 | 76,493,952 | +4.29% | 3,667,321 | yes | ok | +| `04_dead_after_deep_stack` | rss_bytes | 24,100,864 | 25,182,208 | +4.49% | 8,388,608 | no | ok | +| `04_dead_after_deep_stack` | peak_rss_bytes | 28,950,528 | 29,229,056 | +0.96% | 8,388,608 | no | ok | +| `04_dead_after_deep_stack` | wall_ms | 69 | 48 | -30.67% | 100 | no | ok | +| `05_closure_capture` | heap_used_bytes | 5,664 | 544 | -90.40% | 65,536 | yes | ok | +| `05_closure_capture` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `05_closure_capture` | minor_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `05_closure_capture` | step_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `05_closure_capture` | copied_objects | 20,079 | 14,285 | -28.86% | 1,004 | yes | REGRESSION | +| `05_closure_capture` | copied_bytes | 743,384 | 534,720 | -28.07% | 65,536 | yes | REGRESSION | +| `05_closure_capture` | promoted_objects | 3,390 | 6,154 | +81.53% | 170 | yes | REGRESSION | +| `05_closure_capture` | promoted_bytes | 122,120 | 221,624 | +81.48% | 65,536 | yes | REGRESSION | +| `05_closure_capture` | freed_bytes | 26,862,320 | 27,897,872 | +3.86% | 1,343,116 | yes | ok | +| `05_closure_capture` | rss_bytes | 19,169,280 | 23,265,280 | +21.37% | 8,388,608 | no | ok | +| `05_closure_capture` | peak_rss_bytes | 24,248,320 | 26,836,992 | +10.68% | 8,388,608 | no | ok | +| `05_closure_capture` | wall_ms | 68 | 59 | -14.31% | 100 | no | ok | +| `06_string_retention` | heap_used_bytes | 212,640 | 1,072 | -99.50% | 65,536 | yes | improvement | +| `06_string_retention` | heap_total_bytes | 23,068,672 | 22,020,096 | -4.55% | 1,048,576 | yes | ok | +| `06_string_retention` | minor_cycles | 5 | 4 | -20.00% | 1 | yes | ok | +| `06_string_retention` | step_cycles | 5 | 4 | -20.00% | 1 | yes | ok | +| `06_string_retention` | copied_objects | 298 | 270 | -9.40% | 16 | yes | REGRESSION | +| `06_string_retention` | copied_bytes | 72,288 | 70,144 | -2.97% | 65,536 | yes | ok | +| `06_string_retention` | promoted_objects | 14 | 14 | +0.00% | 16 | yes | ok | +| `06_string_retention` | promoted_bytes | 1,072 | 1,072 | +0.00% | 65,536 | yes | ok | +| `06_string_retention` | freed_bytes | 68,136,816 | 68,136,816 | +0.00% | 3,406,841 | yes | ok | +| `06_string_retention` | rss_bytes | 32,964,608 | 28,459,008 | -13.67% | 8,388,608 | no | ok | +| `06_string_retention` | peak_rss_bytes | 33,488,896 | 33,079,296 | -1.22% | 8,388,608 | no | ok | +| `06_string_retention` | wall_ms | 76 | 53 | -30.77% | 100 | no | ok | +| `07_array_grow_evacuate` | heap_used_bytes | 1,072,456 | 1,211,232 | +12.94% | 65,536 | yes | REGRESSION | +| `07_array_grow_evacuate` | heap_total_bytes | 25,165,824 | 25,165,824 | +0.00% | 1,048,576 | yes | ok | +| `07_array_grow_evacuate` | minor_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `07_array_grow_evacuate` | step_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `07_array_grow_evacuate` | copied_objects | 4,991 | 6,702 | +34.28% | 250 | yes | REGRESSION | +| `07_array_grow_evacuate` | copied_bytes | 2,671,936 | 2,636,392 | -1.33% | 133,597 | no | ok | +| `07_array_grow_evacuate` | promoted_objects | 4,879 | 6,154 | +26.13% | 244 | yes | REGRESSION | +| `07_array_grow_evacuate` | promoted_bytes | 615,696 | 841,048 | +36.60% | 65,536 | yes | REGRESSION | +| `07_array_grow_evacuate` | freed_bytes | 83,727,056 | 83,570,704 | -0.19% | 4,186,353 | no | ok | +| `07_array_grow_evacuate` | rss_bytes | 34,029,568 | 37,928,960 | +11.46% | 8,388,608 | no | ok | +| `07_array_grow_evacuate` | peak_rss_bytes | 34,553,856 | 38,535,168 | +11.52% | 8,388,608 | no | ok | +| `07_array_grow_evacuate` | wall_ms | 144 | 63 | -56.20% | 100 | no | ok | +| `08_map_set_sidetables` | heap_used_bytes | 672 | 688 | +2.38% | 65,536 | yes | ok | +| `08_map_set_sidetables` | heap_total_bytes | 16,777,216 | 14,680,064 | -12.50% | 1,048,576 | yes | improvement | +| `08_map_set_sidetables` | minor_cycles | 5 | 6 | +20.00% | 1 | yes | ok | +| `08_map_set_sidetables` | step_cycles | 5 | 6 | +20.00% | 1 | yes | ok | +| `08_map_set_sidetables` | copied_objects | 2,489 | 2,461 | -1.12% | 124 | yes | ok | +| `08_map_set_sidetables` | copied_bytes | 144,384 | 98,472 | -31.80% | 65,536 | yes | ok | +| `08_map_set_sidetables` | promoted_objects | 15 | 14 | -6.67% | 16 | yes | ok | +| `08_map_set_sidetables` | promoted_bytes | 576 | 592 | +2.78% | 65,536 | yes | ok | +| `08_map_set_sidetables` | freed_bytes | 57,655,296 | 56,598,904 | -1.83% | 2,882,765 | yes | ok | +| `08_map_set_sidetables` | rss_bytes | 21,037,056 | 19,955,712 | -5.14% | 8,388,608 | no | ok | +| `08_map_set_sidetables` | peak_rss_bytes | 25,329,664 | 24,559,616 | -3.04% | 8,388,608 | no | ok | +| `08_map_set_sidetables` | wall_ms | 171 | 205 | +19.92% | 100 | no | ok | +| `09_try_catch_roots` | heap_used_bytes | 212,168 | 443,520 | +109.04% | 65,536 | yes | REGRESSION | +| `09_try_catch_roots` | heap_total_bytes | 14,680,064 | 14,680,064 | +0.00% | 1,048,576 | yes | ok | +| `09_try_catch_roots` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `09_try_catch_roots` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `09_try_catch_roots` | copied_objects | 4,962 | 6,673 | +34.48% | 248 | yes | REGRESSION | +| `09_try_catch_roots` | copied_bytes | 230,352 | 462,024 | +100.57% | 65,536 | yes | REGRESSION | +| `09_try_catch_roots` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `09_try_catch_roots` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `09_try_catch_roots` | freed_bytes | 11,112,472 | 10,023,568 | -9.80% | 1,048,576 | yes | REGRESSION | +| `09_try_catch_roots` | rss_bytes | 30,015,488 | 30,195,712 | +0.60% | 8,388,608 | no | ok | +| `09_try_catch_roots` | peak_rss_bytes | 30,457,856 | 30,670,848 | +0.70% | 8,388,608 | no | ok | +| `09_try_catch_roots` | wall_ms | 744 | 155 | -79.10% | 223 | no | improvement | +| `10_store_receiver_across_alloc` | heap_used_bytes | 220,384 | 446,776 | +102.73% | 65,536 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | heap_total_bytes | 16,777,216 | 22,020,096 | +31.25% | 1,048,576 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | minor_cycles | 9 | 8 | -11.11% | 1 | yes | ok | +| `10_store_receiver_across_alloc` | step_cycles | 9 | 8 | -11.11% | 1 | yes | ok | +| `10_store_receiver_across_alloc` | copied_objects | 18,660 | 14,625 | -21.62% | 933 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | copied_bytes | 825,520 | 787,792 | -4.57% | 65,536 | yes | ok | +| `10_store_receiver_across_alloc` | promoted_objects | 4,722 | 6,107 | +29.33% | 236 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | promoted_bytes | 228,440 | 446,368 | +95.40% | 65,536 | yes | REGRESSION | +| `10_store_receiver_across_alloc` | freed_bytes | 88,858,544 | 88,640,584 | -0.25% | 4,442,927 | yes | ok | +| `10_store_receiver_across_alloc` | rss_bytes | 24,756,224 | 35,061,760 | +41.63% | 8,388,608 | no | drift (informational) | +| `10_store_receiver_across_alloc` | peak_rss_bytes | 25,296,896 | 35,586,048 | +40.67% | 8,388,608 | no | drift (informational) | +| `10_store_receiver_across_alloc` | wall_ms | 43 | 196 | +354.30% | 100 | no | drift (informational) | +| `11_collect_at_depth` | heap_used_bytes | 212,168 | 444,720 | +109.61% | 65,536 | yes | REGRESSION | +| `11_collect_at_depth` | heap_total_bytes | 13,631,488 | 12,582,912 | -7.69% | 1,048,576 | yes | ok | +| `11_collect_at_depth` | minor_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `11_collect_at_depth` | step_cycles | 1 | 1 | +0.00% | 1 | yes | ok | +| `11_collect_at_depth` | copied_objects | 4,975 | 6,686 | +34.39% | 249 | yes | REGRESSION | +| `11_collect_at_depth` | copied_bytes | 230,872 | 462,544 | +100.35% | 65,536 | yes | REGRESSION | +| `11_collect_at_depth` | promoted_objects | 0 | 0 | - | 16 | yes | ok | +| `11_collect_at_depth` | promoted_bytes | 0 | 0 | - | 65,536 | yes | ok | +| `11_collect_at_depth` | freed_bytes | 10,062,936 | 8,974,576 | -10.82% | 1,048,576 | yes | REGRESSION | +| `11_collect_at_depth` | rss_bytes | 26,525,696 | 26,492,928 | -0.12% | 8,388,608 | no | ok | +| `11_collect_at_depth` | peak_rss_bytes | 26,984,448 | 27,131,904 | +0.55% | 8,388,608 | no | ok | +| `11_collect_at_depth` | wall_ms | 48 | 43 | -10.60% | 100 | no | ok | +| `12_large_live_set` | heap_used_bytes | 1,104,848 | 569,448 | -48.46% | 65,536 | yes | improvement | +| `12_large_live_set` | heap_total_bytes | 82,837,504 | 74,448,896 | -10.13% | 1,656,750 | yes | improvement | +| `12_large_live_set` | minor_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `12_large_live_set` | step_cycles | 5 | 5 | +0.00% | 1 | yes | ok | +| `12_large_live_set` | copied_objects | 59,405 | 104,050 | +75.15% | 2,970 | yes | REGRESSION | +| `12_large_live_set` | copied_bytes | 2,327,008 | 4,162,008 | +78.86% | 116,350 | yes | REGRESSION | +| `12_large_live_set` | promoted_objects | 529,075 | 530,030 | +0.18% | 26,454 | yes | ok | +| `12_large_live_set` | promoted_bytes | 21,201,208 | 21,201,208 | +0.00% | 1,060,060 | yes | ok | +| `12_large_live_set` | freed_bytes | 63,732,784 | 63,732,784 | +0.00% | 3,186,639 | yes | ok | +| `12_large_live_set` | rss_bytes | 122,044,416 | 117,047,296 | -4.09% | 18,306,662 | no | ok | +| `12_large_live_set` | peak_rss_bytes | 124,665,856 | 120,176,640 | -3.60% | 18,699,878 | no | ok | +| `12_large_live_set` | wall_ms | 1,955 | 325 | -83.35% | 586 | no | improvement | +| `13_large_eden_survivors` | heap_used_bytes | 499,576 | 444,976 | -10.93% | 65,536 | yes | ok | +| `13_large_eden_survivors` | heap_total_bytes | 59,768,832 | 61,865,984 | +3.51% | 1,195,377 | no | drift (informational) | +| `13_large_eden_survivors` | minor_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `13_large_eden_survivors` | step_cycles | 3 | 3 | +0.00% | 1 | yes | ok | +| `13_large_eden_survivors` | copied_objects | 377,569 | 382,868 | +1.40% | 18,878 | yes | ok | +| `13_large_eden_survivors` | copied_bytes | 21,429,712 | 21,804,904 | +1.75% | 1,071,486 | yes | ok | +| `13_large_eden_survivors` | promoted_objects | 386,271 | 387,152 | +0.23% | 19,314 | yes | ok | +| `13_large_eden_survivors` | promoted_bytes | 21,777,792 | 21,975,560 | +0.91% | 1,088,890 | yes | ok | +| `13_large_eden_survivors` | freed_bytes | 108,243,696 | 108,045,936 | -0.18% | 5,412,185 | yes | ok | +| `13_large_eden_survivors` | rss_bytes | 145,522,688 | 142,540,800 | -2.05% | 21,828,403 | no | ok | +| `13_large_eden_survivors` | peak_rss_bytes | 145,850,368 | 143,048,704 | -1.92% | 21,877,555 | no | ok | +| `13_large_eden_survivors` | wall_ms | 965 | 887 | -8.06% | 290 | no | ok | +| `14_grow_then_churn` | heap_used_bytes | 402,968 | 429,408 | +6.56% | 65,536 | yes | ok | +| `14_grow_then_churn` | heap_total_bytes | 23,068,672 | 23,068,672 | +0.00% | 1,048,576 | yes | ok | +| `14_grow_then_churn` | minor_cycles | 21 | 22 | +4.76% | 1 | yes | ok | +| `14_grow_then_churn` | step_cycles | 22 | 23 | +4.55% | 1 | yes | ok | +| `14_grow_then_churn` | copied_objects | 330 | 330 | +0.00% | 16 | yes | ok | +| `14_grow_then_churn` | copied_bytes | 1,222,176 | 1,277,072 | +4.49% | 65,536 | yes | ok | +| `14_grow_then_churn` | promoted_objects | 404,022 | 405,282 | +0.31% | 20,201 | yes | ok | +| `14_grow_then_churn` | promoted_bytes | 147,516,064 | 147,967,848 | +0.31% | 7,375,803 | yes | ok | +| `14_grow_then_churn` | freed_bytes | 118,903,288 | 119,549,744 | +0.54% | 5,945,164 | yes | ok | +| `14_grow_then_churn` | rss_bytes | 286,490,624 | 297,287,680 | +3.77% | 42,973,594 | no | ok | +| `14_grow_then_churn` | peak_rss_bytes | 286,834,688 | 297,779,200 | +3.82% | 43,025,203 | no | ok | +| `14_grow_then_churn` | wall_ms | 403 | 492 | +21.98% | 121 | no | ok | + +### Cells excluded from the gating family by probe override + +- `07_array_grow_evacuate`.copied_bytes — NOT GATED ON THIS PROBE (#9790). Address-dependent promotion order changes old-block packing and the allocation boundary where nursery pressure is checked. The fifth minor observes a different live cohort: a completed 8,208-byte array or a new 144-byte array. Header-size sums and from-space reclamation account for the byte deltas; this is placement-dependent pacing, not an accounting discrepancy. Keep this cell visible; correctness, retention, cycle counts, object counts and promoted bytes remain gated. See evidence/9790-array-growth-pacing.json and the README investigation. (observed spread 8,064 over 21 runs, 2026-09-05, macOS arm64, Perry 0.5.1520; 21 executions of one unchanged binary. Compiler/runtime hashes and raw counters: benchmarks/gc_ratchet/evidence/9790-array-growth-pacing.json.; https://github.com/PerryTS/perry/issues/9790) +- `07_array_grow_evacuate`.freed_bytes — NOT GATED ON THIS PROBE (#9790). Address-dependent promotion order changes old-block packing and the allocation boundary where nursery pressure is checked. The fifth minor observes a different live cohort: a completed 8,208-byte array or a new 144-byte array. Header-size sums and from-space reclamation account for the byte deltas; this is placement-dependent pacing, not an accounting discrepancy. Keep this cell visible; correctness, retention, cycle counts, object counts and promoted bytes remain gated. See evidence/9790-array-growth-pacing.json and the README investigation. (observed spread 8,208 over 21 runs, 2026-09-05, macOS arm64, Perry 0.5.1520; 21 executions of one unchanged binary. Compiler/runtime hashes and raw counters: benchmarks/gc_ratchet/evidence/9790-array-growth-pacing.json.; https://github.com/PerryTS/perry/issues/9790) +- `13_large_eden_survivors`.heap_total_bytes — NOT GATED ON THIS PROBE (#9829). Total reserved arena capacity varies by 2 MiB across executions of one unchanged binary: 18/21 runs reserve 61865984 bytes and 3/21 reserve 63963136. All 21 report the same 227048 live bytes and identical seven GC counters (including three minors and 377569 copied objects), with Node-equivalent output. js_arena_stats sums reserved block sizes for heapTotal, separately from its exact live-object census for heapUsed. This is spare-capacity/placement variation, not changing live retention or GC work; the precise allocating block/order is not isolated. CI run 33989581881 independently contains the same two capacities. Keep the cell visible, while heapUsed, liveness, copying/promotion/reclamation, and all other probes remain gated. Raw 21-run evidence and binary/source hashes: evidence/9829-recovery.json. (observed spread 2,097,152 over 21 runs, 2026-09-06, linux-x86_64, clean main d36a1af0c compiler and matching runtime/stdlib archives. One unchanged probe binary, 21 traced executions with PERRY_GC_SCAVENGE_NURSERY_MB=64. See evidence/9829-recovery.json capacity_variance.; https://github.com/PerryTS/perry/issues/9829) diff --git a/benchmarks/catch_frames/evidence/mac-gc-guard.json.gz b/benchmarks/catch_frames/evidence/mac-gc-guard.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..ad3f25de520dc65131bd593aa69a4ad7d3325d91 GIT binary patch literal 6067 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/mac-gc-harness-tests.log b/benchmarks/catch_frames/evidence/mac-gc-harness-tests.log new file mode 100644 index 0000000000..e32875dca2 --- /dev/null +++ b/benchmarks/catch_frames/evidence/mac-gc-harness-tests.log @@ -0,0 +1,23 @@ +...........................gc-ratchet error: 01_probe: heap_used_bytes summary is inconsistent with its samples +.....gc-ratchet: UNFIT PINNED CELL `01_probe.heap_used_bytes` — spread 6768 when pinned, but its band is justified by bit-identity, not by a noise allowance. Either re-pin on a quiet host, or take this one cell out of the gating family with a probe_overrides entry that records the evidence. +gc-ratchet: 1 unfit cell(s) deferred to `check` (--scope structural); they will fail the job there, after the probes run +gc-ratchet: UNFIT PINNED CELL `01_probe.heap_used_bytes` — spread 6768 when pinned, but its band is justified by bit-identity, not by a noise allowance. Either re-pin on a quiet host, or take this one cell out of the gating family with a probe_overrides entry that records the evidence. +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpnp401gxv/artifact.json has 1 unfit cell(s); re-pin them or record a probe_overrides entry +gc-ratchet: UNFIT PINNED PROBE `01_probe` — baseline was pinned without a passing Node oracle diff (status='unchecked'), so this probe's rows are not evidence about the collector +gc-ratchet: 1 unfit cell(s) deferred to `check` (--scope structural); they will fail the job there, after the probes run +gc-ratchet: UNFIT PINNED PROBE `01_probe` — baseline was pinned without a passing Node oracle diff (status='unchecked'), so this probe's rows are not evidence about the collector +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpoa3t5n78/artifact.json has 1 unfit cell(s); re-pin them or record a probe_overrides entry +gc-ratchet: UNFIT PINNED PROBE `01_probe` — baseline pinned a probe that ran no minor collection, so there is no evacuating-minor behaviour here to ratchet against +gc-ratchet: 1 unfit cell(s) deferred to `check` (--scope structural); they will fail the job there, after the probes run +gc-ratchet: UNFIT PINNED PROBE `01_probe` — baseline pinned a probe that ran no minor collection, so there is no evacuating-minor behaviour here to ratchet against +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpmkazs2vz/artifact.json has 1 unfit cell(s); re-pin them or record a probe_overrides entry +..gc-ratchet: UNFIT PINNED CELL `01_probe.heap_used_bytes` — spread 6768 when pinned, but its band is justified by bit-identity, not by a noise allowance. Either re-pin on a quiet host, or take this one cell out of the gating family with a probe_overrides entry that records the evidence. +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpnpoq5boi/artifact.json has 1 unfit cell(s); re-pin them or record a probe_overrides entry +................................................................................. +---------------------------------------------------------------------- +Ran 115 tests in 8.432s + +OK +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpnp401gxv/artifact.json is structurally valid +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpoa3t5n78/artifact.json is structurally valid +gc-ratchet: /var/folders/8v/09vl257j2_v70v2k77gh01n00000gn/T/tmpmkazs2vz/artifact.json is structurally valid diff --git a/benchmarks/catch_frames/evidence/mac-gc-structural.log b/benchmarks/catch_frames/evidence/mac-gc-structural.log new file mode 100644 index 0000000000..35b22ce55f --- /dev/null +++ b/benchmarks/catch_frames/evidence/mac-gc-structural.log @@ -0,0 +1 @@ +gc-ratchet: /Users/amlug/projects/perry/wt-js-throw-catch-frames/benchmarks/gc_ratchet/baseline/gc-ratchet-v1.json is structurally valid diff --git a/benchmarks/catch_frames/evidence/matrix-trend.json.gz b/benchmarks/catch_frames/evidence/matrix-trend.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..1575c09f0594a2dc1e67f5e3c3237ff442a75f4d GIT binary patch literal 2746 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 ABLDyZ literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/parity.json.gz b/benchmarks/catch_frames/evidence/parity.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..805859d725650034b63c1e4bbaf7c3767f006cc5 GIT binary patch literal 19671 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 z

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

weP3^(kR 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

Kwu!M0~GxJZa#ZfuwF=0P%WKBsK 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

A8K)%{xFf0XH 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 literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/pre-edit/promises.frames b/benchmarks/catch_frames/evidence/pre-edit/promises.frames new file mode 100644 index 0000000000..24e7eeb3a6 --- /dev/null +++ b/benchmarks/catch_frames/evidence/pre-edit/promises.frames @@ -0,0 +1,3 @@ +# started on Mon Sep 14 04:30:40 2026 + +100007;;perrycatch_probe:push;148213065;100.00;; diff --git a/benchmarks/catch_frames/evidence/pre-edit/promises.no-inline.folded.gz b/benchmarks/catch_frames/evidence/pre-edit/promises.no-inline.folded.gz new file mode 100644 index 0000000000000000000000000000000000000000..32f103fd8819b13f481ce33513a4b16188490c7e GIT binary patch literal 3055 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 HnvnniS03q< literal 0 HcmV?d00001 diff --git a/benchmarks/catch_frames/evidence/validation.md b/benchmarks/catch_frames/evidence/validation.md new file mode 100644 index 0000000000..d34f1296f2 --- /dev/null +++ b/benchmarks/catch_frames/evidence/validation.md @@ -0,0 +1,148 @@ +# Local validation replay + +Baseline: main `eb13fa188d0690fb964cd6df329593e05aa55617`, version 0.5.1564. +This commit already contains the #10215 large-array fix. All edits and builds +used session-owned worktrees and targets; the user's dirty checkout was not +modified. The feature branch does not bump the workspace version. Landing +requires the repository's merge train and a replay on the assembled train. + +## Runtime and static gates + +The final source, including the constructor-identity guard, was checked on +macOS arm64 with nightly-2026-08-20. Default runtime features include both +regex-engine and dyn-eval, so all 13 registered restore witnesses run. + +| Check | Result | +|---|---| +| `cargo fmt --all -- --check` | Pass | +| `cargo check -p perry-runtime --no-default-features --features full` | Pass | +| `cargo test -p perry-runtime --lib -- --test-threads=1` | 3,811 passed, 4 ignored; baseline 3,798 passed, 4 ignored | +| One omitted production restore at a time | All 13 detected at the nested enclosing-state assertion; restored exception suite: 20 passed | +| `cargo clippy -p perry-runtime --lib --tests --message-format=json` compared with main | No added or removed diagnostics; both return 101 for the same existing errors | +| `scripts/run_lint_gates.sh` | 80/83 pass; three baseline-reproduced failures, two CI-only skips | + +Clippy diagnostics are compared as multisets of level, lint code, message and +primary filename, ignoring source-line movement. The baseline has 12 +`clippy::approx_constant` errors; `clippy-comparison.json` records the diff. +The user-listed `native_stack` test passes on this host. + +The final complete lint replay ran 83 gates: 80 passed and three failed, +with two CI-only checks skipped by the script. Each failure was independently +reproduced on the clean baseline: + +- Public benchmark evidence freshness is stale on main. +- Host-compatible all-targets `RUSTFLAGS="-D warnings" cargo check` rejects + unused WebAssembly helpers in unchanged `global_this_webassembly.rs`. +- Generated API documentation differs from committed docs. Baseline and + candidate generated Markdown and declarations are byte-identical, including + missing committed bun-pty entries. Generated documentation was restored + after checking; no baseline or warning suppression is included in the patch. + +Product strict-warning, product clippy and workspace clippy gates pass. +The full lint transcript and baseline comparisons are retained beside this +file. The GC custody, root inventory and wiring checks are part of that replay. + +## GC replay + +The catch-frame patch before the seven-line constructor marker guard passed +the full Linux matrix: 86 corpus fixtures × 22 arms = 1,892 cells, with 1,533 +PASS, 359 UNVER, zero XFAIL and zero FAIL. Every one of the 21 arms with a +liveness requirement exercised its required collector operation. The shipped +control has no liveness requirement. The 359 UNVER cells are not counted as +passing checks; they are retained by the official matrix harness. + +This matrix used a coherent release build of `perry`, `perry-runtime-static`, +`perry-stdlib-static`, `perry-ext-net`, and `perry-ext-http`, pinned Node 26.5.1, +`PERRY_NO_AUTO_OPTIMIZE=1`, and the full runtime archives. The explicit +extension packages avoid mixing archives with a different runtime source +stamp. GC representation flags still vary across the matrix's compile groups. +The full JSON report is `gc-stress.json.gz`. The final guarded PR-arm replay also passes: 86 fixtures × seven arms = +602/602 byte-exact Node matches, 431 PASS, 171 UNVER, zero XFAIL and zero +FAIL. All six required liveness checks pass. Its complete report is +`guard-gc-stress.json.gz`, with liveness counters in +`guard-gc-stress-summary.txt`. + +The final guarded Linux ratchet ran seven repetitions of all 14 probes against Node 26.5.1. +Its same-host baseline was built from the stated main commit. All 126 +heap/collector medians match exactly and `check --profile shared_ci` passes +against that fresh comparison artifact. The artifact is evidence only; the +repository's pinned baseline is unchanged. + +The exact pinned ratchet was also replayed on macOS with the workflow's +three-package release graph and default one-codegen-unit release profile. +The GC harness unit tests and `validate --scope structural` pass. Baseline and +final guarded candidate have identical values for all 126 heap/collector +medians; both fail the pinned artifact at the same 30 cells. The ordered +failure diagnostics are identical (`pinned-gc-comparison.json`). Wall time and RSS are observations only, not performance claims. + +## Compiled integration + +The final Linux replay completed all four disjoint +`run_parity_tests.sh --shard N/4` shards with the frozen guarded three-package +artifacts used for instruction measurements. Auto-optimized extension +variants requested by the harness used the matching guarded source tree. +The official merge required all four reports and verified disjoint test IDs. + +| Complete inventory | Result | +|---|---| +| All parity fixtures | 1,633 entries: 1,472 pass, 93 output mismatches, 29 compile failures, two timeouts classified as crashes, five Node oracle failures, 32 skips | +| Gap subset | All 785 entries: 776 pass, nine output mismatches, no crashes/compile failures/oracle failures/skips | +| Aggregate threshold | Pass, 93.9% by the harness's formula | +| Matrix trend | Pass | +| Gap snapshot | Three baseline-reproduced mismatches | +| Platform known-failure gate | Eight unlisted results: seven reproduce on main; the eighth passes an isolated candidate replay after restoring its echo-server prerequisite | + +Every `test_gap_` fixture ran as part of the full sweep. The extracted gap +report was checked with the same `gap_snapshot.py check` used by +`scripts/run_gap_tests.sh`. Both complete reports, coverage assertions and +all gate commands/results are retained. No allowlist or snapshot is relaxed. + +The seven unlisted baseline-reproduced results are: + +- `test_bun_plugin` and `test_dynamic_import_data_10104` (oracle/import behavior). +- `test_gap_2899_2779_2777_static_helpers`, `test_gap_disposablestack_2875`, and + `test_gap_iterator_prototype_next_patch` (also the three gap-gate failures). +- `test_issue_10155_textfield_singleline` (compile failure). +- `test_issue_336_class_keys_collision` (Node rejects namespace syntax). + +The eighth, `test_sock_write_map`, encountered a missing echo server during +the parallel sweep: both Node and Perry received connection-refused errors. +The official isolated fixture passes on both main and the guarded candidate. +`socket-recheck.md` records the cause and successful replay; the original +aggregate report is retained without rewriting its failure to a pass. + +Both crashes are 10-second timeouts and reproduce on main: +`test_issue_4975_http_agent_keep_alive_connection_options` and +`test_parity_stream_web`. Their existing failure records cite closed #8841 +and #793 respectively; that stale tracking is not presented as a new open +issue. See `additional-baseline-checks.json` for the observed behavior. + +The five Node oracle failures are long-lived server/channel fixtures: +`test_node_http_basic`, `test_issue_4826_array_headers`, +`test_node_http_post_body`, `test_message_channel_global`, and +`test_node_http_ws_upgrade`. Perry was not tested by those entries. The array +headers oracle timeout was also reproduced with the clean baseline harness. +The test sources and harness are unchanged by this PR. These entries and the +32 skips remain explicit gaps in this replay's execution coverage. + +Constructor-marker regression and guard-omission evidence are recorded in +`constructor-identity.md`. All five targeted guarded rechecks pass, and all +five also pass in the complete sweep. + +## Evidence provenance + +`instructions.json` records the SHA-256 of the reviewed +`git diff eb13fa188d -- crates` patch and the frozen three-package artifacts. +`source-files.json` hashes all 20 changed or added Rust source files; each +matches the Linux validation source byte for byte. Final instruction +measurements and full integration include the constructor guard. The older +full 22-arm matrix precedes only that guard; its scope is stated above. The +final source passes the seven-arm PR matrix and matches main on both GC +ratchet measurements. + +Full logs and binaries are retained under `/root/js-throw-evidence` on +perrymaster. Local unit, lint, clippy and pinned GC logs are under +`/tmp/perry-catch-evidence`. Repository evidence contains compact JSON, raw +instruction-stat outputs, folded stacks, fault transcripts and gate reports. +Superseded incomplete integration runs, including an early source-stamp +mismatch, are excluded from the final results. diff --git a/benchmarks/catch_frames/exec1.ts b/benchmarks/catch_frames/exec1.ts new file mode 100644 index 0000000000..c2f866a24e --- /dev/null +++ b/benchmarks/catch_frames/exec1.ts @@ -0,0 +1 @@ +const vals: string[] = []; for (let i = 0; i < 1000000; i++) vals.push((i % 2 ? "record_" : "!bad_") + i); let c = 0; const re = /([a-z]+)_([0-9]+)/; for (let i = 0; i < vals.length; i++) { const m = re.exec(vals[i]); if (m !== null) c += m[2].length; } console.log(c); diff --git a/benchmarks/catch_frames/fault_restore.py b/benchmarks/catch_frames/fault_restore.py new file mode 100644 index 0000000000..7d2819d535 --- /dev/null +++ b/benchmarks/catch_frames/fault_restore.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Temporarily omit each registered production restore; require its real-throw test to fail.""" +import argparse +import json +import os +from pathlib import Path +import re +import resource +import subprocess + + +def build(root, log): + command = ["cargo", "test", "-p", "perry-runtime", "--lib", "--no-run", "--message-format=json"] + result = subprocess.run(command, cwd=root, text=True, capture_output=True) + log.with_suffix(".stderr").write_text(result.stderr) + log.write_text(result.stdout) + result.check_returncode() + artifacts = [json.loads(line) for line in result.stdout.splitlines() if line.startswith("{")] + return next(a["executable"] for a in artifacts if a.get("reason") == "compiler-artifact" and a.get("executable") and a["target"]["name"] == "perry_runtime") + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args() + args.output.mkdir(parents=True, exist_ok=True) + resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) + root = Path(__file__).resolve().parents[2] + path = root / "crates/perry-runtime/src/exception/savepoints.rs" + original = path.read_text() + needle = "$($(#[$attr])* $restore(self.$name);)*" + assert original.count(needle) == 1 + names = re.findall(r"^ (\w+): [^\n]+ = ", original, flags=re.MULTILINE) + captures = re.findall(r"^ capture: ", original, flags=re.MULTILINE) + assert names and len(names) == len(set(names)) == len(captures), names + mutant = original.replace(needle, '''$($(#[$attr])* { + if std::env::var("PERRY_TEST_SKIP_CATCH_RESTORE").as_deref() != Ok(stringify!($name)) { + $restore(self.$name); + } + })*''') + results = [] + try: + path.write_text(mutant) + executable = build(root, args.output / "mutant-build.jsonl") + for name in names: + test = f"exception::savepoints::restore_tests::{name}" + result = subprocess.run([executable, "--exact", test, "--test-threads=1", "--nocapture"], env=dict(os.environ, PERRY_TEST_SKIP_CATCH_RESTORE=name), text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + (args.output / (name + ".log")).write_text(result.stdout) + # A filter matching zero tests, or an unrelated startup failure, + # must not count as a detected missing restore. + detected = result.returncode != 0 and "inner catch must preserve its enclosing scope" in result.stdout + results.append({"restore": name, "test": test, "exit_code": result.returncode, "detected": detected}) + print(name, result.returncode, detected, flush=True) + (args.output / "fault-results.json").write_text(json.dumps(results, indent=2) + "\n") + assert all(r["detected"] for r in results), results + finally: + path.write_text(original) + # The source AND executable must be restored; a later green run must + # not accidentally exercise an environment-controlled mutant. + executable = build(root, args.output / "restored-build.jsonl") + with (args.output / "restored-tests.log").open("w") as stream: + subprocess.run([executable, "exception::", "--test-threads=1"], stdout=stream, stderr=subprocess.STDOUT, check=True) + + +if __name__ == "__main__": + main() diff --git a/benchmarks/catch_frames/hoist.ts b/benchmarks/catch_frames/hoist.ts new file mode 100644 index 0000000000..07c34ce7c5 --- /dev/null +++ b/benchmarks/catch_frames/hoist.ts @@ -0,0 +1 @@ +const vals: string[] = []; for (let i = 0; i < 1000000; i++) vals.push((i % 2 ? "record_" : "!bad_") + i); let c = 0; const re = /^[a-z]+_[0-9]+$/; for (let i = 0; i < vals.length; i++) if (re.test(vals[i])) c++; console.log(c); diff --git a/benchmarks/catch_frames/json.ts b/benchmarks/catch_frames/json.ts new file mode 100644 index 0000000000..cd21e41159 --- /dev/null +++ b/benchmarks/catch_frames/json.ts @@ -0,0 +1,10 @@ +const source = '{"name":"a-long-heap-string-payload","count":42,"items":[1,2,3],"child":{"ok":true}}'; +let checksum = 0; +for (let i = 0; i < 100000; i++) { + const value = JSON.parse(source); + value.count = i; + const encoded = JSON.stringify(value); + const decoded = JSON.parse(encoded); + checksum += encoded.length + decoded.count + decoded.items[2]; +} +console.log(checksum); diff --git a/benchmarks/catch_frames/measure.py b/benchmarks/catch_frames/measure.py new file mode 100644 index 0000000000..7a21c3b8e5 --- /dev/null +++ b/benchmarks/catch_frames/measure.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""Build/check probes, count user instructions, and retain folded DWARF stacks.""" +import argparse +import collections +import json +import os +from pathlib import Path +import re +import subprocess + + +def run(args, output, env=None): + with output.open("w") as stream: + subprocess.run(args, stdout=stream, stderr=subprocess.STDOUT, env=env, check=True) + + +def fold(text): + stacks = collections.Counter() + frames = [] + for line in text.splitlines() + [""]: + if not line.strip(): + if frames: + stacks[";".join(reversed(frames))] += 1 + frames = [] + elif line[0].isspace(): + parts = line.strip().split(None, 1) + if len(parts) == 2: + symbol = parts[1].rsplit(" (", 1)[0] + frames.append(re.sub(r"\+0x[0-9a-f]+$", "", symbol)) + return stacks + + +def summarize(instructions, stacks): + # LTO can inline capture into either exported entry point. Counting only + # the private helper would miss those frames. Never count a callback body + # just because catch_js_throw / perry_sjlj_try appears above it. + capture_pattern = re.compile(r"\b(?:try_push_with_kind|js_try_push|js_eh_try_push)\b|CatchSavepoint::capture") + capture = sum(n for s, n in stacks.items() if capture_pattern.search(s)) + transport = sum(n for s, n in stacks.items() if re.search(r"perry_sjlj_try|arm_trap_and_run|sigsetjmp|__sigjmp_save|js_try_end|catch_js_throw", s.split(";")[-1])) + total = sum(stacks.values()) + return {"instructions": instructions, "samples": total, "capture_samples": capture, "transport_leaf_samples": transport, "capture_percent": 100 * capture / total} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--perry", type=Path, required=True) + parser.add_argument("--micro", type=Path) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--period", type=int, default=1000003) + parser.add_argument("--probes", nargs="*", default=["promises", "json", "hoist", "exec1"]) + args = parser.parse_args() + args.output.mkdir(parents=True, exist_ok=True) + env = dict(os.environ, PERRY_KEEP_SYMBOLS="1", PERRY_NO_AUTO_OPTIMIZE="1", PERRY_NO_TELEMETRY="1") + results = {} + jobs = [] + for name in args.probes: + source = Path(__file__).resolve().parent / (name + ".ts") + binary = args.output / name + run([str(args.perry), "compile", str(source), "--no-auto-optimize", "-o", str(binary)], args.output / (name + ".compile.log"), env) + expected = subprocess.check_output(["node", str(source)], env=env) + actual = subprocess.check_output([str(binary)], env=env) + (args.output / (name + ".expected")).write_bytes(expected) + (args.output / (name + ".out")).write_bytes(actual) + assert actual == expected, name + jobs.append((name, [str(binary)])) + if args.micro: + for mode in ["plain", "catch", "unwind"]: + jobs.append((mode, [str(args.micro), mode, "1000000"])) + for name, command in jobs: + stat = args.output / (name + ".stat") + run(["perf", "stat", "-x", ";", "-r", "3", "-e", "instructions:u", "-o", str(stat), "--"] + command, args.output / (name + ".stat.out"), env) + instructions = next(float(line.split(";")[0]) for line in stat.read_text().splitlines() if "instructions:u" in line) + data = args.output / (name + ".perf.data") + run(["perf", "record", "-q", "-m", "64M", "-e", "instructions:u", "-c", str(args.period), "--call-graph", "dwarf", "-o", str(data), "--"] + command, args.output / (name + ".profile.out"), env) + stacks = fold(subprocess.check_output(["perf", "script", "--no-inline", "-i", str(data)], text=True)) + (args.output / (name + ".folded")).write_text("".join(f"{s} {n}\n" for s, n in stacks.most_common())) + results[name] = summarize(instructions, stacks) + print(name, results[name], flush=True) + (args.output / "results.json").write_text(json.dumps(results, indent=2) + "\n") + + +if __name__ == "__main__": + main() diff --git a/benchmarks/catch_frames/promises.ts b/benchmarks/catch_frames/promises.ts new file mode 100644 index 0000000000..bafee1b950 --- /dev/null +++ b/benchmarks/catch_frames/promises.ts @@ -0,0 +1,9 @@ +async function run(): Promise { + let checksum = 0; + for (let i = 0; i < 100000; i++) { + const value = await Promise.resolve(i).then((n: number) => n + 1); + checksum += value; + } + console.log(checksum); +} +run(); diff --git a/changelog.d/catch-frames.md b/changelog.d/catch-frames.md new file mode 100644 index 0000000000..c1b269f8ba --- /dev/null +++ b/changelog.d/catch-frames.md @@ -0,0 +1,5 @@ +Group JavaScript exception frames and inline savepoint capture providers to +reduce catch setup overhead. A shared declaration now couples each subsystem's +capture, restore and nested real-throw regression test, while runtime traps +continue to use the C `setjmp` trampoline. +Preserve builtin constructor marker identity across Thin LTO runtime archives. diff --git a/crates/perry-runtime/examples/catch_frames.rs b/crates/perry-runtime/examples/catch_frames.rs new file mode 100644 index 0000000000..52a5a4962a --- /dev/null +++ b/crates/perry-runtime/examples/catch_frames.rs @@ -0,0 +1,26 @@ +//! Instruction-count probe: compare `catch` with its `plain` loop control. +use perry_runtime::exception::{catch_js_throw, js_eh_try_push, js_try_end}; +use std::hint::black_box; + +fn main() { + let mode = std::env::args().nth(1).unwrap_or_else(|| "catch".into()); + let count: u64 = std::env::args() + .nth(2) + .map(|n| n.parse().unwrap()) + .unwrap_or(1_000_000); + let mut sum = 0; + for i in 0..count { + sum += match mode.as_str() { + "catch" => catch_js_throw(|| black_box(i)).unwrap(), + "unwind" => { + js_eh_try_push(); + let value = black_box(i); + js_try_end(); + value + } + "plain" => black_box(i), + _ => panic!("expected catch, unwind or plain"), + }; + } + println!("{sum}"); +} diff --git a/crates/perry-runtime/src/dyn_eval/mod.rs b/crates/perry-runtime/src/dyn_eval/mod.rs index ad93c0ea7b..3fb7695df2 100644 --- a/crates/perry-runtime/src/dyn_eval/mod.rs +++ b/crates/perry-runtime/src/dyn_eval/mod.rs @@ -271,6 +271,7 @@ pub(crate) fn root_set(idx: usize, value: f64) { ROOTS.with(|r| r.borrow_mut()[idx] = value.to_bits()); } +#[inline] pub(crate) fn roots_len() -> usize { ROOTS.with(|r| r.borrow().len()) } @@ -292,6 +293,7 @@ pub(crate) fn roots_truncate(len: usize) { /// epilogues, so `js_throw` restores both from the savepoint of the catching /// `try` — exactly like the shadow-stack savepoint (#1830) and the /// method-depth savepoint (#5591). +#[inline] pub(crate) fn interp_savepoint() -> u64 { let len = roots_len() as u64; let depth = CALL_DEPTH.with(|c| c.get()) as u64; diff --git a/crates/perry-runtime/src/exception.rs b/crates/perry-runtime/src/exception.rs index 6b861b697a..ef1e4c7283 100644 --- a/crates/perry-runtime/src/exception.rs +++ b/crates/perry-runtime/src/exception.rs @@ -6,7 +6,7 @@ //! `js_throw` raises through the system unwinder //! (`_Unwind_RaiseException`; `RaiseException` on Windows) and the //! frame's `landingpad`/`catchpad` receives control — see `crate::eh`. -//! * **Rust-side boundary traps** (`js_try_push` + `ffi::setjmp`, +//! * **Rust-side boundary traps** (`js_try_push` + the C trampoline, //! `HandlerKind::Setjmp`): runtime helpers that drive user JS from a //! Rust-owned context (`js_call_catching`, promise combinators, iterator //! trampolines) catch via `longjmp` — Rust cannot catch a foreign @@ -42,38 +42,19 @@ impl JmpBuf { } } -use crate::gc::{ - runtime_handle_stack_restore, runtime_handle_stack_savepoint, shadow_stack_restore, - shadow_stack_savepoint, ShadowSavepoint, -}; +mod savepoints; +use savepoints::CatchSavepoint; extern "C" { fn longjmp(env: *mut i32, val: i32) -> !; } -// Maximum nesting depth for try blocks. Backed by fixed-size per-thread -// arrays (see ExceptionState), so this directly sizes thread-local memory: -// jump_buffers is MAX_TRY_DEPTH * sizeof(JmpBuf) (256 B each). 1024 covers -// deep-but-legal recursion-through-try; genuinely unbounded recursion hits a -// native stack overflow well before this. Raised from 128 (#5065): 128 -// aborted the process via panic on legal deeply-nested try/catch. +// Maximum nesting depth for try blocks. All per-depth state lives in one +// fixed heap slab per thread. The slab keeps jump-buffer addresses stable and +// avoids ld64's 64KB inline initialized-TLS limit on arm64_32. Raised from 128 +// (#5065): legal recursion through try/catch must reach 1024 open handlers. const MAX_TRY_DEPTH: usize = 1024; -/// Per-thread exception state. Exception handling uses setjmp/longjmp, -/// and a jmp_buf captured by setjmp on thread A is meaningless on thread -/// B (its stack frame doesn't exist there) — so the buffers, the depth -/// counter, the current exception, and the finally-flag all have to -/// live in TLS once `perry/thread` workers can run user code that -/// throws. Previously this state was process-wide `static mut` data and would -/// corrupt under any concurrent throw. -// arm64_32 fix: the per-depth arrays are HEAP-allocated (`Box<[..]>`) -// instead of stored inline in TLS. At MAX_TRY_DEPTH=1024 they are ~280KB of -// initialized thread-local data (`jump_buffers` alone is 1024 * 256B = 256KB), -// which overflows ld64's 64KB `__thread_data` cap for arm64_32 (and the ILP32 -// TLS layout generally). Boxing leaves only fat pointers + scalars inline in -// TLS; the arrays live on the heap. `[T]` indexing on `Box<[T]>` is -// unchanged, so the accessors below need no edits. (Mirrors the -// TRANSITION_CACHE / VTABLE_IC / INTERN_TABLE boxing.) /// How a handler-stack entry catches (#7302). /// /// `Setjmp`: the handler frame armed a `jmp_buf` (generated setjmp-based @@ -93,68 +74,25 @@ enum HandlerKind { Unwind, } +/// One depth indexes one allocation and one bounds check. The jump buffer +/// stays in a fixed slab, so its address remains valid while a trap is armed. +#[derive(Clone, Copy)] +struct TryFrame { + jump_buffer: JmpBuf, + kind: HandlerKind, + savepoint: CatchSavepoint, +} + +impl TryFrame { + const EMPTY: Self = Self { + jump_buffer: JmpBuf::new(), + kind: HandlerKind::Setjmp, + savepoint: CatchSavepoint::EMPTY, + }; +} + struct ExceptionState { - jump_buffers: Box<[JmpBuf]>, - /// Catch mechanism per open handler, in lockstep with `jump_buffers` - /// (whose slot is simply unused for `Unwind` entries). - handler_kinds: Box<[HandlerKind]>, - /// Shadow-stack depth captured when each `try` block was pushed, so the - /// unwind path can drop the orphaned frames `longjmp` leaves behind (see - /// `js_throw` / issue #1830). Indexed by try-depth, in lockstep with - /// `jump_buffers`. - shadow_savepoints: Box<[ShadowSavepoint]>, - /// Runtime-handle stack depth captured with each `try`. A `longjmp` skips - /// `RuntimeHandleScope` drops, so stale roots must be removed before the - /// catch path can allocate or trigger GC. - runtime_handle_savepoints: Box<[usize]>, - /// `js_native_call_method` recursion depth captured when each `try` was - /// pushed. A throw `longjmp`s past the in-flight method frames, skipping - /// their `CallMethodDepthGuard` `Drop`s; the unwind path restores this so - /// the counter doesn't leak (see `js_throw` / `crate::object`'s - /// `call_method_depth_*`). Indexed by try-depth, in lockstep with - /// `jump_buffers`. - call_method_depths: Box<[u32]>, - /// Re-entrant stdlib-pump depth at handler entry. A callback can throw - /// across `js_run_stdlib_pump`, skipping its `PumpDepthGuard`; restore the - /// counter so the next top-level pump still runs tick-begin lifecycle - /// hooks such as the native-handle quarantine drain. - pump_depths: Box<[u32]>, - /// Active Set/Map `forEach` walks. Their normal epilogues re-enable - /// backing-store compaction, but a caught throw skips those epilogues. - set_foreach_depths: Box<[usize]>, - map_foreach_depths: Box<[usize]>, - /// Recorded-prototype lookup stack depth. A getter can throw while - /// `resolve_inherited_field` is recursively walking; longjmp skips its - /// guard drops, so restore the stack to this try-entry savepoint. - prototype_resolution_depths: Box<[usize]>, - /// Static private-environment dispatch depth at each handler. A throw can - /// bypass a static method/accessor's normal pop, so catch entry restores - /// the stack to its handler-entry state. - static_private_owner_depths: Box<[usize]>, - /// Lexical private-brand dispatch stack depth at each handler. Generated - /// throws bypass normal method epilogues, so the catch path truncates the - /// orphaned entries exactly like the shadow and runtime-handle stacks. - private_lexical_brand_depths: Box<[usize]>, - /// Active derived-constructor binding cells at handler entry. A caught - /// throw can skip an inline constructor's normal scope pop. - derived_super_binding_depths: Box<[usize]>, - /// Pending private-member dispatch hints at handler entry. A throw while - /// evaluating the right-hand side of a guarded private write skips the - /// normal consumer, so catch entry must discard the orphaned hint. - private_member_access_hint_depths: Box<[usize]>, - /// Active allocation-free regex-factory sites at handler entry. A - /// non-literal replacement callee can throw before the wrapper's normal - /// pop, so catch entry discards the orphaned identity frame. - #[cfg(feature = "regex-engine")] - regex_factory_site_depths: Box<[usize]>, - /// #6559: dyn-eval interpreter state (rooted-stack length + interpreter - /// call depth, packed) captured when each `try` was pushed. A throw - /// `longjmp`s past interpreter Rust frames without running their - /// epilogues; the unwind path restores the interpreter's rooted value - /// stack so caught throws neither leak roots nor leave the depth counter - /// wedged. Same savepoint pattern as the two fields above. - #[cfg(feature = "dyn-eval")] - dyn_eval_savepoints: Box<[u64]>, + frames: Box<[TryFrame]>, try_depth: usize, current_exception: f64, has_exception: bool, @@ -162,27 +100,11 @@ struct ExceptionState { } impl ExceptionState { - // No longer `const`: `vec!` builds the arrays directly on the heap (no large - // stack temporary), so first access lazily allocates ~280KB off the TLS. fn new() -> Self { - ExceptionState { - jump_buffers: vec![JmpBuf::new(); MAX_TRY_DEPTH].into_boxed_slice(), - handler_kinds: vec![HandlerKind::Setjmp; MAX_TRY_DEPTH].into_boxed_slice(), - shadow_savepoints: vec![ShadowSavepoint::EMPTY; MAX_TRY_DEPTH].into_boxed_slice(), - runtime_handle_savepoints: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - call_method_depths: vec![0u32; MAX_TRY_DEPTH].into_boxed_slice(), - pump_depths: vec![0u32; MAX_TRY_DEPTH].into_boxed_slice(), - set_foreach_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - map_foreach_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - prototype_resolution_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - static_private_owner_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - private_lexical_brand_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - derived_super_binding_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - private_member_access_hint_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - #[cfg(feature = "regex-engine")] - regex_factory_site_depths: vec![0usize; MAX_TRY_DEPTH].into_boxed_slice(), - #[cfg(feature = "dyn-eval")] - dyn_eval_savepoints: vec![0u64; MAX_TRY_DEPTH].into_boxed_slice(), + Self { + // Build directly on the heap; a slab this large must never be an + // inline TLS initializer or a native-stack temporary (arm64_32). + frames: vec![TryFrame::EMPTY; MAX_TRY_DEPTH].into_boxed_slice(), try_depth: 0, current_exception: 0.0, has_exception: false, @@ -235,43 +157,12 @@ fn try_push_with_kind(kind: HandlerKind) -> *mut i32 { panic!("Try block nesting too deep"); } let depth = (*s).try_depth; - (*s).handler_kinds[depth] = kind; - // Capture the shadow-stack depth now, before the protected region - // can push any callee frames, so the unwind path can restore to - // exactly this point and drop the frames `longjmp` orphans (#1830). - (*s).shadow_savepoints[depth] = shadow_stack_savepoint(); - (*s).runtime_handle_savepoints[depth] = runtime_handle_stack_savepoint(); - // Capture the method-dispatch recursion depth too, so a throw caught by - // this `try` can restore it — `longjmp` skips the `CallMethodDepthGuard` - // `Drop`s of the method frames it unwinds (#5591). - (*s).call_method_depths[depth] = crate::object::call_method_depth_savepoint(); - (*s).pump_depths[depth] = crate::stdlib_pump::pump_depth_savepoint(); - (*s).set_foreach_depths[depth] = crate::set::set_foreach_stack_savepoint(); - (*s).map_foreach_depths[depth] = crate::map::map_foreach_stack_savepoint(); - (*s).prototype_resolution_depths[depth] = - crate::object::prototype_chain::resolution_stack_savepoint(); - (*s).static_private_owner_depths[depth] = - crate::object::static_private_owner_stack_savepoint(); - (*s).private_lexical_brand_depths[depth] = - crate::object::private_lexical_brand_stack_savepoint(); - (*s).derived_super_binding_depths[depth] = - crate::object::derived_super_binding_stack_savepoint(); - (*s).private_member_access_hint_depths[depth] = - crate::object::private_member_access_hints_savepoint(); - #[cfg(feature = "regex-engine")] - { - (*s).regex_factory_site_depths[depth] = - crate::regex::site_test::active_factory_stack_savepoint(); - } - // #6559: capture the dyn-eval interpreter's rooted-stack length + - // call depth, so a caught throw restores interpreter state exactly - // like the shadow stack. - #[cfg(feature = "dyn-eval")] - { - (*s).dyn_eval_savepoints[depth] = crate::dyn_eval::interp_savepoint(); - } + let savepoint = CatchSavepoint::capture(); + let frame = &mut (*s).frames[depth]; + frame.kind = kind; + frame.savepoint = savepoint; (*s).try_depth += 1; - (*s).jump_buffers[depth].as_mut_ptr() + frame.jump_buffer.as_mut_ptr() }) } @@ -468,52 +359,16 @@ pub extern "C-unwind" fn js_throw(value: f64) -> ! { // restore code this longjmp skips (#788). Pure thread-local state // swaps — no JS runs and nothing allocates. crate::async_context::unwind_context_guards(depth); - // Drop the shadow-stack frames of the functions we are about to - // unwind past. `longjmp` skips their epilogues (and therefore their - // `js_shadow_frame_pop` calls), so without this the next GC would - // scan — and the copying collector would rewrite — slots living in - // already-unwound stack frames (#1830). Restore to the depth captured - // when this `try` was pushed. - shadow_stack_restore((*s).shadow_savepoints[depth]); - runtime_handle_stack_restore((*s).runtime_handle_savepoints[depth]); - // Restore the method-dispatch recursion depth captured when this `try` - // was pushed. The direct and longjmp transports skip the guards' - // `Drop`s. A system-unwinder fallback does run them, but the guards use - // their entry depths to make cleanup after this eager restore a no-op; - // otherwise caught throws wrap the counter below zero and wedge every - // later method call into the depth-guard fallback (#5591). - crate::object::call_method_depth_restore((*s).call_method_depths[depth]); - crate::stdlib_pump::pump_depth_restore((*s).pump_depths[depth]); - crate::set::set_foreach_stack_restore((*s).set_foreach_depths[depth]); - crate::map::map_foreach_stack_restore((*s).map_foreach_depths[depth]); - crate::object::prototype_chain::resolution_stack_restore( - (*s).prototype_resolution_depths[depth], - ); - crate::object::static_private_owner_stack_restore((*s).static_private_owner_depths[depth]); - crate::object::private_lexical_brand_stack_restore( - (*s).private_lexical_brand_depths[depth], - ); - crate::object::derived_super_binding_stack_restore( - (*s).derived_super_binding_depths[depth], - ); - crate::object::private_member_access_hints_restore( - (*s).private_member_access_hint_depths[depth], - ); - #[cfg(feature = "regex-engine")] - crate::regex::site_test::active_factory_stack_restore( - (*s).regex_factory_site_depths[depth], - ); - // #6559: restore the dyn-eval interpreter's rooted stack + call depth - // (interpreter Rust frames unwound by this longjmp never run their - // truncate/decrement epilogues). - #[cfg(feature = "dyn-eval")] - crate::dyn_eval::interp_restore((*s).dyn_eval_savepoints[depth]); + // Restore every subsystem before transporting the exception. The + // registration generates capture and restore together, including the + // feature-gated entries; the test replay uses this exact path too. + (*s).frames[depth].savepoint.restore(); // The savepoint restores above are transport-independent: the unwind // path skips Rust cleanups exactly like longjmp does (the runtime is // built panic=abort; see crate::eh), so restoring at throw time is // correct for both. - match (*s).handler_kinds[depth] { - HandlerKind::Setjmp => (*s).jump_buffers[depth].as_mut_ptr(), + match (*s).frames[depth].kind { + HandlerKind::Setjmp => (*s).frames[depth].jump_buffer.as_mut_ptr(), HandlerKind::Unwind => std::ptr::null_mut(), } }); @@ -850,31 +705,14 @@ pub(crate) fn test_try_depth() -> usize { with_exception_state(|s| unsafe { (*s).try_depth }) } -/// Replay the shadow-stack restore that `js_throw` performs for the -/// innermost open `try`, without the `longjmp` (which can't return in a -/// unit test). Lets tests exercise the real #1830 savepoint/restore path -/// recorded by `js_try_push`. +/// Replay the production savepoint restoration without transporting an +/// exception. Legacy subsystem tests use this; each registration additionally +/// has a nested real-throw test in `savepoints::restore_tests`. #[cfg(test)] pub(crate) fn test_unwind_innermost_shadow_restore() { with_exception_state(|s| unsafe { assert!((*s).try_depth > 0, "no open try to unwind"); - let depth = (*s).try_depth - 1; - shadow_stack_restore((*s).shadow_savepoints[depth]); - runtime_handle_stack_restore((*s).runtime_handle_savepoints[depth]); - crate::object::call_method_depth_restore((*s).call_method_depths[depth]); - crate::stdlib_pump::pump_depth_restore((*s).pump_depths[depth]); - crate::set::set_foreach_stack_restore((*s).set_foreach_depths[depth]); - crate::map::map_foreach_stack_restore((*s).map_foreach_depths[depth]); - crate::object::prototype_chain::resolution_stack_restore( - (*s).prototype_resolution_depths[depth], - ); - crate::object::private_member_access_hints_restore( - (*s).private_member_access_hint_depths[depth], - ); - #[cfg(feature = "regex-engine")] - crate::regex::site_test::active_factory_stack_restore( - (*s).regex_factory_site_depths[depth], - ); + (*s).frames[(*s).try_depth - 1].savepoint.restore(); }); } @@ -951,7 +789,7 @@ mod tests { // Relative to the entry depth so it's robust under shared TLS // (`--test-threads=1`) alongside the other tests in this module. let base = current_try_depth(); - let pushes = (MAX_TRY_DEPTH - base) - 1; + let pushes = MAX_TRY_DEPTH - base; assert!( pushes > 128, "expected room for >128 frames beyond the old limit" diff --git a/crates/perry-runtime/src/exception/savepoints.rs b/crates/perry-runtime/src/exception/savepoints.rs new file mode 100644 index 0000000000..5193a62d55 --- /dev/null +++ b/crates/perry-runtime/src/exception/savepoints.rs @@ -0,0 +1,97 @@ +//! One declaration per catch savepoint: storage, capture, restore and a real +//! throw witness are generated together. The order here is also restore order. +//! +//! Capture providers are inlined so their HotKey accesses share the existing +//! hot TLS cache. No live subsystem state is mirrored or journaled, and the +//! cold restore path continues to use each subsystem's own cleanup rules. + +use crate::gc::ShadowSavepoint; + +macro_rules! catch_savepoints { + ($($(#[$attr:meta])* $name:ident: $ty:ty = $empty:expr, + capture: $capture:path, restore: $restore:path;)*) => { + #[derive(Clone, Copy)] + pub(super) struct CatchSavepoint { + $($(#[$attr])* $name: $ty,)* + } + + impl CatchSavepoint { + pub(super) const EMPTY: Self = Self { + $($(#[$attr])* $name: $empty,)* + }; + + #[inline(always)] + pub(super) fn capture() -> Self { + Self { $($(#[$attr])* $name: $capture(),)* } + } + + pub(super) fn restore(self) { + $($(#[$attr])* $restore(self.$name);)* + } + } + + #[cfg(test)] + mod restore_tests { + use super::tests; + $($(#[$attr])* + #[test] + fn $name() { + tests::assert_nested_restore($capture, $restore, tests::$name); + } + )* + } + }; +} + +catch_savepoints! { + // #1830, #6951: both shadow frames and expression temp roots. + shadow: ShadowSavepoint = ShadowSavepoint::EMPTY, + capture: crate::gc::shadow_stack_savepoint, + restore: crate::gc::shadow_stack_restore; + // Longjmp skips RuntimeHandleScope drops. + runtime_handles: usize = 0, + capture: crate::gc::runtime_handle_stack_savepoint, + restore: crate::gc::runtime_handle_stack_restore; + // #5591: skipped method guards must not wedge the recursion counter. + call_method: u32 = 0, + capture: crate::object::call_method_depth_savepoint, + restore: crate::object::call_method_depth_restore; + // Includes removal of the process-wide outer-pump contribution. + pump: u32 = 0, + capture: crate::stdlib_pump::pump_depth_savepoint, + restore: crate::stdlib_pump::pump_depth_restore; + // #9082: abandoned walks must no longer inhibit compaction. + set_foreach: usize = 0, + capture: crate::set::set_foreach_stack_savepoint, + restore: crate::set::set_foreach_stack_restore; + map_foreach: usize = 0, + capture: crate::map::map_foreach_stack_savepoint, + restore: crate::map::map_foreach_stack_restore; + prototype_resolution: usize = 0, + capture: crate::object::prototype_chain::resolution_stack_savepoint, + restore: crate::object::prototype_chain::resolution_stack_restore; + static_private_owner: usize = 0, + capture: crate::object::static_private_owner_stack_savepoint, + restore: crate::object::static_private_owner_stack_restore; + private_lexical_brand: usize = 0, + capture: crate::object::private_lexical_brand_stack_savepoint, + restore: crate::object::private_lexical_brand_stack_restore; + derived_super_binding: usize = 0, + capture: crate::object::derived_super_binding_stack_savepoint, + restore: crate::object::derived_super_binding_stack_restore; + private_member_access_hints: usize = 0, + capture: crate::object::private_member_access_hints_savepoint, + restore: crate::object::private_member_access_hints_restore; + #[cfg(feature = "regex-engine")] + regex_factory: usize = 0, + capture: crate::regex::site_test::active_factory_stack_savepoint, + restore: crate::regex::site_test::active_factory_stack_restore; + // #6559: rooted interpreter values AND the packed call depth. + #[cfg(feature = "dyn-eval")] + dyn_eval: u64 = 0, + capture: crate::dyn_eval::interp_savepoint, + restore: crate::dyn_eval::interp_restore; +} + +#[cfg(test)] +mod tests; diff --git a/crates/perry-runtime/src/exception/savepoints/tests.rs b/crates/perry-runtime/src/exception/savepoints/tests.rs new file mode 100644 index 0000000000..0f0865f133 --- /dev/null +++ b/crates/perry-runtime/src/exception/savepoints/tests.rs @@ -0,0 +1,136 @@ +use crate::exception::{catch_js_throw, current_try_depth, js_has_exception, js_throw}; +use std::fmt::Debug; + +/// Every registered subsystem must supply a witness that changes real state. +/// Test both nested landings with a nonempty outer scope, and run through the +/// production js_throw + C trampoline, never a test-only replay of cleanup. +pub(super) fn assert_nested_restore( + capture: fn() -> T, + restore: fn(T), + push: fn(u32), +) { + struct Reset { + value: T, + restore: fn(T), + } + impl Drop for Reset { + fn drop(&mut self) { + (self.restore)(self.value); + } + } + + let _lock = crate::gc::global_side_table_test_lock(); + let base = capture(); + // This guard lives outside every abandoned frame, including on a failing + // assertion in the catch path. It also keeps injected faults isolated. + let _reset = Reset { + value: base, + restore, + }; + let try_base = current_try_depth(); + push(1); + let outer = capture(); + assert_ne!(outer, base, "fixture must establish live outer state"); + let outcome: Result<(), f64> = catch_js_throw(|| { + push(2); + let inner = capture(); + assert_ne!( + inner, outer, + "fixture must change state inside the outer trap" + ); + let nested: Result<(), f64> = catch_js_throw(|| { + push(3); + assert_ne!( + capture(), + inner, + "fixture must change state inside the inner trap" + ); + js_throw(31.0) + }); + assert_eq!(nested, Err(31.0)); + assert_eq!( + capture(), + inner, + "inner catch must preserve its enclosing scope" + ); + assert_eq!(current_try_depth(), try_base + 1); + js_throw(47.0) + }); + assert_eq!(outcome, Err(47.0)); + assert_eq!( + capture(), + outer, + "outer catch must preserve the preexisting scope" + ); + assert_eq!(current_try_depth(), try_base); + assert_eq!(js_has_exception(), 0); + assert_eq!(catch_js_throw(|| push(4)), Ok(())); + assert_ne!( + capture(), + outer, + "normal completion must not replay cleanup" + ); + assert_eq!(current_try_depth(), try_base); +} + +pub(super) fn shadow(marker: u32) { + crate::gc::js_shadow_frame_push(marker); + crate::gc::js_shadow_slot_set(0, (marker as f64).to_bits()); + crate::gc::js_gc_temp_root_push((marker as f64).to_bits()); +} + +pub(super) fn runtime_handles(marker: u32) { + let scope = crate::gc::RuntimeHandleScope::new(); + scope.root_nanbox_f64(marker as f64); + std::mem::forget(scope); +} + +pub(super) fn call_method(_: u32) { + crate::object::test_enter_catch_method(); +} + +pub(super) fn pump(_: u32) { + crate::stdlib_pump::test_enter_catch_pump(); +} + +pub(super) fn set_foreach(_: u32) { + crate::set::test_enter_catch_foreach(); +} + +pub(super) fn map_foreach(_: u32) { + crate::map::test_enter_catch_foreach(); +} + +pub(super) fn prototype_resolution(_: u32) { + let owner = crate::object::js_object_alloc(0, 0); + assert!(crate::object::prototype_chain::test_resolution_stack_enter_and_forget(owner as usize)); +} + +pub(super) fn static_private_owner(marker: u32) { + crate::object::static_private_owner_push(marker as f64); +} + +pub(super) fn private_lexical_brand(marker: u32) { + crate::object::private_lexical_brand_push(marker as f64); +} + +pub(super) fn derived_super_binding(_: u32) { + // The production stack stores native alloca addresses. No binding is + // evaluated here, so an empty address suffices for the lifetime witness. + crate::object::js_derived_super_scope_push(std::ptr::null_mut()); +} + +pub(super) fn private_member_access_hints(marker: u32) { + crate::object::test_push_catch_private_hint(marker); +} + +#[cfg(feature = "regex-engine")] +pub(super) fn regex_factory(marker: u32) { + crate::regex::site_test::test_enter_catch_factory(marker); +} + +#[cfg(feature = "dyn-eval")] +pub(super) fn dyn_eval(marker: u32) { + crate::dyn_eval::root_push(marker as f64); + crate::dyn_eval::call_depth_enter().unwrap(); +} diff --git a/crates/perry-runtime/src/gc/roots/runtime_handles.rs b/crates/perry-runtime/src/gc/roots/runtime_handles.rs index b3ea2b8d6b..755d767261 100644 --- a/crates/perry-runtime/src/gc/roots/runtime_handles.rs +++ b/crates/perry-runtime/src/gc/roots/runtime_handles.rs @@ -185,6 +185,7 @@ impl RuntimeHandleScope { /// Snapshot the transient-handle stack before a callback may throw across /// Rust frames. `longjmp` skips `RuntimeHandleScope::drop`, so exception /// unwinding restores this depth explicitly. +#[inline] pub(crate) fn runtime_handle_stack_savepoint() -> usize { runtime_handle_stack().len() } diff --git a/crates/perry-runtime/src/gc/roots/shadow_stack.rs b/crates/perry-runtime/src/gc/roots/shadow_stack.rs index 3f17b47f12..27c562c554 100644 --- a/crates/perry-runtime/src/gc/roots/shadow_stack.rs +++ b/crates/perry-runtime/src/gc/roots/shadow_stack.rs @@ -729,7 +729,7 @@ pub(crate) fn shadow_stack_has_active_frame() -> bool { /// reaches its `js_gc_temp_root_truncate`. That depth is therefore recorded /// here and restored with the frames, so one savepoint covers both precise /// root stacks and `crate::exception` needs no separate hook. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) struct ShadowSavepoint { frame_top: usize, len: usize, @@ -749,6 +749,7 @@ impl ShadowSavepoint { /// Capture the current shadow-stack depth so it can be restored after a /// non-local exit. Call at `js_try_push` time, before the protected /// region can push any callee frames. +#[inline] pub(crate) fn shadow_stack_savepoint() -> ShadowSavepoint { SHADOW.with(|cell| unsafe { let s = &*cell.get(); diff --git a/crates/perry-runtime/src/gc/roots/temp_roots.rs b/crates/perry-runtime/src/gc/roots/temp_roots.rs index 8405fdf8d9..0bcbb877bc 100644 --- a/crates/perry-runtime/src/gc/roots/temp_roots.rs +++ b/crates/perry-runtime/src/gc/roots/temp_roots.rs @@ -176,6 +176,7 @@ pub extern "C" fn js_array_push_f64_temp_rooted(idx: u32, value: f64) { } /// Current depth — the value a savepoint records. +#[inline] pub(crate) fn temp_root_depth() -> usize { unsafe { (*hot_temp_roots()).len() } } diff --git a/crates/perry-runtime/src/lib.rs b/crates/perry-runtime/src/lib.rs index c540da6335..254dbc3792 100644 --- a/crates/perry-runtime/src/lib.rs +++ b/crates/perry-runtime/src/lib.rs @@ -468,10 +468,16 @@ pub(crate) mod stdlib_pump { } } + #[cfg(test)] + pub(crate) fn test_enter_catch_pump() { + std::mem::forget(PumpDepthGuard::enter().0); + } + /// Capture the re-entrant stdlib-pump depth at `try` entry. A caught JS /// throw can longjmp past `PumpDepthGuard::drop`; exception handling uses /// this savepoint to keep the next top-level pump recognizable as a new /// tick (and therefore run its lifecycle hooks). + #[inline] pub(crate) fn pump_depth_savepoint() -> u32 { PUMP_DEPTH.with(|depth| depth.get()) } diff --git a/crates/perry-runtime/src/map.rs b/crates/perry-runtime/src/map.rs index 7fb8e0c0cb..78a6ae60da 100644 --- a/crates/perry-runtime/src/map.rs +++ b/crates/perry-runtime/src/map.rs @@ -43,6 +43,7 @@ fn map_foreach_leave(map: *const MapHeader) -> bool { }) } +#[inline] pub(crate) fn map_foreach_stack_savepoint() -> usize { MAP_FOREACH_STACK.with(|stack| stack.borrow().len()) } @@ -4027,3 +4028,8 @@ mod tests { #[cfg(test)] #[path = "map_tombstone_tests.rs"] mod map_tombstone_tests; + +#[cfg(test)] +pub(crate) fn test_enter_catch_foreach() { + map_foreach_enter(js_map_alloc(4)); +} diff --git a/crates/perry-runtime/src/object/call_method_depth.rs b/crates/perry-runtime/src/object/call_method_depth.rs index c48f1ea2ac..848e48dc59 100644 --- a/crates/perry-runtime/src/object/call_method_depth.rs +++ b/crates/perry-runtime/src/object/call_method_depth.rs @@ -60,6 +60,7 @@ impl Drop for CallMethodDepthGuard { /// dispatching). System unwinding does run those drops; guards remember their /// entry depths so the eager restore makes their later cleanup a no-op instead /// of a second decrement. See `crate::exception::{js_try_push, js_throw}`. +#[inline] pub(crate) fn call_method_depth_savepoint() -> u32 { CALL_METHOD_DEPTH.with(|d| d.get()) } @@ -70,3 +71,8 @@ pub(crate) fn call_method_depth_savepoint() -> u32 { pub(crate) fn call_method_depth_restore(depth: u32) { CALL_METHOD_DEPTH.with(|d| d.set(depth)); } + +#[cfg(test)] +pub(crate) fn test_enter_catch_method() { + std::mem::forget(CallMethodDepthGuard::enter("catch-savepoint").unwrap()); +} diff --git a/crates/perry-runtime/src/object/field_get_set.rs b/crates/perry-runtime/src/object/field_get_set.rs index dc9438fcd3..9ff187b390 100644 --- a/crates/perry-runtime/src/object/field_get_set.rs +++ b/crates/perry-runtime/src/object/field_get_set.rs @@ -291,8 +291,6 @@ pub(crate) use has_property::{ wide_key_index_lookup, wide_key_index_note_hit, WIDE_KEY_INDEX_MIN_KEYS, }; pub use has_property::{js_in_operator, js_object_has_property}; -#[cfg(test)] -pub(crate) use ic_miss::primitive_proto_method_name_static; pub(crate) use ic_miss::{ bind_primitive_proto_method_static, cannot_be_private_member_name, current_private_lexical_brand_value, is_array_method_value_name, @@ -309,6 +307,8 @@ pub use ic_miss::{ js_object_set_field_by_property_id, js_private_brand_add, js_private_brand_check, js_private_field_add, js_private_guard, PicCache, PicCacheSlot, PIC_CACHE_WORDS, }; +#[cfg(test)] +pub(crate) use ic_miss::{primitive_proto_method_name_static, test_push_catch_private_hint}; /// The one slow exit of the emitted generic property-get tower. Declared here /// rather than inside `ic_miss.rs` only because that file sits at the /// 2000-line cap; the source lives next to its sibling entries. diff --git a/crates/perry-runtime/src/object/field_get_set/ic_miss.rs b/crates/perry-runtime/src/object/field_get_set/ic_miss.rs index 9cedc25adb..0babcbf77e 100644 --- a/crates/perry-runtime/src/object/field_get_set/ic_miss.rs +++ b/crates/perry-runtime/src/object/field_get_set/ic_miss.rs @@ -1274,6 +1274,7 @@ pub(crate) fn private_lexical_brand_pop() { }); } +#[inline] pub(crate) fn private_lexical_brand_stack_savepoint() -> usize { PRIVATE_LEXICAL_BRAND_STACK.with(|stack| stack.borrow().len()) } diff --git a/crates/perry-runtime/src/object/field_get_set/ic_miss/private_member_access.rs b/crates/perry-runtime/src/object/field_get_set/ic_miss/private_member_access.rs index 3025840726..4ddb8b7b74 100644 --- a/crates/perry-runtime/src/object/field_get_set/ic_miss/private_member_access.rs +++ b/crates/perry-runtime/src/object/field_get_set/ic_miss/private_member_access.rs @@ -18,6 +18,7 @@ struct PrivateMemberAccessHint { is_write: bool, } +#[inline] pub(crate) fn private_member_access_hints_savepoint() -> usize { PRIVATE_MEMBER_ACCESS_HINTS.with(|hints| hints.borrow().len()) } @@ -373,3 +374,16 @@ fn throw_private_type_error(msg: &str) -> ! { let v = crate::value::JSValue::pointer(err as *const u8).bits(); crate::exception::js_throw(f64::from_bits(v)) } + +#[cfg(test)] +pub(crate) fn test_push_catch_private_hint(marker: u32) { + PRIVATE_MEMBER_ACCESS_HINTS.with(|hints| { + hints.borrow_mut().push(PrivateMemberAccessHint { + class_id: marker, + name: format!("catch-savepoint-{marker}"), + kind: 0, + is_static: false, + is_write: true, + }); + }); +} diff --git a/crates/perry-runtime/src/object/global_this/fetch_globals.rs b/crates/perry-runtime/src/object/global_this/fetch_globals.rs index 2051ae5807..f27c058eec 100644 --- a/crates/perry-runtime/src/object/global_this/fetch_globals.rs +++ b/crates/perry-runtime/src/object/global_this/fetch_globals.rs @@ -166,10 +166,17 @@ pub unsafe extern "C" fn js_global_or_console_property_by_name( /// sentinels directly (e.g. `globalThis.Array(3)`) returns undefined — /// best-effort no-op rather than throwing — and remains a known gap for /// non-String call-form constructors after re-binding the global to a local. +// This function's address identifies builtin constructors across separately +// linked runtime and stdlib archives. Thin LTO must not replace each copy with +// a different unrelated undefined-returning thunk. Keep one external symbol +// and a distinct body, even when changes elsewhere alter LTO partitioning. +#[no_mangle] +#[inline(never)] pub(crate) extern "C" fn global_this_builtin_noop_thunk( _closure: *const crate::closure::ClosureHeader, _arg: f64, ) -> f64 { + std::hint::black_box(global_this_builtin_noop_thunk as *const u8); f64::from_bits(crate::value::TAG_UNDEFINED) } diff --git a/crates/perry-runtime/src/object/mod.rs b/crates/perry-runtime/src/object/mod.rs index 3870a0d455..c069973a18 100644 --- a/crates/perry-runtime/src/object/mod.rs +++ b/crates/perry-runtime/src/object/mod.rs @@ -296,6 +296,8 @@ pub(crate) use field_get_set::{ private_member_access_hints_restore, private_member_access_hints_savepoint, scan_private_lexical_brand_roots_mut, }; +#[cfg(test)] +pub(crate) use this_binding::js_derived_super_scope_push; pub(crate) use this_binding::{ derived_super_binding_stack_restore, derived_super_binding_stack_savepoint, scan_implicit_this_roots_mut, static_private_owner_current, static_private_owner_pop, @@ -594,6 +596,8 @@ pub(crate) use keys_lookup::*; pub(crate) mod array_tail_transition; mod call_method_depth; +#[cfg(test)] +pub(crate) use call_method_depth::test_enter_catch_method; mod meta_accessors; use call_method_depth::CallMethodDepthGuard; pub(crate) use call_method_depth::{call_method_depth_restore, call_method_depth_savepoint}; diff --git a/crates/perry-runtime/src/object/prototype_chain.rs b/crates/perry-runtime/src/object/prototype_chain.rs index f9100deb31..9fcf0904f4 100644 --- a/crates/perry-runtime/src/object/prototype_chain.rs +++ b/crates/perry-runtime/src/object/prototype_chain.rs @@ -89,6 +89,7 @@ impl Drop for PrototypeResolutionGuard { } } +#[inline] pub(crate) fn resolution_stack_savepoint() -> usize { PROTOTYPE_RESOLUTION_STACK.with(|stack| stack.borrow().len()) } diff --git a/crates/perry-runtime/src/object/this_binding.rs b/crates/perry-runtime/src/object/this_binding.rs index b8421f2a19..5fe88a66f3 100644 --- a/crates/perry-runtime/src/object/this_binding.rs +++ b/crates/perry-runtime/src/object/this_binding.rs @@ -84,6 +84,7 @@ pub(crate) fn static_private_owner_current() -> Option { STATIC_PRIVATE_OWNER_STACK.with(|stack| stack.borrow().last().copied().map(f64::from_bits)) } +#[inline] pub(crate) fn static_private_owner_stack_savepoint() -> usize { STATIC_PRIVATE_OWNER_STACK.with(|stack| stack.borrow().len()) } @@ -327,6 +328,7 @@ pub extern "C" fn js_derived_super_scope_pop() { }); } +#[inline] pub(crate) fn derived_super_binding_stack_savepoint() -> usize { DERIVED_SUPER_BINDING_STACK.with(|stack| stack.borrow().len()) } diff --git a/crates/perry-runtime/src/regex/site_test.rs b/crates/perry-runtime/src/regex/site_test.rs index a21e388304..2f3f94a268 100644 --- a/crates/perry-runtime/src/regex/site_test.rs +++ b/crates/perry-runtime/src/regex/site_test.rs @@ -295,6 +295,7 @@ impl Drop for ActiveFactoryGuard { } } +#[inline] pub(crate) fn active_factory_stack_savepoint() -> usize { ACTIVE_FACTORY_SITES.with(|stack| stack.borrow().len()) } @@ -538,6 +539,11 @@ pub(super) fn test_header(site_key: usize) -> Option { lookup(site_key).map(|(header, _)| header as usize) } +#[cfg(test)] +pub(crate) fn test_enter_catch_factory(marker: u32) { + std::mem::forget(ActiveFactoryGuard::push(marker as usize, usize::MAX)); +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/perry-runtime/src/set.rs b/crates/perry-runtime/src/set.rs index 2011b8ead8..e8393cca3b 100644 --- a/crates/perry-runtime/src/set.rs +++ b/crates/perry-runtime/src/set.rs @@ -42,6 +42,7 @@ fn set_foreach_leave(set: *const SetHeader) -> bool { }) } +#[inline] pub(crate) fn set_foreach_stack_savepoint() -> usize { SET_FOREACH_STACK.with(|stack| stack.borrow().len()) } @@ -3309,3 +3310,8 @@ mod ordered_delete_repair_tests { #[cfg(test)] #[path = "set_tombstone_tests.rs"] mod set_tombstone_tests; + +#[cfg(test)] +pub(crate) fn test_enter_catch_foreach() { + set_foreach_enter(js_set_alloc(4)); +} From 068058b61ffb1efee8cdfd0baaa67d1d99db15d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 08:53:15 +0200 Subject: [PATCH 2/8] docs: key catch-frame changeset to PR 10257 --- changelog.d/{catch-frames.md => 10257-catch-frames.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{catch-frames.md => 10257-catch-frames.md} (100%) diff --git a/changelog.d/catch-frames.md b/changelog.d/10257-catch-frames.md similarity index 100% rename from changelog.d/catch-frames.md rename to changelog.d/10257-catch-frames.md From 1c832b411e8230cb71e64731b98842dad26e2c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 12:21:40 +0200 Subject: [PATCH 3/8] fix(runtime): keep catch snapshots compact and initialize active slots only --- benchmarks/catch_frames/README.md | 21 +++++-- benchmarks/catch_frames/fault_restore.py | 2 +- changelog.d/10257-catch-frames.md | 2 + crates/perry-runtime/src/exception.rs | 59 +++++++++---------- .../perry-runtime/src/exception/savepoints.rs | 32 +++++----- .../src/gc/roots/shadow_stack.rs | 9 --- 6 files changed, 61 insertions(+), 64 deletions(-) diff --git a/benchmarks/catch_frames/README.md b/benchmarks/catch_frames/README.md index bf08755316..4902cdffb4 100644 --- a/benchmarks/catch_frames/README.md +++ b/benchmarks/catch_frames/README.md @@ -8,10 +8,18 @@ same snapshot capture, although its exception transport uses the system unwinder ## Design and correctness -`exception::TryFrame` stores the jump buffer, handler kind and `CatchSavepoint` -in one fixed, heap-allocated slab. A depth indexes one allocation instead of -separate boxed arrays. The slab never grows, so jump-buffer addresses remain -stable. The 1,024-handler limit and try-depth accounting are unchanged. +`ExceptionState` keeps fixed jump-buffer and handler-kind slabs alongside one +slab of per-depth `CatchSavepoint` records. Grouping the captured fields removes +their separate savepoint arrays. Keeping jump buffers separately aligned avoids +the submitted all-in-one record's 15 KiB of padding per thread on the default +64-bit build. The slabs never grow, so jump-buffer addresses remain stable. +The 1,024-handler limit and try-depth accounting are unchanged. + +Snapshot slots use `MaybeUninit`: a push writes every field before incrementing +`try_depth`, and restoration reads only a published handler's initialized slot. +Inactive snapshots are neither read nor scanned. This also avoids eagerly +writing the nonzero shadow-stack sentinel throughout unused snapshot pages. +The record is `Copy`, so no owned resources need destruction in inactive slots. `exception/savepoints.rs` declares each snapshot field together with its capture provider, restore provider and required real-throw witness. The macro @@ -43,6 +51,11 @@ original source in `finally`, then requires the exception suite to pass. ## Instruction measurements, 2026-09-14 +The historical numbers below describe the submitted all-in-one record layout. +The landing train remeasures the adjusted storage against its merged baseline +with the same package selection and records CPU/instruction and RSS results +separately; these historical numbers are not measurements of that adjustment. + Baseline: main `eb13fa188d` (0.5.1564), which already includes the #10215 large-array corruption fix. Host: perrymaster, AMD Ryzen 7 7700X, Linux 6.17.0-23-generic, perf 6.17.13, Rust nightly 2026-08-20 diff --git a/benchmarks/catch_frames/fault_restore.py b/benchmarks/catch_frames/fault_restore.py index 7d2819d535..1eefd12f03 100644 --- a/benchmarks/catch_frames/fault_restore.py +++ b/benchmarks/catch_frames/fault_restore.py @@ -30,7 +30,7 @@ def main(): original = path.read_text() needle = "$($(#[$attr])* $restore(self.$name);)*" assert original.count(needle) == 1 - names = re.findall(r"^ (\w+): [^\n]+ = ", original, flags=re.MULTILINE) + names = re.findall(r"^ (\w+): [^\n]+,\n capture: ", original, flags=re.MULTILINE) captures = re.findall(r"^ capture: ", original, flags=re.MULTILINE) assert names and len(names) == len(set(names)) == len(captures), names mutant = original.replace(needle, '''$($(#[$attr])* { diff --git a/changelog.d/10257-catch-frames.md b/changelog.d/10257-catch-frames.md index c1b269f8ba..f0a68d0190 100644 --- a/changelog.d/10257-catch-frames.md +++ b/changelog.d/10257-catch-frames.md @@ -3,3 +3,5 @@ reduce catch setup overhead. A shared declaration now couples each subsystem's capture, restore and nested real-throw regression test, while runtime traps continue to use the C `setjmp` trampoline. Preserve builtin constructor marker identity across Thin LTO runtime archives. +Keep jump buffers separately aligned and initialize only published snapshots, +avoiding per-frame padding and eager writes to inactive snapshot pages. diff --git a/crates/perry-runtime/src/exception.rs b/crates/perry-runtime/src/exception.rs index ef1e4c7283..18ac672844 100644 --- a/crates/perry-runtime/src/exception.rs +++ b/crates/perry-runtime/src/exception.rs @@ -49,9 +49,9 @@ extern "C" { fn longjmp(env: *mut i32, val: i32) -> !; } -// Maximum nesting depth for try blocks. All per-depth state lives in one -// fixed heap slab per thread. The slab keeps jump-buffer addresses stable and -// avoids ld64's 64KB inline initialized-TLS limit on arm64_32. Raised from 128 +// Maximum nesting depth for try blocks. Per-depth state lives in fixed heap +// slabs per thread. They keep jump-buffer addresses stable and +// avoid ld64's 64KB inline initialized-TLS limit on arm64_32. Raised from 128 // (#5065): legal recursion through try/catch must reach 1024 open handlers. const MAX_TRY_DEPTH: usize = 1024; @@ -74,25 +74,13 @@ enum HandlerKind { Unwind, } -/// One depth indexes one allocation and one bounds check. The jump buffer -/// stays in a fixed slab, so its address remains valid while a trap is armed. -#[derive(Clone, Copy)] -struct TryFrame { - jump_buffer: JmpBuf, - kind: HandlerKind, - savepoint: CatchSavepoint, -} - -impl TryFrame { - const EMPTY: Self = Self { - jump_buffer: JmpBuf::new(), - kind: HandlerKind::Setjmp, - savepoint: CatchSavepoint::EMPTY, - }; -} - struct ExceptionState { - frames: Box<[TryFrame]>, + // Group captured fields per depth, but keep jump buffers separately aligned. + // Putting their 16-byte alignment and a one-byte kind into every record + // adds 15 KiB of padding per thread in the default 64-bit configuration. + jump_buffers: Box<[JmpBuf]>, + handler_kinds: Box<[HandlerKind]>, + savepoints: Box<[std::mem::MaybeUninit]>, try_depth: usize, current_exception: f64, has_exception: bool, @@ -102,9 +90,14 @@ struct ExceptionState { impl ExceptionState { fn new() -> Self { Self { - // Build directly on the heap; a slab this large must never be an - // inline TLS initializer or a native-stack temporary (arm64_32). - frames: vec![TryFrame::EMPTY; MAX_TRY_DEPTH].into_boxed_slice(), + // Build the fixed slabs directly on the heap, without large TLS + // initializers or native-stack temporaries (arm64_32). + jump_buffers: vec![JmpBuf::new(); MAX_TRY_DEPTH].into_boxed_slice(), + handler_kinds: vec![HandlerKind::Setjmp; MAX_TRY_DEPTH].into_boxed_slice(), + // Each push writes a complete snapshot before incrementing try_depth. + // Inactive slots are never read or scanned. Avoid touching every + // page with the shadow-stack sentinel at thread initialization. + savepoints: Box::<[CatchSavepoint]>::new_uninit_slice(MAX_TRY_DEPTH), try_depth: 0, current_exception: 0.0, has_exception: false, @@ -158,11 +151,10 @@ fn try_push_with_kind(kind: HandlerKind) -> *mut i32 { } let depth = (*s).try_depth; let savepoint = CatchSavepoint::capture(); - let frame = &mut (*s).frames[depth]; - frame.kind = kind; - frame.savepoint = savepoint; + (*s).handler_kinds[depth] = kind; + (*s).savepoints[depth].write(savepoint); (*s).try_depth += 1; - frame.jump_buffer.as_mut_ptr() + (*s).jump_buffers[depth].as_mut_ptr() }) } @@ -362,13 +354,14 @@ pub extern "C-unwind" fn js_throw(value: f64) -> ! { // Restore every subsystem before transporting the exception. The // registration generates capture and restore together, including the // feature-gated entries; the test replay uses this exact path too. - (*s).frames[depth].savepoint.restore(); + // depth names a published handler, whose push initialized this slot. + (*s).savepoints[depth].assume_init_read().restore(); // The savepoint restores above are transport-independent: the unwind // path skips Rust cleanups exactly like longjmp does (the runtime is // built panic=abort; see crate::eh), so restoring at throw time is // correct for both. - match (*s).frames[depth].kind { - HandlerKind::Setjmp => (*s).frames[depth].jump_buffer.as_mut_ptr(), + match (*s).handler_kinds[depth] { + HandlerKind::Setjmp => (*s).jump_buffers[depth].as_mut_ptr(), HandlerKind::Unwind => std::ptr::null_mut(), } }); @@ -712,7 +705,9 @@ pub(crate) fn test_try_depth() -> usize { pub(crate) fn test_unwind_innermost_shadow_restore() { with_exception_state(|s| unsafe { assert!((*s).try_depth > 0, "no open try to unwind"); - (*s).frames[(*s).try_depth - 1].savepoint.restore(); + (*s).savepoints[(*s).try_depth - 1] + .assume_init_read() + .restore(); }); } diff --git a/crates/perry-runtime/src/exception/savepoints.rs b/crates/perry-runtime/src/exception/savepoints.rs index 5193a62d55..ab62d2c472 100644 --- a/crates/perry-runtime/src/exception/savepoints.rs +++ b/crates/perry-runtime/src/exception/savepoints.rs @@ -8,7 +8,7 @@ use crate::gc::ShadowSavepoint; macro_rules! catch_savepoints { - ($($(#[$attr:meta])* $name:ident: $ty:ty = $empty:expr, + ($($(#[$attr:meta])* $name:ident: $ty:ty, capture: $capture:path, restore: $restore:path;)*) => { #[derive(Clone, Copy)] pub(super) struct CatchSavepoint { @@ -16,10 +16,6 @@ macro_rules! catch_savepoints { } impl CatchSavepoint { - pub(super) const EMPTY: Self = Self { - $($(#[$attr])* $name: $empty,)* - }; - #[inline(always)] pub(super) fn capture() -> Self { Self { $($(#[$attr])* $name: $capture(),)* } @@ -45,50 +41,50 @@ macro_rules! catch_savepoints { catch_savepoints! { // #1830, #6951: both shadow frames and expression temp roots. - shadow: ShadowSavepoint = ShadowSavepoint::EMPTY, + shadow: ShadowSavepoint, capture: crate::gc::shadow_stack_savepoint, restore: crate::gc::shadow_stack_restore; // Longjmp skips RuntimeHandleScope drops. - runtime_handles: usize = 0, + runtime_handles: usize, capture: crate::gc::runtime_handle_stack_savepoint, restore: crate::gc::runtime_handle_stack_restore; // #5591: skipped method guards must not wedge the recursion counter. - call_method: u32 = 0, + call_method: u32, capture: crate::object::call_method_depth_savepoint, restore: crate::object::call_method_depth_restore; // Includes removal of the process-wide outer-pump contribution. - pump: u32 = 0, + pump: u32, capture: crate::stdlib_pump::pump_depth_savepoint, restore: crate::stdlib_pump::pump_depth_restore; // #9082: abandoned walks must no longer inhibit compaction. - set_foreach: usize = 0, + set_foreach: usize, capture: crate::set::set_foreach_stack_savepoint, restore: crate::set::set_foreach_stack_restore; - map_foreach: usize = 0, + map_foreach: usize, capture: crate::map::map_foreach_stack_savepoint, restore: crate::map::map_foreach_stack_restore; - prototype_resolution: usize = 0, + prototype_resolution: usize, capture: crate::object::prototype_chain::resolution_stack_savepoint, restore: crate::object::prototype_chain::resolution_stack_restore; - static_private_owner: usize = 0, + static_private_owner: usize, capture: crate::object::static_private_owner_stack_savepoint, restore: crate::object::static_private_owner_stack_restore; - private_lexical_brand: usize = 0, + private_lexical_brand: usize, capture: crate::object::private_lexical_brand_stack_savepoint, restore: crate::object::private_lexical_brand_stack_restore; - derived_super_binding: usize = 0, + derived_super_binding: usize, capture: crate::object::derived_super_binding_stack_savepoint, restore: crate::object::derived_super_binding_stack_restore; - private_member_access_hints: usize = 0, + private_member_access_hints: usize, capture: crate::object::private_member_access_hints_savepoint, restore: crate::object::private_member_access_hints_restore; #[cfg(feature = "regex-engine")] - regex_factory: usize = 0, + regex_factory: usize, capture: crate::regex::site_test::active_factory_stack_savepoint, restore: crate::regex::site_test::active_factory_stack_restore; // #6559: rooted interpreter values AND the packed call depth. #[cfg(feature = "dyn-eval")] - dyn_eval: u64 = 0, + dyn_eval: u64, capture: crate::dyn_eval::interp_savepoint, restore: crate::dyn_eval::interp_restore; } diff --git a/crates/perry-runtime/src/gc/roots/shadow_stack.rs b/crates/perry-runtime/src/gc/roots/shadow_stack.rs index 27c562c554..946b6907a9 100644 --- a/crates/perry-runtime/src/gc/roots/shadow_stack.rs +++ b/crates/perry-runtime/src/gc/roots/shadow_stack.rs @@ -736,15 +736,6 @@ pub(crate) struct ShadowSavepoint { temp_roots: usize, } -impl ShadowSavepoint { - /// Identity savepoint for an empty shadow stack — used to - /// zero-initialize the per-try-depth savepoint table. - pub(crate) const EMPTY: ShadowSavepoint = ShadowSavepoint { - frame_top: usize::MAX, - len: 0, - temp_roots: 0, - }; -} /// Capture the current shadow-stack depth so it can be restored after a /// non-local exit. Call at `js_try_push` time, before the protected From 1416e3361e17805b7e98ee24ea39a5fc4ced18cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 09:18:25 +0200 Subject: [PATCH 4/8] fix(compile): imported default ctor arity matches the synthesized forwarding ctor (#10258) --- .../10258-imported-default-ctor-arity.md | 1 + .../perry-codegen/src/codegen/ctor_arity.rs | 28 +++++++++- crates/perry-codegen/src/codegen/mod.rs | 1 + crates/perry-codegen/src/lib.rs | 2 +- .../src/commands/compile/run_pipeline.rs | 19 +++++-- .../tests/source_graph_export_regressions.rs | 2 + .../issue_10258.rs | 55 +++++++++++++++++++ 7 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 changelog.d/10258-imported-default-ctor-arity.md create mode 100644 crates/perry/tests/source_graph_export_regressions/issue_10258.rs diff --git a/changelog.d/10258-imported-default-ctor-arity.md b/changelog.d/10258-imported-default-ctor-arity.md new file mode 100644 index 0000000000..1cc6dba602 --- /dev/null +++ b/changelog.d/10258-imported-default-ctor-arity.md @@ -0,0 +1 @@ +Fix `new ImportedClass(args)` for an exported class with no own constructor whose `extends` clause is a runtime value (for example effect v4's `class SystemError extends Data.Error {}`). The defining module synthesizes a forwarding constructor with a fixed parameter band because the parent's arity is unknown there, but the imported-class metadata counted only the class's own (absent) constructor and declared it with zero parameters, so the importing module called it with `this` alone and the parent constructor never saw the arguments. Importers now derive the arity from the same rule as the synthesized constructor. This unblocks OpenCode's config loading, where effect's file-not-found `PlatformError` lost its reason and turned a missing optional config file into a fatal error (#10107). diff --git a/crates/perry-codegen/src/codegen/ctor_arity.rs b/crates/perry-codegen/src/codegen/ctor_arity.rs index efc3d68469..73917e63e2 100644 --- a/crates/perry-codegen/src/codegen/ctor_arity.rs +++ b/crates/perry-codegen/src/codegen/ctor_arity.rs @@ -6,6 +6,33 @@ use std::collections::HashMap; +/// Positional forwarding band for a synthesized default ctor whose parent arity +/// cannot be resolved while compiling the defining module (see the tail of +/// [`synthesized_ctor_param_count`]). +pub const UNRESOLVED_PARENT_FWD_ARITY: usize = 8; + +/// The standalone-constructor arity of `class` when it can be decided from the +/// class definition alone, without the defining module's class table or +/// imports. Importers use this to describe a class they did not compile, so it +/// MUST agree with [`synthesized_ctor_param_count`] for every case it answers: +/// an own constructor, a native parent, no heritage, and a heritage that is only +/// a runtime value (`extends_expr` with no resolvable `extends_name`), which +/// always synthesizes the fixed forwarding band. `None` means the arity depends +/// on the ancestor walk and callers keep their existing behaviour (#10258). +pub fn context_free_ctor_param_count(class: &perry_hir::Class) -> Option { + if let Some(c) = class.constructor.as_ref() { + return Some(c.params.len()); + } + if class.native_extends.is_some() { + return Some(0); + } + match (&class.extends_name, &class.extends_expr) { + (None, None) => Some(0), + (None, Some(_)) => Some(UNRESOLVED_PARENT_FWD_ARITY), + _ => None, + } +} + /// The standalone-constructor arity Perry emits for `class`, accounting for the /// JS spec default ctor `constructor(...args) { super(...args) }` that a class /// with NO own constructor but WITH heritage inherits. Walks the ancestor chain @@ -78,6 +105,5 @@ pub(super) fn synthesized_ctor_param_count( // positional params: the `new` site pads missing slots with `undefined`, // and a parent ctor reading fewer params ignores the trailing `undefined`s, // so over-declaring is correct for any (non-native) parent up to this band. - const UNRESOLVED_PARENT_FWD_ARITY: usize = 8; UNRESOLVED_PARENT_FWD_ARITY } diff --git a/crates/perry-codegen/src/codegen/mod.rs b/crates/perry-codegen/src/codegen/mod.rs index df28e079e1..8b09ca39a5 100644 --- a/crates/perry-codegen/src/codegen/mod.rs +++ b/crates/perry-codegen/src/codegen/mod.rs @@ -188,6 +188,7 @@ mod clone_suffix_tests; mod closure; mod closure_collect; mod ctor_arity; +pub use ctor_arity::{context_free_ctor_param_count, UNRESOLVED_PARENT_FWD_ARITY}; #[cfg(test)] mod declared_string_add_tests; #[cfg(test)] diff --git a/crates/perry-codegen/src/lib.rs b/crates/perry-codegen/src/lib.rs index 9eb72e7496..dd085e8618 100644 --- a/crates/perry-codegen/src/lib.rs +++ b/crates/perry-codegen/src/lib.rs @@ -75,7 +75,7 @@ pub mod types; pub mod unit_cache; pub use codegen::{ - compile_module, namespace_member_class_key, namespace_member_func_key, + compile_module, context_free_ctor_param_count, namespace_member_class_key, namespace_member_func_key, namespace_member_var_key, resolve_target_triple, short_spread_method_capabilities, user_function_symbol, AppMetadata, CompileOptions, ExportedObjectLiteralCapability, FpContractMode, ImportedClass, ImportedObjectLiteral, ImportedObjectLiteralMethod, diff --git a/crates/perry/src/commands/compile/run_pipeline.rs b/crates/perry/src/commands/compile/run_pipeline.rs index a71acbbcd2..1016b348c3 100644 --- a/crates/perry/src/commands/compile/run_pipeline.rs +++ b/crates/perry/src/commands/compile/run_pipeline.rs @@ -293,11 +293,20 @@ fn imported_class_from_hir( local_alias, namespace: None, source_prefix, - constructor_param_count: class - .constructor - .as_ref() - .map(|ctor| ctor.params.len()) - .unwrap_or(0), + // #10258: must match the arity of the standalone constructor the + // defining module emits. A class with no own constructor whose parent + // is only a runtime value synthesizes a fixed forwarding band; counting + // just the (absent) own constructor declared it as 0 params here, so + // `new ImportedClass(args)` passed only `this` and the parent ran + // without its arguments. + constructor_param_count: perry_codegen::context_free_ctor_param_count(class) + .unwrap_or_else(|| { + class + .constructor + .as_ref() + .map(|ctor| ctor.params.len()) + .unwrap_or(0) + }), has_own_constructor: class.constructor.is_some(), constructor_has_rest: class .constructor diff --git a/crates/perry/tests/source_graph_export_regressions.rs b/crates/perry/tests/source_graph_export_regressions.rs index ea4df499cb..4797a6c6a9 100644 --- a/crates/perry/tests/source_graph_export_regressions.rs +++ b/crates/perry/tests/source_graph_export_regressions.rs @@ -963,3 +963,5 @@ mod issue_10160; mod issue_10180; #[path = "source_graph_export_regressions/issue_10197.rs"] mod issue_10197; +#[path = "source_graph_export_regressions/issue_10258.rs"] +mod issue_10258; diff --git a/crates/perry/tests/source_graph_export_regressions/issue_10258.rs b/crates/perry/tests/source_graph_export_regressions/issue_10258.rs new file mode 100644 index 0000000000..e2c790d879 --- /dev/null +++ b/crates/perry/tests/source_graph_export_regressions/issue_10258.rs @@ -0,0 +1,55 @@ +//! `new ImportedClass(args)` for an exported class with no own constructor whose +//! parent is a runtime value must forward the arguments (#10258). The defining +//! module synthesizes a fixed-arity forwarding constructor; the importer used to +//! declare it with zero parameters and dropped every argument. effect v4's +//! `PlatformError.SystemError extends Data.Error {}` has this shape. + +use super::{compile_and_run, write}; + +#[test] +fn imported_default_ctor_with_runtime_parent_forwards_args() { + let dir = tempfile::tempdir().unwrap(); + write( + dir.path(), + "core.ts", + "export const YieldableError = (function () { class YieldableError extends globalThis.Error {}; return YieldableError })()\n\ + export const Error = (function () {\n\ + \x20 return class Base extends YieldableError {\n\ + \x20 constructor(args?: any) { super(args?.message); if (args) Object.assign(this, args) }\n\ + \x20 }\n\ + })()\n\ + export const Plain = (function () { return class P { constructor(a?: any, b?: any, c?: any) { (this as any).sum = [a, b, c] } } })()\n", + ); + write(dir.path(), "data.ts", "import * as core from \"./core\"\nexport const Error = core.Error\nexport const Plain = core.Plain\n"); + write( + dir.path(), + "platform.ts", + "import * as Data from \"./data\"\n\ + export class Empty extends (Data.Error as any) {}\n\ + export class WithGetter extends (Data.Error as any) { get message() { return \"G:\" + (this as any)._tag } }\n\ + export class WithMethod extends (Data.Error as any) { describe() { return (this as any).module } }\n\ + export class Explicit extends (Data.Error as any) { constructor(a: any) { super(a) } }\n\ + export class ThreeArgs extends (Data.Plain as any) {}\n\ + export const makeLocal = (o: any) => new WithGetter(o)\n", + ); + write( + dir.path(), + "main.ts", + "import { Empty, WithGetter, WithMethod, Explicit, ThreeArgs, makeLocal } from \"./platform\"\n\ + import * as P from \"./platform\"\n\ + const o = () => ({ _tag: \"NotFound\", module: \"FS\" })\n\ + const show = (e: any) => [e._tag, e.module, e instanceof Error].join(\",\")\n\ + console.log(show(new Empty(o())), show(new WithGetter(o())), new WithGetter(o()).message)\n\ + console.log(show(new WithMethod(o())), new WithMethod(o()).describe(), show(new Explicit(o())))\n\ + console.log(show(new P.Empty(o())), show(makeLocal(o())), JSON.stringify((new ThreeArgs(1, 2, 3) as any).sum))\n\ + class Sub extends Empty {}\n\ + console.log(show(new Sub(o())))\n", + ); + assert_eq!( + compile_and_run(dir.path(), "main.ts"), + "NotFound,FS,true NotFound,FS,true G:NotFound\n\ + NotFound,FS,true FS NotFound,FS,true\n\ + NotFound,FS,true NotFound,FS,true [1,2,3]\n\ + NotFound,FS,true\n" + ); +} From 51b95d534e36d712753f94b105de89bc00ff011a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 09:53:55 +0200 Subject: [PATCH 5/8] feat(ui): add responsive centered widget max-width --- changelog.d/10167-widget-max-width.md | 10 + crates/perry-codegen-arkts/src/mutations.rs | 2 + crates/perry-codegen-js/src/emit/calls.rs | 1 + crates/perry-codegen-js/src/lib.rs | 20 ++ crates/perry-codegen-js/src/web_runtime.js | 14 ++ .../src/emit/ui_method_map.rs | 1 + crates/perry-codegen-wasm/src/lib.rs | 24 ++ crates/perry-codegen-wasm/src/wasm_runtime.js | 17 +- .../perry-codegen/tests/widget_max_width.rs | 26 +++ crates/perry-dispatch/src/ui_table/part_a.rs | 6 + .../perry-ui-android/src/ffi/tabbar_layout.rs | 5 + crates/perry-ui-gtk4/src/ffi/layout.rs | 5 + crates/perry-ui-ios/src/ffi/widgets_basic.rs | 5 + crates/perry-ui-macos/Cargo.toml | 5 + crates/perry-ui-macos/src/app.rs | 2 +- .../src/lib_ffi/core_widgets.rs | 6 + .../perry-ui-macos/src/widgets/max_width.rs | 216 ++++++++++++++++++ crates/perry-ui-macos/src/widgets/mod.rs | 50 +++- crates/perry-ui-macos/src/widgets/padding.rs | 1 + .../perry-ui-macos/src/widgets/scrollview.rs | 11 +- crates/perry-ui-macos/src/widgets/zstack.rs | 2 +- .../tests/native_widget_max_width.rs | 154 +++++++++++++ .../native_widget_max_width/containers.rs | 80 +++++++ crates/perry-ui-tvos/src/ffi/styling.rs | 5 + crates/perry-ui-visionos/src/ffi_layout.rs | 5 + crates/perry-ui-watchos/src/lib.rs | 5 + crates/perry-ui-windows/src/ffi/mod.rs | 5 + crates/perry-ui/src/styling_matrix.rs | 6 + docs/src/ui/layout.md | 21 ++ docs/src/ui/styling-matrix.md | 19 +- docs/src/ui/widgets.md | 1 + types/perry/ui/index.d.ts | 8 + 32 files changed, 711 insertions(+), 27 deletions(-) create mode 100644 changelog.d/10167-widget-max-width.md create mode 100644 crates/perry-codegen/tests/widget_max_width.rs create mode 100644 crates/perry-ui-macos/src/widgets/max_width.rs create mode 100644 crates/perry-ui-macos/tests/native_widget_max_width.rs create mode 100644 crates/perry-ui-macos/tests/native_widget_max_width/containers.rs diff --git a/changelog.d/10167-widget-max-width.md b/changelog.d/10167-widget-max-width.md new file mode 100644 index 0000000000..d606a705ae --- /dev/null +++ b/changelog.d/10167-widget-max-width.md @@ -0,0 +1,10 @@ +Add `widgetSetMaxWidth(widget, maxWidth)` for responsive centered content columns. +On macOS, Auto Layout fills available width up to the cap while preserving padding, +stack alignment, and widget identity. Caps can be set before or after insertion and +updated in place. JavaScript and WebAssembly web targets use CSS max-width and auto +margins. Other backends export a documented no-op for portable compilation. + +Fixes #10167. Native layout regressions cover resizing, padded parents and content, +repeated updates, insertion order, fill alignment, hide/show, reparenting, +scroll views, and app-root placement. Native, JavaScript, and WebAssembly codegen +tests cover the new runtime call. diff --git a/crates/perry-codegen-arkts/src/mutations.rs b/crates/perry-codegen-arkts/src/mutations.rs index 6cfdfa1966..60d302ac41 100644 --- a/crates/perry-codegen-arkts/src/mutations.rs +++ b/crates/perry-codegen-arkts/src/mutations.rs @@ -624,6 +624,8 @@ pub(crate) fn collect_mutations_in_expr( cond, ); } + // Responsive max-width currently degrades to a no-op on HarmonyOS. + "widgetSetMaxWidth" => {} "widgetMatchParentWidth" => { push_mut(Mutation::Modifier(".width('100%')".to_string()), out, cond); } diff --git a/crates/perry-codegen-js/src/emit/calls.rs b/crates/perry-codegen-js/src/emit/calls.rs index 002a3d76a1..79bd1a9b10 100644 --- a/crates/perry-codegen-js/src/emit/calls.rs +++ b/crates/perry-codegen-js/src/emit/calls.rs @@ -304,6 +304,7 @@ impl JsEmitter { "widgetReorderChild" => "perry_ui_widget_reorder_child", "widgetClearChildren" => "perry_ui_widget_remove_all_children", "widgetSetWidth" => "perry_ui_widget_set_width", + "widgetSetMaxWidth" => "perry_ui_widget_set_max_width", "widgetSetHeight" => "perry_ui_widget_set_height", "widgetSetHugging" => "perry_ui_widget_set_hugging", "widgetSetHidden" => "perry_ui_set_widget_hidden", diff --git a/crates/perry-codegen-js/src/lib.rs b/crates/perry-codegen-js/src/lib.rs index 4685d2e412..3c7243bcfe 100644 --- a/crates/perry-codegen-js/src/lib.rs +++ b/crates/perry-codegen-js/src/lib.rs @@ -213,3 +213,23 @@ fn html_escape(s: &str) -> String { .replace('>', ">") .replace('"', """) } + +#[cfg(test)] +mod max_width_tests { + use super::*; + use perry_hir::Expr; + + #[test] + fn max_width_calls_the_web_runtime() { + let mut module = Module::new("max_width"); + module.init.push(Stmt::Expr(Expr::NativeMethodCall { + module: "perry/ui".into(), + class_name: None, + object: None, + method: "widgetSetMaxWidth".into(), + args: vec![Expr::Number(1.0), Expr::Number(640.0)], + })); + let (js, _) = compile_module_to_js(&module, false); + assert!(js.contains("perry_ui_widget_set_max_width(1, 640)"), "{js}"); + } +} diff --git a/crates/perry-codegen-js/src/web_runtime.js b/crates/perry-codegen-js/src/web_runtime.js index 23df4ca85d..7e79e3e0cd 100644 --- a/crates/perry-codegen-js/src/web_runtime.js +++ b/crates/perry-codegen-js/src/web_runtime.js @@ -1236,6 +1236,19 @@ function perry_ui_button_set_content_tint_color(h, r, g, b, a) { if (el) el.style.color = `rgba(${Math.round(r*255)},${Math.round(g*255)},${Math.round(b*255)},${a})`; } +function perry_ui_widget_set_max_width(h, maxWidth) { + if (!Number.isFinite(maxWidth) || maxWidth < 0) return; + const el = getHandle(h); + if (!el) return; + el.style.boxSizing = "border-box"; + el.style.width = "100%"; + el.style.minWidth = "0"; + el.style.maxWidth = maxWidth + "px"; + el.style.flexShrink = "1"; + el.style.marginLeft = "auto"; + el.style.marginRight = "auto"; +} + function perry_ui_widget_set_width(h, w) { const el = getHandle(h); if (el) { el.style.width = w + "px"; el.style.minWidth = w + "px"; el.style.maxWidth = w + "px"; el.style.flexShrink = "0"; } @@ -3834,6 +3847,7 @@ window.__perry = { perry_ui_app_on_terminate, perry_ui_app_set_timer, // Widget layout + perry_ui_widget_set_max_width, perry_ui_widget_set_width, perry_ui_widget_set_height, perry_ui_widget_set_hugging, diff --git a/crates/perry-codegen-wasm/src/emit/ui_method_map.rs b/crates/perry-codegen-wasm/src/emit/ui_method_map.rs index 2f72800225..a437b44216 100644 --- a/crates/perry-codegen-wasm/src/emit/ui_method_map.rs +++ b/crates/perry-codegen-wasm/src/emit/ui_method_map.rs @@ -93,6 +93,7 @@ pub(super) fn map_ui_method(method: &str, class_name: Option<&str>) -> &'static "setTooltip" | "set_tooltip" => "perry_ui_set_tooltip", "setControlSize" | "set_control_size" => "perry_ui_set_control_size", "widgetSetWidth" => "perry_ui_widget_set_width", + "widgetSetMaxWidth" => "perry_ui_widget_set_max_width", "widgetSetHeight" => "perry_ui_widget_set_height", "widgetSetHugging" => "perry_ui_widget_set_hugging", "widgetSetHidden" => "perry_ui_set_widget_hidden", diff --git a/crates/perry-codegen-wasm/src/lib.rs b/crates/perry-codegen-wasm/src/lib.rs index 7f02b0fa10..d3d8d8ecab 100644 --- a/crates/perry-codegen-wasm/src/lib.rs +++ b/crates/perry-codegen-wasm/src/lib.rs @@ -123,3 +123,27 @@ mod tests { ); } } + +#[cfg(test)] +mod max_width_tests { + use super::*; + use perry_hir::{Expr, Stmt}; + + #[test] + fn max_width_uses_the_runtime_bridge() { + let mut module = Module::new("max_width"); + module.init.push(Stmt::Expr(Expr::NativeMethodCall { + module: "perry/ui".into(), + class_name: None, + object: None, + method: "widgetSetMaxWidth".into(), + args: vec![Expr::Number(1.0), Expr::Number(640.0)], + })); + let modules = vec![("max_width".into(), module)]; + let wasm = compile_modules_to_wasm(&modules).unwrap(); + // UI calls use the generic bridge with the mapped runtime name in the + // data section (the separate FFI import list is for declare functions). + let symbol = b"perry_ui_widget_set_max_width"; + assert!(wasm.windows(symbol.len()).any(|bytes| bytes == symbol)); + } +} diff --git a/crates/perry-codegen-wasm/src/wasm_runtime.js b/crates/perry-codegen-wasm/src/wasm_runtime.js index 5b58665346..9749db43e9 100644 --- a/crates/perry-codegen-wasm/src/wasm_runtime.js +++ b/crates/perry-codegen-wasm/src/wasm_runtime.js @@ -3099,7 +3099,20 @@ function perry_ui_widget_set_background_gradient(h, r1, g1, b1, a1, r2, g2, b2, const dir = direction === 1 ? "to right" : "to bottom"; el.style.background = `linear-gradient(${dir}, ${c1}, ${c2})`; } -function perry_ui_widget_set_width(h, w) { const el = uiGet(h); if (el) el.style.width = w + "px"; } +function perry_ui_widget_set_max_width(h, maxWidth) { + if (!Number.isFinite(maxWidth) || maxWidth < 0) return; + const el = uiGet(h); + if (!el) return; + el.style.boxSizing = "border-box"; + el.style.width = "100%"; + el.style.minWidth = "0"; + el.style.maxWidth = maxWidth + "px"; + el.style.flexShrink = "1"; + el.style.marginLeft = "auto"; + el.style.marginRight = "auto"; +} + +function perry_ui_widget_set_width(h, w) { const el = uiGet(h); if (el) { el.style.width = w + "px"; el.style.maxWidth = ""; } } function perry_ui_widget_set_height(h, height) { const el = uiGet(h); if (el) el.style.height = height + "px"; } function perry_ui_widget_set_hugging(h) { const el = uiGet(h); if (el) el.style.flex = "0 0 auto"; } function perry_ui_widget_match_parent_width(h) { const el = uiGet(h); if (el) el.style.width = "100%"; } @@ -4723,7 +4736,7 @@ const __perryUiDispatch = { perry_ui_widget_set_border_color, perry_ui_widget_set_border_width, perry_ui_text_set_decoration, perry_ui_textfield_set_borderless, perry_ui_stack_set_alignment, - perry_ui_widget_set_width, perry_ui_widget_set_height, perry_ui_widget_set_hugging, + perry_ui_widget_set_max_width, perry_ui_widget_set_width, perry_ui_widget_set_height, perry_ui_widget_set_hugging, perry_ui_widget_match_parent_width, perry_ui_widget_match_parent_height, perry_ui_widget_set_edge_insets, perry_ui_stack_set_detaches_hidden, perry_ui_stack_set_distribution, perry_ui_widget_set_context_menu, diff --git a/crates/perry-codegen/tests/widget_max_width.rs b/crates/perry-codegen/tests/widget_max_width.rs new file mode 100644 index 0000000000..5b0a05f4fe --- /dev/null +++ b/crates/perry-codegen/tests/widget_max_width.rs @@ -0,0 +1,26 @@ +use perry_codegen::{compile_module, CompileOptions}; +use perry_hir::{Expr, Module, Stmt}; + +#[test] +fn max_width_lowers_to_the_native_widget_abi() { + let mut module = Module::new("widget_max_width"); + module.init.push(Stmt::Expr(Expr::NativeMethodCall { + module: "perry/ui".into(), + class_name: None, + object: None, + method: "widgetSetMaxWidth".into(), + args: vec![Expr::Number(1.0), Expr::Number(640.0)], + })); + let options = CompileOptions { + emit_ir_only: true, + ..Default::default() + }; + let ir = String::from_utf8(compile_module(&module, options).unwrap()).unwrap(); + assert!( + ir.lines().any( + |line| line.contains("call void @perry_ui_widget_set_max_width(i64 ") + && line.contains(", double ") + ), + "max-width must pass a native widget handle and numeric cap: {ir}" + ); +} diff --git a/crates/perry-dispatch/src/ui_table/part_a.rs b/crates/perry-dispatch/src/ui_table/part_a.rs index 19c6a4b086..fd8f037743 100644 --- a/crates/perry-dispatch/src/ui_table/part_a.rs +++ b/crates/perry-dispatch/src/ui_table/part_a.rs @@ -563,6 +563,12 @@ pub(crate) const PERRY_UI_TABLE_PART_A: &[MethodRow] = &[ args: &[ArgKind::Widget, ArgKind::F64], ret: ReturnKind::Void, }, + MethodRow { + method: "widgetSetMaxWidth", + runtime: "perry_ui_widget_set_max_width", + args: &[ArgKind::Widget, ArgKind::F64], + ret: ReturnKind::Void, + }, // ---- Image ---- MethodRow { method: "ImageFile", diff --git a/crates/perry-ui-android/src/ffi/tabbar_layout.rs b/crates/perry-ui-android/src/ffi/tabbar_layout.rs index ceb49c7ae8..74c50c8949 100644 --- a/crates/perry-ui-android/src/ffi/tabbar_layout.rs +++ b/crates/perry-ui-android/src/ffi/tabbar_layout.rs @@ -379,3 +379,8 @@ pub extern "C" fn perry_ui_app_set_window_state(_app_handle: i64, _value_ptr: i6 /// Frame persistence only applies to repositionable desktop windows. #[no_mangle] pub extern "C" fn perry_ui_app_set_frame_autosave_name(_app_handle: i64, _value_ptr: i64) {} + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui-gtk4/src/ffi/layout.rs b/crates/perry-ui-gtk4/src/ffi/layout.rs index 6ff574de20..e62de417b8 100644 --- a/crates/perry-ui-gtk4/src/ffi/layout.rs +++ b/crates/perry-ui-gtk4/src/ffi/layout.rs @@ -181,3 +181,8 @@ pub extern "C" fn perry_ui_hstack_create_with_insets( ) -> i64 { widgets::hstack::create_with_insets(spacing, top, left, bottom, right) } + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui-ios/src/ffi/widgets_basic.rs b/crates/perry-ui-ios/src/ffi/widgets_basic.rs index b4d39f200f..58a977c39a 100644 --- a/crates/perry-ui-ios/src/ffi/widgets_basic.rs +++ b/crates/perry-ui-ios/src/ffi/widgets_basic.rs @@ -841,3 +841,8 @@ pub extern "C" fn perry_ui_textfield_set_text_color(handle: i64, r: f64, g: f64, pub extern "C" fn perry_ui_widget_add_child_at(parent_handle: i64, child_handle: i64, index: f64) { widgets::add_child_at(parent_handle, child_handle, index as i64); } + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui-macos/Cargo.toml b/crates/perry-ui-macos/Cargo.toml index 332d166c05..31fce17283 100644 --- a/crates/perry-ui-macos/Cargo.toml +++ b/crates/perry-ui-macos/Cargo.toml @@ -85,3 +85,8 @@ harness = false name = "native_widget_padding" path = "tests/native_widget_padding.rs" harness = false + +[[test]] +name = "native_widget_max_width" +path = "tests/native_widget_max_width.rs" +harness = false diff --git a/crates/perry-ui-macos/src/app.rs b/crates/perry-ui-macos/src/app.rs index 0b9163a948..2535656a38 100644 --- a/crates/perry-ui-macos/src/app.rs +++ b/crates/perry-ui-macos/src/app.rs @@ -136,7 +136,7 @@ pub fn app_set_body(app_handle: i64, root_handle: i64) { if idx < apps.len() { apps[idx]._root_widget = Some(root_handle); - if let Some(view) = widgets::get_widget(root_handle) { + if let Some(view) = widgets::get_layout_widget(root_handle) { let window = &apps[idx].window; // Check if the current content view is an NSVisualEffectView (set by vibrancy). diff --git a/crates/perry-ui-macos/src/lib_ffi/core_widgets.rs b/crates/perry-ui-macos/src/lib_ffi/core_widgets.rs index 6107210f34..504264b2d6 100644 --- a/crates/perry-ui-macos/src/lib_ffi/core_widgets.rs +++ b/crates/perry-ui-macos/src/lib_ffi/core_widgets.rs @@ -473,6 +473,12 @@ pub extern "C" fn perry_ui_widget_set_width(handle: i64, width: f64) { widgets::set_width(handle, width); } +/// Fill the available width up to a cap, centering the widget within it. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(handle: i64, max_width: f64) { + widgets::set_max_width(handle, max_width); +} + /// Set a fixed height constraint on a widget. #[no_mangle] pub extern "C" fn perry_ui_widget_set_height(handle: i64, height: f64) { diff --git a/crates/perry-ui-macos/src/widgets/max_width.rs b/crates/perry-ui-macos/src/widgets/max_width.rs new file mode 100644 index 0000000000..65812f6e30 --- /dev/null +++ b/crates/perry-ui-macos/src/widgets/max_width.rs @@ -0,0 +1,216 @@ +//! A full-width layout slot lets a capped child center without fighting its +//! NSStackView's leading/fill alignment. Widget operations still target the +//! original content view; only insertion/removal uses the slot. + +use objc2::rc::Retained; +use objc2::{define_class, msg_send, DefinedClass, MainThreadOnly}; +use objc2_app_kit::{NSLayoutConstraint, NSStackView, NSStackViewGravity, NSView}; +use objc2_foundation::MainThreadMarker; +use std::cell::RefCell; + +pub struct MaxWidthIvars { + content: Retained, + cap: Retained, + parent_constraints: RefCell>>, +} + +define_class!( + #[unsafe(super(NSView))] + #[name = "PerryMaxWidthView"] + #[ivars = MaxWidthIvars] + pub struct MaxWidthView; + + impl MaxWidthView { + #[unsafe(method(viewDidMoveToSuperview))] + fn did_move_to_superview(&self) { + unsafe { let _: () = msg_send![super(self), viewDidMoveToSuperview]; } + self.refresh_parent(); + } + } +); + +impl MaxWidthView { + fn refresh_parent(&self) { + let mut constraints = self.ivars().parent_constraints.borrow_mut(); + for constraint in constraints.drain(..) { + constraint.setActive(false); + } + let Some(parent) = (unsafe { self.superview() }) else { + return; + }; + // A stack's edge insets are inside its bounds. Do not fill through them. + let inset = parent + .downcast_ref::() + .map(|stack| { + let insets = stack.edgeInsets(); + insets.left + insets.right + }) + .unwrap_or(0.0); + let fits = self + .widthAnchor() + .constraintLessThanOrEqualToAnchor_constant(&parent.widthAnchor(), -inset); + let fills = self + .widthAnchor() + .constraintEqualToAnchor_constant(&parent.widthAnchor(), -inset); + fills.setPriority(999.0); + fits.setActive(true); + fills.setActive(true); + constraints.extend([fits, fills]); + } +} + +pub(super) fn content(view: Retained) -> Retained { + view.downcast_ref::() + .map(|slot| slot.ivars().content.clone()) + .unwrap_or(view) +} + +pub(super) fn clear_cap(handle: i64) { + if let Some(view) = super::get_layout_widget(handle) { + if let Some(slot) = view.downcast_ref::() { + slot.ivars().cap.setActive(false); + } + } +} + +pub(super) fn refresh_children(view: &NSView) { + for child in view.subviews() { + if let Some(slot) = child.downcast_ref::() { + slot.refresh_parent(); + } + } +} + +/// Fill the available width up to `max_width`, keeping the content centered. +/// Invalid values are ignored; zero is a valid cap. A new cap replaces an old +/// fixed width, and repeated calls update the existing constraint in place. +pub fn set_max_width(handle: i64, max_width: f64) { + if !max_width.is_finite() || max_width < 0.0 { + return; + } + let Some(view) = super::get_layout_widget(handle) else { + return; + }; + super::WIDTH_CONSTRAINTS.with(|constraints| { + if let Some(old) = constraints.borrow_mut().remove(&handle) { + unsafe { + let _: () = msg_send![&*old, setActive: false]; + } + } + }); + if let Some(slot) = view.downcast_ref::() { + slot.ivars().cap.setConstant(max_width); + slot.ivars().cap.setActive(true); + return; + } + + let mtm = MainThreadMarker::new().expect("perry/ui must run on the main thread"); + let parent = unsafe { view.superview() }; + let window = view + .window() + .filter(|window| window.contentView().as_deref() == Some(&view)); + let stack_position = parent.as_ref().and_then(|parent| { + parent.downcast_ref::().and_then(|stack| { + stack + .viewsInGravity(NSStackViewGravity::Top) + .iter() + .position(|child| Retained::as_ptr(&child) == Retained::as_ptr(&view)) + }) + }); + + // Existing parent pins (matchParentWidth, ZStack, ScrollView, app body) + // describe the layout slot. Transfer them so the cap can win inside it. + let mut external = Vec::new(); + let mut ancestor = parent.clone(); + while let Some(owner) = ancestor { + for constraint in owner.constraints() { + unsafe { + let first = constraint.firstItem(); + let second = constraint.secondItem(); + let is_content = |item: &Option>| { + item.as_ref().is_some_and(|item| { + Retained::as_ptr(item).cast::() == Retained::as_ptr(&view) + }) + }; + if is_content(&first) || is_content(&second) { + constraint.setActive(false); + external.push((constraint, first, second)); + } + } + } + ancestor = unsafe { owner.superview() }; + } + if let Some(stack) = parent + .as_ref() + .and_then(|parent| parent.downcast_ref::()) + { + stack.removeView(&view); + } + view.removeFromSuperview(); + view.setTranslatesAutoresizingMaskIntoConstraints(false); + let cap = view + .widthAnchor() + .constraintLessThanOrEqualToConstant(max_width); + let slot = MaxWidthView::alloc(mtm).set_ivars(MaxWidthIvars { + content: view.clone(), + cap: cap.clone(), + parent_constraints: RefCell::new(Vec::new()), + }); + let slot: Retained = unsafe { msg_send![super(slot), init] }; + slot.setTranslatesAutoresizingMaskIntoConstraints(false); + slot.setHidden(view.isHidden()); + slot.addSubview(&view); + let fills = view + .widthAnchor() + .constraintEqualToAnchor(&slot.widthAnchor()); + fills.setPriority(998.0); + let fits = view + .widthAnchor() + .constraintLessThanOrEqualToAnchor(&slot.widthAnchor()); + // An explicit setWidth applied later can still overflow a narrow parent. + fits.setPriority(999.0); + for constraint in [ + cap, + fills, + fits, + view.centerXAnchor() + .constraintEqualToAnchor(&slot.centerXAnchor()), + view.topAnchor().constraintEqualToAnchor(&slot.topAnchor()), + view.bottomAnchor() + .constraintEqualToAnchor(&slot.bottomAnchor()), + ] { + constraint.setActive(true); + } + let slot: Retained = slot.into_super(); + super::WIDGETS.with(|widgets| widgets.borrow_mut()[handle as usize - 1] = slot.clone()); + if let Some(window) = window { + window.setContentView(Some(&slot)); + } else if let Some(parent) = parent { + if let (Some(stack), Some(index)) = (parent.downcast_ref::(), stack_position) { + stack.insertView_atIndex_inGravity(&slot, index, NSStackViewGravity::Top); + } else { + parent.addSubview(&slot); + } + } + for (old, first, second) in external { + unsafe { + let replace = |item: Option>| { + item.map(|item| { + if Retained::as_ptr(&item).cast::() == Retained::as_ptr(&view) { + Retained::cast_unchecked(slot.clone()) + } else { + item + } + }) + }; + let first = replace(first); + let second = replace(second); + let constraint = NSLayoutConstraint::constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant( + first.as_deref().unwrap(), old.firstAttribute(), old.relation(), + second.as_deref(), old.secondAttribute(), old.multiplier(), old.constant(), + ); + constraint.setPriority(old.priority()); + constraint.setActive(true); + } + } +} diff --git a/crates/perry-ui-macos/src/widgets/mod.rs b/crates/perry-ui-macos/src/widgets/mod.rs index a9c3971c0f..927144d90b 100644 --- a/crates/perry-ui-macos/src/widgets/mod.rs +++ b/crates/perry-ui-macos/src/widgets/mod.rs @@ -19,6 +19,8 @@ pub mod image_gallery; pub mod keyboard; pub mod lazyvstack; pub mod map_view; +mod max_width; +pub use max_width::set_max_width; pub mod navstack; pub(crate) mod padding; pub mod pdf_view; @@ -162,7 +164,8 @@ pub extern "C" fn perry_ui_query_widget_tree(out_len: *mut usize) -> *mut u8 { let json = WIDGETS.with(|w| { let widgets = w.borrow(); let mut s = String::from("["); - for (i, view) in widgets.iter().enumerate() { + for (i, layout_view) in widgets.iter().enumerate() { + let view = max_width::content(layout_view.clone()); let handle = (i + 1) as i64; if i > 0 { s.push(','); } unsafe { @@ -251,6 +254,11 @@ pub fn register_external_nsview(nsview_ptr: i64) -> i64 { /// Retrieve the NSView for a given handle. pub fn get_widget(handle: i64) -> Option> { + get_layout_widget(handle).map(max_width::content) +} + +/// The view inserted into containers (including a max-width layout slot). +pub(crate) fn get_layout_widget(handle: i64) -> Option> { WIDGETS.with(|w| { let widgets = w.borrow(); let idx = (handle - 1) as usize; @@ -262,7 +270,11 @@ pub fn get_widget(handle: i64) -> Option> { /// When unhiding a view that NSStackView detached (no superview), re-inserts it /// into its parent NSStackView at the original position. pub fn set_hidden(handle: i64, hidden: bool) { - if let Some(view) = get_widget(handle) { + if let Some(view) = get_layout_widget(handle) { + let content = max_width::content(view.clone()); + if Retained::as_ptr(&content) != Retained::as_ptr(&view) { + content.setHidden(hidden); + } unsafe { let _: () = objc2::msg_send![&*view, setHidden: hidden]; } @@ -396,6 +408,14 @@ fn collect_subtree_handles(view: &NSView) -> Vec { } } } + if view.downcast_ref::().is_some() { + for child in view.subviews() { + if let Some(h) = find_handle_for_view(&child) { + handles.push(h); + } + handles.extend(collect_subtree_handles(&child)); + } + } handles } @@ -463,6 +483,9 @@ pub fn clear_children(handle: i64) { // Phase 3: Batch deactivate constraints on all views for sv in &views { + if sv.downcast_ref::().is_some() { + continue; + } unsafe { let constraints: Retained = objc2::msg_send![&**sv, constraints]; let c_count: usize = objc2::msg_send![&*constraints, count]; @@ -509,7 +532,9 @@ fn refresh_stack_parent_map(parent_handle: i64, stack: &NSStackView) { /// Insert or move a child at an index, retaining its own layout metadata. /// Perry stacks use the top/leading gravity area for both orientations. pub fn add_child_at(parent_handle: i64, child_handle: i64, index: i64) { - if let (Some(parent), Some(child)) = (get_widget(parent_handle), get_widget(child_handle)) { + if let (Some(parent), Some(child)) = + (get_widget(parent_handle), get_layout_widget(child_handle)) + { let is_stack = AnyClass::get(c"NSStackView") .map(|class| parent.isKindOfClass(class)) .unwrap_or(false); @@ -542,7 +567,9 @@ pub fn add_child_at(parent_handle: i64, child_handle: i64, index: i64) { /// Add a child view to a parent view. /// If the parent is an NSStackView, uses addArrangedSubview for proper layout. pub fn add_child(parent_handle: i64, child_handle: i64) { - if let (Some(parent), Some(child)) = (get_widget(parent_handle), get_widget(child_handle)) { + if let (Some(parent), Some(child)) = + (get_widget(parent_handle), get_layout_widget(child_handle)) + { // Check if parent is an NSStackView let is_stack = if let Some(cls) = AnyClass::get(c"NSStackView") { parent.isKindOfClass(cls) @@ -568,7 +595,9 @@ pub fn add_child(parent_handle: i64, child_handle: i64) { /// If the parent is an NSStackView, removes from arranged subviews first. /// Also cleans up metadata maps for the removed child and its descendants. pub fn remove_child(parent_handle: i64, child_handle: i64) { - if let (Some(parent), Some(child)) = (get_widget(parent_handle), get_widget(child_handle)) { + if let (Some(parent), Some(child)) = + (get_widget(parent_handle), get_layout_widget(child_handle)) + { let is_stack = if let Some(cls) = AnyClass::get(c"NSStackView") { parent.isKindOfClass(cls) } else { @@ -599,7 +628,9 @@ pub fn remove_child(parent_handle: i64, child_handle: i64) { /// The overlay floats on top of the parent's stack layout. /// Caller must set frame via widgetSetOverlayFrame(child, x, y, w, h). pub fn add_overlay(parent_handle: i64, child_handle: i64) { - if let (Some(parent), Some(child)) = (get_widget(parent_handle), get_widget(child_handle)) { + if let (Some(parent), Some(child)) = + (get_widget(parent_handle), get_layout_widget(child_handle)) + { // Always use plain addSubview (not addArrangedSubview) so it floats on top parent.addSubview(&child); } @@ -883,6 +914,7 @@ pub fn set_corner_radius(handle: i64, radius: f64) { /// Set a fixed width constraint on a widget. /// Idempotent: deactivates any previous width constraint before creating a new one. pub fn set_width(handle: i64, width: f64) { + max_width::clear_cap(handle); if let Some(view) = get_widget(handle) { // Deactivate old width constraint if any WIDTH_CONSTRAINTS.with(|wc| { @@ -956,7 +988,7 @@ pub fn set_hugging_priority(handle: i64, priority: f64) { /// the child's widthAnchor to that stack's widthAnchor. Useful for VStack /// children (especially embedded NSViews) that should stretch horizontally. pub fn match_stack_width(child_handle: i64) { - if let Some(child) = get_widget(child_handle) { + if let Some(child) = get_layout_widget(child_handle) { unsafe { // Walk up the superview chain to find the NSStackView. // NSStackView may wrap arranged subviews in intermediate views. @@ -995,7 +1027,7 @@ pub fn match_stack_width(child_handle: i64) { /// fill the parent's height. Useful for HStack children that should stretch /// vertically instead of being centered. pub fn match_parent_height(child_handle: i64) { - if let Some(child) = get_widget(child_handle) { + if let Some(child) = get_layout_widget(child_handle) { unsafe { let superview_ptr: *const NSView = msg_send![&*child, superview]; if superview_ptr.is_null() { @@ -1019,7 +1051,7 @@ pub fn match_parent_height(child_handle: i64) { /// Pin a child view's leading and trailing anchors to its superview, forcing it /// to fill the parent's width. pub fn match_parent_width(child_handle: i64) { - if let Some(child) = get_widget(child_handle) { + if let Some(child) = get_layout_widget(child_handle) { unsafe { let superview_ptr: *const NSView = msg_send![&*child, superview]; if superview_ptr.is_null() { diff --git a/crates/perry-ui-macos/src/widgets/padding.rs b/crates/perry-ui-macos/src/widgets/padding.rs index de62433062..e4e88ae435 100644 --- a/crates/perry-ui-macos/src/widgets/padding.rs +++ b/crates/perry-ui-macos/src/widgets/padding.rs @@ -239,6 +239,7 @@ pub(crate) fn set_edge_insets(view: &NSView, top: f64, left: f64, bottom: f64, r if let Some(cls) = AnyClass::get(c"NSStackView") { if view.isKindOfClass(cls) { let _: () = msg_send![view, setEdgeInsets: insets]; + super::max_width::refresh_children(view); return; } } diff --git a/crates/perry-ui-macos/src/widgets/scrollview.rs b/crates/perry-ui-macos/src/widgets/scrollview.rs index 35d2886669..cac77febf2 100644 --- a/crates/perry-ui-macos/src/widgets/scrollview.rs +++ b/crates/perry-ui-macos/src/widgets/scrollview.rs @@ -77,7 +77,7 @@ pub fn create() -> i64 { pub fn set_child(scroll_handle: i64, child_handle: i64) { if let (Some(scroll_view), Some(child)) = ( super::get_widget(scroll_handle), - super::get_widget(child_handle), + super::get_layout_widget(child_handle), ) { unsafe { let sv: &NSScrollView = &*(Retained::as_ptr(&scroll_view) as *const NSScrollView); @@ -128,16 +128,17 @@ pub fn set_child(scroll_handle: i64, child_handle: i64) { let _: () = msg_send![&*c5, setActive: true]; // If NSStackView, switch to GravityAreas, stretch children to fill width + let content = super::get_widget(child_handle).unwrap(); let stack_cls = AnyClass::get(c"NSStackView"); if let Some(cls) = stack_cls { - if (*child).isKindOfClass(cls) { + if (*content).isKindOfClass(cls) { // GravityAreas: children use intrinsic height - let _: () = msg_send![&*child, setDistribution: -1_isize]; + let _: () = msg_send![&*content, setDistribution: -1_isize]; // Change alignment from Leading to Width so children fill cross-axis // NSLayoutAttribute: Leading=5, Width=7 (fills cross-axis) - let _: () = msg_send![&*child, setAlignment: 7_isize]; + let _: () = msg_send![&*content, setAlignment: 7_isize]; - let arranged: Retained = msg_send![&*child, arrangedSubviews]; + let arranged: Retained = msg_send![&*content, arrangedSubviews]; let n: usize = msg_send![&*arranged, count]; for i in 0..n { let subview: *mut AnyObject = msg_send![&*arranged, objectAtIndex: i]; diff --git a/crates/perry-ui-macos/src/widgets/zstack.rs b/crates/perry-ui-macos/src/widgets/zstack.rs index e9b8cf44fa..95cfeb93c3 100644 --- a/crates/perry-ui-macos/src/widgets/zstack.rs +++ b/crates/perry-ui-macos/src/widgets/zstack.rs @@ -50,7 +50,7 @@ pub fn create() -> i64 { pub fn add_child(parent_handle: i64, child_handle: i64) { if let (Some(parent), Some(child)) = ( super::get_widget(parent_handle), - super::get_widget(child_handle), + super::get_layout_widget(child_handle), ) { unsafe { parent.addSubview(&child); diff --git a/crates/perry-ui-macos/tests/native_widget_max_width.rs b/crates/perry-ui-macos/tests/native_widget_max_width.rs new file mode 100644 index 0000000000..037111b0f5 --- /dev/null +++ b/crates/perry-ui-macos/tests/native_widget_max_width.rs @@ -0,0 +1,154 @@ +#[cfg(target_os = "macos")] +fn main() { + use objc2::rc::Retained; + use objc2_app_kit::{NSApplication, NSStackView, NSView}; + use objc2_core_foundation::CGSize; + use objc2_foundation::MainThreadMarker; + use perry_runtime as _; + use perry_ui_macos::{perry_ui_widget_set_max_width, widgets}; + + if std::env::args().any(|arg| arg == "--list") { + println!("native_widget_max_width: test"); + return; + } + let mtm = MainThreadMarker::new().unwrap(); + let _app = NSApplication::sharedApplication(mtm); + let host = NSView::new(mtm); + host.setFrameSize(CGSize::new(1400.0, 400.0)); + + for before_insertion in [true, false] { + let parent = widgets::vstack::create_with_insets(0.0, 0.0, 20.0, 0.0, 40.0); + let column = widgets::vstack::create_with_insets(0.0, 0.0, 32.0, 0.0, 32.0); + let label_text = b"Content"; + let string = perry_runtime::string::js_string_from_bytes( + label_text.as_ptr(), + label_text.len() as u32, + ); + let label = widgets::text::create(string.cast()); + widgets::add_child(column, label); + let parent_view = widgets::get_widget(parent).unwrap(); + parent_view.setTranslatesAutoresizingMaskIntoConstraints(false); + host.addSubview(&parent_view); + let width = parent_view.widthAnchor().constraintEqualToConstant(1200.0); + width.setActive(true); + parent_view + .heightAnchor() + .constraintEqualToConstant(200.0) + .setActive(true); + parent_view + .leadingAnchor() + .constraintEqualToAnchor(&host.leadingAnchor()) + .setActive(true); + parent_view + .topAnchor() + .constraintEqualToAnchor(&host.topAnchor()) + .setActive(true); + + let original = widgets::get_widget(column).unwrap(); + widgets::set_width(column, 900.0); + if before_insertion { + perry_ui_widget_set_max_width(column, 640.0); + } + widgets::add_child(parent, column); + if !before_insertion { + host.layoutSubtreeIfNeeded(); + perry_ui_widget_set_max_width(column, 640.0); + } + assert_eq!( + Retained::as_ptr(&widgets::get_widget(column).unwrap()), + Retained::as_ptr(&original) + ); + + let check = |parent_width: f64, cap: f64| { + width.setConstant(parent_width); + host.layoutSubtreeIfNeeded(); + let frame = original.convertRect_toView(original.bounds(), Some(&parent_view)); + let insets = parent_view + .downcast_ref::() + .unwrap() + .edgeInsets(); + let available = parent_width - insets.left - insets.right; + near(frame.size.width, available.min(cap), "width"); + near( + frame.origin.x, + insets.left + (available - available.min(cap)) / 2.0, + "center", + ); + let label_view = widgets::get_widget(label).unwrap(); + let label_frame = label_view.convertRect_toView(label_view.bounds(), Some(&original)); + // NSTextField frames extend two points beyond their alignment rect. + let aligned = label_view.alignmentRectForFrame(label_frame); + near(aligned.origin.x, 32.0, "content padding"); + }; + for size in [1200.0, 700.0, 400.0, 1200.0] { + check(size, 640.0); + } + perry_ui_widget_set_max_width(column, 480.0); + perry_ui_widget_set_max_width(column, 480.0); + check(1200.0, 480.0); + perry_ui_widget_set_max_width(column, f64::NAN); + perry_ui_widget_set_max_width(column, -1.0); + check(400.0, 480.0); + + // Fill-aligned stacks must not force capped content to become full-width. + widgets::set_alignment(parent, 7); + check(1200.0, 480.0); + widgets::set_hidden(column, true); + host.layoutSubtreeIfNeeded(); + widgets::set_hidden(column, false); + check(1200.0, 480.0); + + widgets::set_edge_insets(parent, 0.0, 30.0, 0.0, 50.0); + check(400.0, 480.0); + widgets::set_width(column, 900.0); + host.layoutSubtreeIfNeeded(); + near( + original.frame().size.width, + 900.0, + "fixed width overrides cap", + ); + perry_ui_widget_set_max_width(column, 480.0); + check(400.0, 480.0); + + // Moving a capped widget retains the cap and binds to the new parent. + let other = widgets::vstack::create(0.0); + let other_view = widgets::get_widget(other).unwrap(); + other_view.setTranslatesAutoresizingMaskIntoConstraints(false); + host.addSubview(&other_view); + widgets::set_width(other, 300.0); + widgets::set_height(other, 200.0); + widgets::add_child(other, column); + host.layoutSubtreeIfNeeded(); + near(original.frame().size.width, 300.0, "reparented width"); + widgets::add_child(parent, column); + check(1200.0, 480.0); + other_view.removeFromSuperview(); + + widgets::clear_children(parent); + widgets::add_child(parent, column); + check(1200.0, 480.0); + let stack = parent_view.downcast_ref::().unwrap(); + assert_eq!(stack.arrangedSubviews().len(), 1); + widgets::remove_child(parent, column); + assert!(stack.arrangedSubviews().is_empty()); + parent_view.removeFromSuperview(); + } + containers::check(mtm); + println!( + "PASS native max-width resizing, padding, updates, insertion, alignment and visibility" + ); + + fn near(actual: f64, expected: f64, label: &str) { + assert!( + (actual - expected).abs() < 0.51, + "{label}: expected {expected}, got {actual}" + ); + } +} + +#[cfg(not(target_os = "macos"))] +fn main() {} + +#[cfg(target_os = "macos")] +#[path = "native_widget_max_width/containers.rs"] +mod containers; diff --git a/crates/perry-ui-macos/tests/native_widget_max_width/containers.rs b/crates/perry-ui-macos/tests/native_widget_max_width/containers.rs new file mode 100644 index 0000000000..c345ce921c --- /dev/null +++ b/crates/perry-ui-macos/tests/native_widget_max_width/containers.rs @@ -0,0 +1,80 @@ +use objc2_app_kit::NSView; +use objc2_core_foundation::CGSize; +use objc2_foundation::MainThreadMarker; +use perry_ui_macos::{app, widgets}; + +pub fn check(mtm: MainThreadMarker) { + for before in [true, false] { + for scroll in [true, false] { + let host = NSView::new(mtm); + host.setFrameSize(CGSize::new(1200.0, 400.0)); + let parent = if scroll { + widgets::scrollview::create() + } else { + widgets::zstack::create() + }; + let parent_view = widgets::get_widget(parent).unwrap(); + host.addSubview(&parent_view); + parent_view.setTranslatesAutoresizingMaskIntoConstraints(false); + let width = parent_view.widthAnchor().constraintEqualToConstant(1000.0); + width.setActive(true); + parent_view + .heightAnchor() + .constraintEqualToConstant(300.0) + .setActive(true); + let column = widgets::vstack::create(0.0); + if before { + widgets::set_max_width(column, 640.0); + } + if scroll { + widgets::scrollview::set_child(parent, column); + } else { + widgets::add_child(parent, column); + } + host.layoutSubtreeIfNeeded(); + if !before { + widgets::set_max_width(column, 640.0); + } + for size in [1000.0, 400.0, 1000.0] { + width.setConstant(size); + host.layoutSubtreeIfNeeded(); + let column_view = widgets::get_widget(column).unwrap(); + let rect = column_view.convertRect_toView(column_view.bounds(), Some(&parent_view)); + assert!( + (rect.size.width - size.min(640.0)).abs() < 1.0, + "scroll={scroll}, before={before}: {rect:?}" + ); + assert!( + (rect.origin.x - (size - size.min(640.0)) / 2.0).abs() < 1.0, + "scroll={scroll}, before={before}: {rect:?}" + ); + } + } + let app_handle = app::app_create(std::ptr::null(), 1000.0, 400.0); + let root = widgets::vstack::create(0.0); + if before { + widgets::set_max_width(root, 640.0); + } + app::app_set_body(app_handle, root); + let root_view = widgets::get_widget(root).unwrap(); + let window = root_view.window().unwrap(); + window.contentView().unwrap().layoutSubtreeIfNeeded(); + if !before { + widgets::set_max_width(root, 640.0); + } + for width in [1000.0, 400.0, 1000.0] { + window.setContentSize(CGSize::new(width, 400.0)); + let content = window.contentView().unwrap(); + content.layoutSubtreeIfNeeded(); + let rect = root_view.convertRect_toView(root_view.bounds(), Some(&content)); + assert!( + (rect.size.width - width.min(640.0)).abs() < 1.0, + "root before={before}: {rect:?}" + ); + assert!( + (rect.origin.x - (width - width.min(640.0)) / 2.0).abs() < 1.0, + "root before={before}: {rect:?}" + ); + } + } +} diff --git a/crates/perry-ui-tvos/src/ffi/styling.rs b/crates/perry-ui-tvos/src/ffi/styling.rs index e1002d34a7..17f52185ca 100644 --- a/crates/perry-ui-tvos/src/ffi/styling.rs +++ b/crates/perry-ui-tvos/src/ffi/styling.rs @@ -179,3 +179,8 @@ pub extern "C" fn perry_ui_stack_set_alignment(handle: i64, alignment: f64) { } } } + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui-visionos/src/ffi_layout.rs b/crates/perry-ui-visionos/src/ffi_layout.rs index 50feedd979..dd6c2b6506 100644 --- a/crates/perry-ui-visionos/src/ffi_layout.rs +++ b/crates/perry-ui-visionos/src/ffi_layout.rs @@ -270,3 +270,8 @@ pub extern "C" fn perry_ui_stack_set_alignment(handle: i64, alignment: f64) { } } } + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui-watchos/src/lib.rs b/crates/perry-ui-watchos/src/lib.rs index f17bd64ad6..da1cf6b2f2 100644 --- a/crates/perry-ui-watchos/src/lib.rs +++ b/crates/perry-ui-watchos/src/lib.rs @@ -1964,3 +1964,8 @@ pub extern "C" fn perry_ui_canvas_draw_image( /// Frame persistence only applies to repositionable desktop windows. #[no_mangle] pub extern "C" fn perry_ui_app_set_frame_autosave_name(_app_handle: i64, _value_ptr: i64) {} + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui-windows/src/ffi/mod.rs b/crates/perry-ui-windows/src/ffi/mod.rs index 814e52e43c..51bd1aeb7d 100644 --- a/crates/perry-ui-windows/src/ffi/mod.rs +++ b/crates/perry-ui-windows/src/ffi/mod.rs @@ -38,3 +38,8 @@ pub mod textfield_scroll; pub mod widget_create; pub mod widget_layout_extras; pub mod widget_tree_state; + +/// Responsive max-width is not implemented on this backend yet. +/// Export the shared ABI so portable perry/ui code continues to compile. +#[no_mangle] +pub extern "C" fn perry_ui_widget_set_max_width(_handle: i64, _max_width: f64) {} diff --git a/crates/perry-ui/src/styling_matrix.rs b/crates/perry-ui/src/styling_matrix.rs index edc5db2b58..f4b5a5c45e 100644 --- a/crates/perry-ui/src/styling_matrix.rs +++ b/crates/perry-ui/src/styling_matrix.rs @@ -284,6 +284,12 @@ pub const MATRIX: &[MatrixRow] = &[ ffi: "perry_ui_widget_set_width", statuses: W_ALL_NATIVE_WEB_TODO, }, + MatrixRow { + widget: "*", + prop: "max_width", + ffi: "perry_ui_widget_set_max_width", + statuses: [Wired, Stub, Stub, Stub, Stub, Stub, Stub, Stub, Wired], + }, MatrixRow { widget: "*", prop: "height", diff --git a/docs/src/ui/layout.md b/docs/src/ui/layout.md index 18b5f0d812..82fca762c1 100644 --- a/docs/src/ui/layout.md +++ b/docs/src/ui/layout.md @@ -161,6 +161,27 @@ Pin a child's edges to its parent container: - `widgetMatchParentWidth(widget)` — stretch to fill parent's width - `widgetMatchParentHeight(widget)` — stretch to fill parent's height +- `widgetSetMaxWidth(widget, maxWidth)` — fill the available width up to a cap and center horizontally (macOS and Web) + +For a responsive content column, apply the cap to the column and put padding +inside it. This keeps a 32-point content inset on narrow windows and grows the +outside gutters on wide windows: + +```typescript +import { App, VStack, Text, widgetSetMaxWidth, setPadding } from "perry/ui"; + +const column = VStack(12, [Text("Responsive content")]); +setPadding(column, 32); +widgetSetMaxWidth(column, 720); +App({ title: "Content", width: 1000, height: 600, body: VStack(0, [column]) }); +``` + +The cap includes padding and can be set before or after adding the widget to a +parent. Calling it again replaces the cap; it also replaces a previous fixed +`widgetSetWidth`. Negative and non-finite values are ignored; zero is valid. +macOS uses Auto Layout, and Web (JavaScript and WebAssembly) uses CSS `max-width` +with automatic side margins. iOS, tvOS, visionOS, watchOS, Android, GTK4, +Windows (including WinUI), and HarmonyOS currently accept this API as a no-op. ## Content Hugging diff --git a/docs/src/ui/styling-matrix.md b/docs/src/ui/styling-matrix.md index e40ce58cfa..ac8e62017b 100644 --- a/docs/src/ui/styling-matrix.md +++ b/docs/src/ui/styling-matrix.md @@ -21,6 +21,7 @@ Legend: `✓` Wired (real native impl), `~` Stub (symbol exists, no-op), `✗` M | `control_size` | `perry_ui_widget_set_control_size` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `hugging` | `perry_ui_widget_set_hugging` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `width` | `perry_ui_widget_set_width` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| `max_width` | `perry_ui_widget_set_max_width` | ✓ | ~ | ~ | ~ | ~ | ~ | ~ | ~ | ✓ | | `height` | `perry_ui_widget_set_height` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `match_parent_width` | `perry_ui_widget_match_parent_width` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `match_parent_height` | `perry_ui_widget_match_parent_height` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | @@ -85,13 +86,13 @@ Legend: `✓` Wired (real native impl), `~` Stub (symbol exists, no-op), `✗` M | Platform | Wired | Stub | Missing | Not applicable | |---|---|---|---|---| -| macOS | 47 | 0 | 0 | 0 | -| iOS | 47 | 0 | 0 | 0 | -| tvOS | 47 | 0 | 0 | 0 | -| visionOS | 47 | 0 | 0 | 0 | -| watchOS | 47 | 0 | 0 | 0 | -| Android | 47 | 0 | 0 | 0 | -| GTK4 | 47 | 0 | 0 | 0 | -| Windows | 47 | 0 | 0 | 0 | -| Web | 47 | 0 | 0 | 0 | +| macOS | 48 | 0 | 0 | 0 | +| iOS | 47 | 1 | 0 | 0 | +| tvOS | 47 | 1 | 0 | 0 | +| visionOS | 47 | 1 | 0 | 0 | +| watchOS | 47 | 1 | 0 | 0 | +| Android | 47 | 1 | 0 | 0 | +| GTK4 | 47 | 1 | 0 | 0 | +| Windows | 47 | 1 | 0 | 0 | +| Web | 48 | 0 | 0 | 0 | diff --git a/docs/src/ui/widgets.md b/docs/src/ui/widgets.md index ece7401069..2fb32eabbd 100644 --- a/docs/src/ui/widgets.md +++ b/docs/src/ui/widgets.md @@ -444,6 +444,7 @@ Every widget handle accepts these: | Helper | Description | |---|---| | `widgetSetWidth(w, n)` / `widgetSetHeight(w, n)` | Explicit size in points | +| `widgetSetMaxWidth(w, n)` | Responsive centered width cap, including padding (macOS and Web; no-op elsewhere) | | `widgetSetBackgroundColor(w, r, g, b, a)` | RGBA in [0, 1] | | `setCornerRadius(w, r)` | Rounded corners in points | | `widgetSetOpacity(w, alpha)` | Opacity in [0, 1] | diff --git a/types/perry/ui/index.d.ts b/types/perry/ui/index.d.ts index 76d53639a3..7e7187da70 100644 --- a/types/perry/ui/index.d.ts +++ b/types/perry/ui/index.d.ts @@ -889,6 +889,14 @@ export function widgetClearChildren(widget: Widget): void; export function widgetRemoveChild(parent: Widget, child: Widget): void; export function widgetReorderChild(widget: Widget, fromIndex: number, toIndex: number): void; export function widgetSetWidth(widget: Widget, width: number): void; +/** + * Fill the available parent width up to maxWidth and center horizontally. + * The cap includes the widget's padding. May be set before or after insertion; + * repeated calls replace the cap. Replaces an explicit widgetSetWidth. + * Invalid (negative or non-finite) caps are ignored; zero is valid. + * Supported on macOS and Web (JS/Wasm). Currently a no-op on other backends. + */ +export function widgetSetMaxWidth(widget: Widget, maxWidth: number): void; export function widgetSetHeight(widget: Widget, height: number): void; export function widgetSetHugging(widget: Widget, priority: number): void; export function widgetSetHidden(widget: Widget, hidden: number): void; From 1de1aabae24cdcd923efbc32432c0999baa77692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 09:54:34 +0200 Subject: [PATCH 6/8] docs: key max-width changelog to PR 10260 --- .../{10167-widget-max-width.md => 10260-widget-max-width.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{10167-widget-max-width.md => 10260-widget-max-width.md} (100%) diff --git a/changelog.d/10167-widget-max-width.md b/changelog.d/10260-widget-max-width.md similarity index 100% rename from changelog.d/10167-widget-max-width.md rename to changelog.d/10260-widget-max-width.md From ccb655cb0b9e0962198bdaa386cd686477de0951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 12:22:23 +0200 Subject: [PATCH 7/8] fix(ui): register max-width coverage and keep fixed widths consistent --- ...-arity.md => 10259-imported-default-ctor-arity.md} | 0 crates/perry-codegen-wasm/src/wasm_runtime.js | 5 ++++- crates/perry-codegen/src/lib.rs | 11 ++++++----- crates/perry-runtime/src/gc/roots/shadow_stack.rs | 1 - docs/examples/ui/layout/max-width.ts | 11 +++++++++++ docs/src/ui/layout.md | 7 +------ scripts/ci_e2e_scope.py | 1 + 7 files changed, 23 insertions(+), 13 deletions(-) rename changelog.d/{10258-imported-default-ctor-arity.md => 10259-imported-default-ctor-arity.md} (100%) create mode 100644 docs/examples/ui/layout/max-width.ts diff --git a/changelog.d/10258-imported-default-ctor-arity.md b/changelog.d/10259-imported-default-ctor-arity.md similarity index 100% rename from changelog.d/10258-imported-default-ctor-arity.md rename to changelog.d/10259-imported-default-ctor-arity.md diff --git a/crates/perry-codegen-wasm/src/wasm_runtime.js b/crates/perry-codegen-wasm/src/wasm_runtime.js index 9749db43e9..a20593c5ba 100644 --- a/crates/perry-codegen-wasm/src/wasm_runtime.js +++ b/crates/perry-codegen-wasm/src/wasm_runtime.js @@ -3112,7 +3112,10 @@ function perry_ui_widget_set_max_width(h, maxWidth) { el.style.marginRight = "auto"; } -function perry_ui_widget_set_width(h, w) { const el = uiGet(h); if (el) { el.style.width = w + "px"; el.style.maxWidth = ""; } } +function perry_ui_widget_set_width(h, w) { + const el = uiGet(h); + if (el) { el.style.width = w + "px"; el.style.minWidth = w + "px"; el.style.maxWidth = w + "px"; el.style.flexShrink = "0"; } +} function perry_ui_widget_set_height(h, height) { const el = uiGet(h); if (el) el.style.height = height + "px"; } function perry_ui_widget_set_hugging(h) { const el = uiGet(h); if (el) el.style.flex = "0 0 auto"; } function perry_ui_widget_match_parent_width(h) { const el = uiGet(h); if (el) el.style.width = "100%"; } diff --git a/crates/perry-codegen/src/lib.rs b/crates/perry-codegen/src/lib.rs index dd085e8618..574f9e1a07 100644 --- a/crates/perry-codegen/src/lib.rs +++ b/crates/perry-codegen/src/lib.rs @@ -75,11 +75,12 @@ pub mod types; pub mod unit_cache; pub use codegen::{ - compile_module, context_free_ctor_param_count, namespace_member_class_key, namespace_member_func_key, - namespace_member_var_key, resolve_target_triple, short_spread_method_capabilities, - user_function_symbol, AppMetadata, CompileOptions, ExportedObjectLiteralCapability, - FpContractMode, ImportedClass, ImportedObjectLiteral, ImportedObjectLiteralMethod, - NamespaceEntry, NamespaceEntryKind, ObjectLiteralMethodCandidate, ShortSpreadMethodCandidate, + compile_module, context_free_ctor_param_count, namespace_member_class_key, + namespace_member_func_key, namespace_member_var_key, resolve_target_triple, + short_spread_method_capabilities, user_function_symbol, AppMetadata, CompileOptions, + ExportedObjectLiteralCapability, FpContractMode, ImportedClass, ImportedObjectLiteral, + ImportedObjectLiteralMethod, NamespaceEntry, NamespaceEntryKind, ObjectLiteralMethodCandidate, + ShortSpreadMethodCandidate, }; pub use collectors::CjsPreambleCensus; // #9843: the segment-view for-of matcher's counter. Exported so the diff --git a/crates/perry-runtime/src/gc/roots/shadow_stack.rs b/crates/perry-runtime/src/gc/roots/shadow_stack.rs index 946b6907a9..ac6894f4c6 100644 --- a/crates/perry-runtime/src/gc/roots/shadow_stack.rs +++ b/crates/perry-runtime/src/gc/roots/shadow_stack.rs @@ -736,7 +736,6 @@ pub(crate) struct ShadowSavepoint { temp_roots: usize, } - /// Capture the current shadow-stack depth so it can be restored after a /// non-local exit. Call at `js_try_push` time, before the protected /// region can push any callee frames. diff --git a/docs/examples/ui/layout/max-width.ts b/docs/examples/ui/layout/max-width.ts new file mode 100644 index 0000000000..df883b1d7c --- /dev/null +++ b/docs/examples/ui/layout/max-width.ts @@ -0,0 +1,11 @@ +// demonstrates: responsive centered content with a maximum width and padding +// docs: docs/src/ui/layout.md +// platforms: macos, linux, windows +// targets: web, wasm + +import { App, VStack, Text, widgetSetMaxWidth, setPadding } from "perry/ui"; + +const column = VStack(12, [Text("Responsive content")]); +setPadding(column, 32); +widgetSetMaxWidth(column, 720); +App({ title: "Content", width: 1000, height: 600, body: VStack(0, [column]) }); diff --git a/docs/src/ui/layout.md b/docs/src/ui/layout.md index 82fca762c1..27edf89df7 100644 --- a/docs/src/ui/layout.md +++ b/docs/src/ui/layout.md @@ -168,12 +168,7 @@ inside it. This keeps a 32-point content inset on narrow windows and grows the outside gutters on wide windows: ```typescript -import { App, VStack, Text, widgetSetMaxWidth, setPadding } from "perry/ui"; - -const column = VStack(12, [Text("Responsive content")]); -setPadding(column, 32); -widgetSetMaxWidth(column, 720); -App({ title: "Content", width: 1000, height: 600, body: VStack(0, [column]) }); +{{#include ../../examples/ui/layout/max-width.ts}} ``` The cap includes padding and can be set before or after adding the widget to a diff --git a/scripts/ci_e2e_scope.py b/scripts/ci_e2e_scope.py index 4270cfe812..419f23dbe0 100755 --- a/scripts/ci_e2e_scope.py +++ b/scripts/ci_e2e_scope.py @@ -154,6 +154,7 @@ "typed_shape_declared_at_allocation", "typed_shape_descriptor", "typed_shape_descriptors", + "widget_max_width", ] SOURCE_SUITE_MAP = { From ebd70cecf6981393913456211fc74db8b3fad09c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 14 Sep 2026 12:22:49 +0200 Subject: [PATCH 8/8] chore: release merge train 189 as v0.5.1567 --- CLAUDE.md | 2 +- Cargo.lock | 162 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 568047b6a7..906bd83cc2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation. -**Current Version:** 0.5.1566 +**Current Version:** 0.5.1567 ## TypeScript Parity Status diff --git a/Cargo.lock b/Cargo.lock index 90632d9236..2bf17339cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5690,7 +5690,7 @@ checksum = "1542e48011813fbdf3c075da4a4ed53ee93c816eef62e36eb5064a6fd2be10a5" [[package]] name = "perry" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "base64 0.22.1", @@ -5754,7 +5754,7 @@ dependencies = [ [[package]] name = "perry-api-manifest" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-dispatch", "serde", @@ -5762,7 +5762,7 @@ dependencies = [ [[package]] name = "perry-audio-miniaudio" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "cc", "libc", @@ -5771,7 +5771,7 @@ dependencies = [ [[package]] name = "perry-codegen" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "aho-corasick", "anyhow", @@ -5789,7 +5789,7 @@ dependencies = [ [[package]] name = "perry-codegen-arkts" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-hir", @@ -5797,7 +5797,7 @@ dependencies = [ [[package]] name = "perry-codegen-glance" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-hir", @@ -5805,7 +5805,7 @@ dependencies = [ [[package]] name = "perry-codegen-js" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-dispatch", @@ -5814,7 +5814,7 @@ dependencies = [ [[package]] name = "perry-codegen-swiftui" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-hir", @@ -5822,7 +5822,7 @@ dependencies = [ [[package]] name = "perry-codegen-wasm" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "base64 0.22.1", @@ -5834,7 +5834,7 @@ dependencies = [ [[package]] name = "perry-codegen-wear-tiles" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-hir", @@ -5842,7 +5842,7 @@ dependencies = [ [[package]] name = "perry-container-compose" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "async-trait", @@ -5870,14 +5870,14 @@ dependencies = [ [[package]] name = "perry-container-e2e" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", ] [[package]] name = "perry-diagnostics" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "serde", "serde_json", @@ -5885,7 +5885,7 @@ dependencies = [ [[package]] name = "perry-dispatch" -version = "0.5.1566" +version = "0.5.1567" [[package]] name = "perry-doc-fixture-my-bindings" @@ -5896,7 +5896,7 @@ dependencies = [ [[package]] name = "perry-doc-tests" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "clap", @@ -5911,7 +5911,7 @@ dependencies = [ [[package]] name = "perry-ext-ads" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "block2", "objc2", @@ -5921,7 +5921,7 @@ dependencies = [ [[package]] name = "perry-ext-argon2" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "argon2", "perry-ffi", @@ -5930,7 +5930,7 @@ dependencies = [ [[package]] name = "perry-ext-axios" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "reqwest", @@ -5939,7 +5939,7 @@ dependencies = [ [[package]] name = "perry-ext-bcrypt" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "bcrypt", "perry-ffi", @@ -5947,7 +5947,7 @@ dependencies = [ [[package]] name = "perry-ext-better-sqlite3" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "rusqlite", @@ -5955,7 +5955,7 @@ dependencies = [ [[package]] name = "perry-ext-cheerio" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "scraper", @@ -5963,7 +5963,7 @@ dependencies = [ [[package]] name = "perry-ext-commander" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "perry-runtime", @@ -5971,7 +5971,7 @@ dependencies = [ [[package]] name = "perry-ext-cron" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "chrono", "cron", @@ -5981,7 +5981,7 @@ dependencies = [ [[package]] name = "perry-ext-dayjs" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "chrono", "perry-ffi", @@ -5989,7 +5989,7 @@ dependencies = [ [[package]] name = "perry-ext-decimal" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "rust_decimal", @@ -5997,7 +5997,7 @@ dependencies = [ [[package]] name = "perry-ext-dotenv" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "serde_json", @@ -6005,7 +6005,7 @@ dependencies = [ [[package]] name = "perry-ext-ethers" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "rand 0.10.2", @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "perry-ext-events" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "perry-runtime", @@ -6021,14 +6021,14 @@ dependencies = [ [[package]] name = "perry-ext-exponential-backoff" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-fastify" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "bytes", "http-body-util", @@ -6046,7 +6046,7 @@ dependencies = [ [[package]] name = "perry-ext-fetch" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "bytes", "lazy_static", @@ -6059,7 +6059,7 @@ dependencies = [ [[package]] name = "perry-ext-http" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "bytes", @@ -6091,7 +6091,7 @@ dependencies = [ [[package]] name = "perry-ext-ioredis" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "lazy_static", "perry-ffi", @@ -6101,7 +6101,7 @@ dependencies = [ [[package]] name = "perry-ext-jsonwebtoken" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "jsonwebtoken", @@ -6112,7 +6112,7 @@ dependencies = [ [[package]] name = "perry-ext-lru-cache" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "lru", "perry-ffi", @@ -6121,7 +6121,7 @@ dependencies = [ [[package]] name = "perry-ext-moment" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "chrono", "perry-ffi", @@ -6129,7 +6129,7 @@ dependencies = [ [[package]] name = "perry-ext-mongodb" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "bson", "futures-util", @@ -6141,7 +6141,7 @@ dependencies = [ [[package]] name = "perry-ext-mysql2" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "chrono", "perry-ffi", @@ -6153,7 +6153,7 @@ dependencies = [ [[package]] name = "perry-ext-nanoid" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "nanoid", "perry-ffi", @@ -6162,7 +6162,7 @@ dependencies = [ [[package]] name = "perry-ext-net" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "bytes", "perry-ffi", @@ -6177,7 +6177,7 @@ dependencies = [ [[package]] name = "perry-ext-node-forge" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "const-oid 0.10.2", "der 0.8.1", @@ -6196,7 +6196,7 @@ dependencies = [ [[package]] name = "perry-ext-nodemailer" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "lettre", "perry-ffi", @@ -6206,7 +6206,7 @@ dependencies = [ [[package]] name = "perry-ext-parcel-watcher" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "notify", "perry-ffi", @@ -6218,7 +6218,7 @@ dependencies = [ [[package]] name = "perry-ext-pdf" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "printpdf", @@ -6226,7 +6226,7 @@ dependencies = [ [[package]] name = "perry-ext-pg" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "sqlx", @@ -6235,7 +6235,7 @@ dependencies = [ [[package]] name = "perry-ext-qs" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "perry-runtime", @@ -6244,7 +6244,7 @@ dependencies = [ [[package]] name = "perry-ext-ratelimit" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "governor", "perry-ffi", @@ -6252,7 +6252,7 @@ dependencies = [ [[package]] name = "perry-ext-sharp" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "fast_image_resize", "image", @@ -6263,7 +6263,7 @@ dependencies = [ [[package]] name = "perry-ext-streams" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "lazy_static", "perry-ffi", @@ -6272,7 +6272,7 @@ dependencies = [ [[package]] name = "perry-ext-typescript" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-ffi", @@ -6292,7 +6292,7 @@ dependencies = [ [[package]] name = "perry-ext-undici" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "perry-runtime", @@ -6301,7 +6301,7 @@ dependencies = [ [[package]] name = "perry-ext-uuid" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "uuid", @@ -6309,7 +6309,7 @@ dependencies = [ [[package]] name = "perry-ext-validator" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-ffi", "perry-validation", @@ -6318,7 +6318,7 @@ dependencies = [ [[package]] name = "perry-ext-ws" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "futures-util", "lazy_static", @@ -6331,7 +6331,7 @@ dependencies = [ [[package]] name = "perry-ext-zlib" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "brotli", "flate2", @@ -6341,7 +6341,7 @@ dependencies = [ [[package]] name = "perry-ffi" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "dashmap 6.2.1", "once_cell", @@ -6351,7 +6351,7 @@ dependencies = [ [[package]] name = "perry-hir" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-api-manifest", @@ -6372,11 +6372,11 @@ dependencies = [ [[package]] name = "perry-native-registration" -version = "0.5.1566" +version = "0.5.1567" [[package]] name = "perry-parser" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-diagnostics", @@ -6390,7 +6390,7 @@ dependencies = [ [[package]] name = "perry-perex" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perex", "regex", @@ -6398,7 +6398,7 @@ dependencies = [ [[package]] name = "perry-runtime" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "ahash", "anyhow", @@ -6458,14 +6458,14 @@ dependencies = [ [[package]] name = "perry-runtime-static" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-runtime", ] [[package]] name = "perry-stdlib" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "aes 0.8.4", "aes 0.9.1", @@ -6560,14 +6560,14 @@ dependencies = [ [[package]] name = "perry-stdlib-static" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "perry-stdlib", ] [[package]] name = "perry-transform" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "perry-hir", @@ -6576,7 +6576,7 @@ dependencies = [ [[package]] name = "perry-ui" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "dirs", "perry-ffi", @@ -6586,7 +6586,7 @@ dependencies = [ [[package]] name = "perry-ui-android" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "itoa", @@ -6604,7 +6604,7 @@ dependencies = [ [[package]] name = "perry-ui-geisterhand" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "rand 0.10.2", "serde", @@ -6614,7 +6614,7 @@ dependencies = [ [[package]] name = "perry-ui-gtk4" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "cairo-rs 0.22.9", @@ -6637,7 +6637,7 @@ dependencies = [ [[package]] name = "perry-ui-ios" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "block2", @@ -6654,7 +6654,7 @@ dependencies = [ [[package]] name = "perry-ui-macos" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "block2", @@ -6671,7 +6671,7 @@ dependencies = [ [[package]] name = "perry-ui-model" -version = "0.5.1566" +version = "0.5.1567" [[package]] name = "perry-ui-test" @@ -6682,11 +6682,11 @@ dependencies = [ [[package]] name = "perry-ui-testkit" -version = "0.5.1566" +version = "0.5.1567" [[package]] name = "perry-ui-tvos" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "block2", @@ -6703,7 +6703,7 @@ dependencies = [ [[package]] name = "perry-ui-visionos" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "block2", @@ -6720,7 +6720,7 @@ dependencies = [ [[package]] name = "perry-ui-watchos" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "block2", "libc", @@ -6734,7 +6734,7 @@ dependencies = [ [[package]] name = "perry-ui-windows" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "libc", @@ -6753,7 +6753,7 @@ dependencies = [ [[package]] name = "perry-ui-windows-winui" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "base64 0.22.1", "libc", @@ -6766,7 +6766,7 @@ dependencies = [ [[package]] name = "perry-updater" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "anyhow", "base64 0.22.1", @@ -6782,7 +6782,7 @@ dependencies = [ [[package]] name = "perry-validation" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "idna", "regex", @@ -6792,7 +6792,7 @@ dependencies = [ [[package]] name = "perry-wasm-host" -version = "0.5.1566" +version = "0.5.1567" dependencies = [ "wasmi", ] diff --git a/Cargo.toml b/Cargo.toml index eb96d810ac..ddf7dc64b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -338,7 +338,7 @@ codegen-units = 1 codegen-units = 1 [workspace.package] -version = "0.5.1566" +version = "0.5.1567" edition = "2021" license = "MIT" repository = "https://github.com/PerryTS/perry"