Skip to content

fix(warnings): SubmodBucket dead-code warning from #7433 #290

fix(warnings): SubmodBucket dead-code warning from #7433

fix(warnings): SubmodBucket dead-code warning from #7433 #290

Workflow file for this run

# CI arm for the exception transport (#7302) and its owned unwinder.
#
# Two things need exercising, and neither is visible from behavior alone:
#
# 1. The owned single-phase walker must actually CARRY throws. If it
# silently starts declining every throw, every test still passes — the
# system unwinder is the fallback and semantics are identical — and the
# only symptom is that the optimization quietly stopped happening. So
# this job asserts `fallback=0` with a nonzero `fast=` count, not merely
# that the program produced the right answer.
# 2. The walker's agreement with the system unwinder must be re-proven, not
# assumed from the bring-up run. `PERRY_EH_WALKER=diff` predicts the
# landing for every throw and asserts it inside the personality against
# the system unwinder's answer; this job requires a nonzero verified
# count and zero declines.
#
# Both are the "assert the subject was LIVE" rule from CLAUDE.md's "Four
# ways a gate can be unable to fail" — a green run here means the fast path
# ran and agreed, not that nothing threw.
#
# NON-REQUIRED until it has run green once on main; promote afterwards (a
# new gate has never been green, so promoting first blocks every PR).
name: eh-transport
# No trigger-level `paths:` — a required check whose workflow is
# path-filtered at the trigger never creates a check run for unrelated PRs,
# so the context waits forever and blocks the merge. Filtering lives in the
# `changes` job: a job skipped by `if:` still reports a check run.
on:
pull_request:
push:
branches: [main]
concurrency:
group: eh-transport-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}
# One group per main COMMIT, cancelling PR runs only. `cancel-in-progress:
# false` alone does not protect a `main` run: GitHub allows at most one
# PENDING run per group and cancels the previously pending one when a new run
# enters, regardless of that setting. That is #7205 — measured here as EIGHT
# consecutive `main` runs cancelled, zero executions. Keying push runs on the
# SHA gives every merged commit a group of its own.
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
changes:
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
outputs:
relevant: ${{ steps.filter.outputs.relevant }}
steps:
- id: filter
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "relevant=true" >> "$GITHUB_OUTPUT"
exit 0
fi
files=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" \
--paginate --jq '.[].filename')
if echo "$files" | grep -qE '^(crates/perry-runtime/src/(eh|eh_walker|eh_windows|exception)\.rs$|crates/perry-codegen/src/stmt/|test-files/test_(gap|issue)_7302_|\.cargo/config\.toml$|Cargo\.toml$|\.github/workflows/eh-transport\.yml$)'; then
echo "relevant=true" >> "$GITHUB_OUTPUT"
else
echo "relevant=false" >> "$GITHUB_OUTPUT"
fi
eh-transport:
needs: changes
if: needs.changes.outputs.relevant == 'true'
# arm64 macOS: the owned walker's current platform. Other targets fall
# back to the system unwinder by design, so there is nothing to assert
# there beyond the behavior the parity suites already cover.
runs-on: macos-15
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- uses: ./.github/actions/setup-llvm22
- name: Setup Node.js
uses: actions/setup-node@v7
with:
node-version-file: .node-version
- uses: Swatinem/rust-cache@v2
with:
shared-key: "${{ runner.os }}-perry"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Build compiler + runtime archives
run: |
cargo build --profile perry-dev -p perry -p perry-runtime-static \
-p perry-stdlib-static
- name: Owned transport — liveness, agreement, fallback, parity
run: |
set -euo pipefail
export PERRY_RUNTIME_DIR="$PWD/target/perry-dev"
export PERRY_NO_AUTO_OPTIMIZE=1
BIN=target/perry-dev/perry
# Two subjects: the structural try/catch matrix (nesting, finally
# on both edges, return-in-try, rethrow) and the GC probe that
# throws across a collection point.
for SRC in test-files/test_gap_7302_invoke_eh_paths.ts \
test-files/test_gap_7302_gc_throw_across_collection.ts; do
NAME=$(basename "$SRC" .ts)
"$BIN" "$SRC" -o "/tmp/$NAME"
# Oracle parity first: a fast path that is wrong is worse than
# no fast path, so nothing below is meaningful without this.
node --experimental-strip-types --no-warnings "$SRC" > "/tmp/$NAME.node"
"/tmp/$NAME" > "/tmp/$NAME.perry"
diff "/tmp/$NAME.node" "/tmp/$NAME.perry"
# LIVENESS: the walker carried every throw. `fallback=0` alone
# would pass vacuously on a program that never threw, so require
# a nonzero fast count too.
stats=$(PERRY_EH_WALKER=stats "/tmp/$NAME" 2>&1 >/dev/null | grep "eh-walker: fast=")
echo "$NAME: $stats"
fast=$(echo "$stats" | sed -E 's/.*fast=([0-9]+).*/\1/')
fb=$(echo "$stats" | sed -E 's/.*fallback=([0-9]+).*/\1/')
[ "$fast" -gt 0 ] || { echo "walker never took the fast path"; exit 1; }
[ "$fb" -eq 0 ] || { echo "walker fell back $fb time(s)"; exit 1; }
# AGREEMENT: re-prove the prediction against the system
# unwinder on this build, rather than trusting the bring-up run.
# The personality aborts on mismatch; the tally must show real
# verifications and no declines.
diffout=$(PERRY_EH_WALKER=diff "/tmp/$NAME" 2>&1 >/dev/null | grep "eh-walker diff:")
echo "$NAME: $diffout"
ver=$(echo "$diffout" | sed -E 's/.*verified=([0-9]+).*/\1/')
dec=$(echo "$diffout" | sed -E 's/.*declined=([0-9]+).*/\1/')
[ "$ver" -gt 0 ] || { echo "diff mode verified nothing"; exit 1; }
[ "$dec" -eq 0 ] || { echo "walk declined $dec throw(s)"; exit 1; }
# FALLBACK: the escape hatch must still produce correct output —
# it is the bisection knob and the every-other-platform path.
PERRY_EH_WALKER=off "/tmp/$NAME" > "/tmp/$NAME.off"
diff "/tmp/$NAME.node" "/tmp/$NAME.off"
done
- name: Throws on perry/thread workers
run: |
set -euo pipefail
export PERRY_RUNTIME_DIR="$PWD/target/perry-dev"
export PERRY_NO_AUTO_OPTIMIZE=1
# Each worker walks ITS OWN stack while the row cache and image
# index are process-global behind a mutex. node cannot run
# perry/thread, so the oracle here is the system unwinder itself:
# walker-on must equal walker-off, and diff mode must agree on
# every worker throw.
SRC=test-files/test_issue_7302_thread_throws.ts
target/perry-dev/perry "$SRC" -o /tmp/eh_threads
/tmp/eh_threads > /tmp/eh_threads.on
PERRY_EH_WALKER=off /tmp/eh_threads > /tmp/eh_threads.off
diff /tmp/eh_threads.on /tmp/eh_threads.off
stats=$(PERRY_EH_WALKER=stats /tmp/eh_threads 2>&1 >/dev/null | grep "eh-walker: fast=")
echo "threads: $stats"
fast=$(echo "$stats" | sed -E 's/.*fast=([0-9]+).*/\1/')
fb=$(echo "$stats" | sed -E 's/.*fallback=([0-9]+).*/\1/')
[ "$fast" -gt 0 ] || { echo "walker never took the fast path on workers"; exit 1; }
[ "$fb" -eq 0 ] || { echo "walker fell back $fb time(s) on workers"; exit 1; }
diffout=$(PERRY_EH_WALKER=diff /tmp/eh_threads 2>&1 >/dev/null | grep "eh-walker diff:")
echo "threads: $diffout"
dec=$(echo "$diffout" | sed -E 's/.*declined=([0-9]+).*/\1/')
ver=$(echo "$diffout" | sed -E 's/.*verified=([0-9]+).*/\1/')
[ "$ver" -gt 0 ] || { echo "diff mode verified nothing on workers"; exit 1; }
[ "$dec" -eq 0 ] || { echo "walk declined $dec worker throw(s)"; exit 1; }
- name: Cross-helper throws + unwind-table self-check
run: |
set -euo pipefail
export PERRY_RUNTIME_DIR="$PWD/target/perry-dev"
export PERRY_NO_AUTO_OPTIMIZE=1
# Throws crossing runtime Rust frames (throwing getter, throwing
# toString, JSON.parse, map callback, deep recursion). These are
# the frames the panic=abort + force-unwind-tables contract exists
# for; a runtime built without the tables aborts here with the
# self-check's message instead of stranding the throw silently.
SRC=test-files/test_gap_7302_throw_across_helper_frames.ts
target/perry-dev/perry "$SRC" -o /tmp/eh_helpers
node --experimental-strip-types --no-warnings "$SRC" > /tmp/eh_helpers.node
/tmp/eh_helpers > /tmp/eh_helpers.perry
diff /tmp/eh_helpers.node /tmp/eh_helpers.perry