Skip to content

feat(jit): poll the async abort flag at native loop back-edges (#410)#464

Merged
InauguralPhysicist merged 1 commit into
mainfrom
fix-410-jit-abort-poll
Jul 7, 2026
Merged

feat(jit): poll the async abort flag at native loop back-edges (#410)#464
InauguralPhysicist merged 1 commit into
mainfrom
fix-410-jit-abort-poll

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

Hard timeouts (eigs_set_abort_flag) now hold at full speed — no EIGS_JIT_OFF required.

Root cause (narrower than the issue assumed)

The gap was only the from-zero thunk: a call-hot function's loop closes natively via the backward patch and never crosses an interpreted back-edge. The OSR tier already polled — its thunk stops before the loop's own JUMP_BACK and re-enters through the interpreted back-edge every iteration, which is where the #379 poll lives. Root-caused during this work; the EMBEDDING.md caveat overstated the gap.

The fix

  • g_vm_abort_flag is never NULL now: unregistered points at a static always-zero int (eigs_set_abort_flag(NULL) maps back to it), so both tiers poll with a single unconditional deref. The interpreter's check simplifies accordingly.
  • The emitter plants movabs &g_vm_abort_flag / mov (%rax),%rax / cmpl $0,(%rax) / jne →epilogue before every native back-edge. On set it bails to the interpreter at the JUMP_BACK (r13d still holds the op's offset, the standard pre-effect bail shape) — the interpreter re-runs the back-edge, consumes the flag, and raises the ordinary catchable aborted error. No error machinery in native code.
  • Unset cost: one predicted-not-taken load+test per back-edge, same shape as the interpreter's.

Planted-fault validation

The new embed_smoke test warms a function past the call threshold then runs one long call (bounded at 200M adds so a regression fails loudly instead of hanging). It FAILS against pre-fix jit.c (the loop ran to the 100M iteration cap ignoring a 150ms timer) and passes after. It sits before the spawn/channel test deliberately — g_vm_multithreaded permanently gates JIT compiles off for the process, so a later placement would test the interpreter twice (verified: zero compiles happen after that test).

Gates

  • make jit-smoke (with the new g_vm_abort_flag stub), make embed-smoke, tools/embed_stack_soak.sh
  • Release suite 2584/2584; ASan+UBSan detect_leaks=1 2584/2584
  • Bench n=5 medians within noise: dmg_shape 326.3→323.4 ms, idxset 39.6→38.8 ms
  • EMBEDDING.md / eigs_embed.h caveats deleted

Closes #410

🤖 Generated with Claude Code

Hard timeouts (eigs_set_abort_flag) now hold at full speed. The gap was
the FROM-ZERO thunk: a call-hot function's loop closes natively via the
backward patch and never crosses an interpreted back-edge (the OSR tier
exits at its own back-edge each iteration and re-enters through the
interpreted JUMP_BACK, so it always polled — root-caused during this
work; the EMBEDDING caveat overstated the gap).

The emitter plants movabs/deref/cmpl before every native back-edge and
bails to the interpreter AT the JUMP_BACK when set (r13d still holds the
op's offset) — the interpreter re-runs the back-edge, consumes the flag,
and raises the ordinary catchable 'aborted' error. No error machinery in
native code. g_vm_abort_flag is now never NULL (unregistered -> static
zero sentinel), so both tiers poll with one unconditional deref.

embed_smoke gains the from-zero abort test, placed BEFORE the spawn test
(g_vm_multithreaded permanently gates JIT compiles off for the process)
and validated as a planted fault: it FAILS against the pre-fix jit.c
(loop runs to the 100M cap ignoring the timer) and passes after.

Gates: jit-smoke, embed-smoke, embed_stack_soak, release 2584/2584,
ASan+UBSan detect_leaks=1 2584/2584. Bench n=5 medians within noise:
dmg_shape 326.3 -> 323.4 ms, idxset 39.6 -> 38.8 ms.

Closes #410

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@InauguralPhysicist InauguralPhysicist merged commit 8289cbe into main Jul 7, 2026
17 checks passed
@InauguralPhysicist InauguralPhysicist deleted the fix-410-jit-abort-poll branch July 7, 2026 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: poll the abort flag at loop back-edges (hard timeouts without EIGS_JIT_OFF)

1 participant