The host combined-binary integration test exposed a new JIT-unsafe class: Dream's error middleware (host/wrap-errors -> dream-catch-with) failed to catch a thrown error under JIT — it escaped as "Unhandled exception" and truncated the host middleware suite (7/9 vs 9/9 on CEK). Root cause: the VM's OP_PUSH_HANDLER (the compiled form of `guard`) only intercepts a VM-level RAISE (opcode 37); it does NOT catch the OCaml Eval_error that the `error` primitive throws from a CALL/CALL_PRIM in a callee frame. So a JIT-compiled `guard` silently fails to catch. dream-catch-with is curried ((fn (on-error) (fn (next) (fn (req) (guard ...))))), so the guard lives in a NESTED closure — JIT-compiling the outer function mints that inner guard as a VmClosure with the broken VM handler. Fix (central, not per-callsite): scan a JIT candidate's bytecode RECURSIVELY — including nested closure code in the constant pool — for OP_PUSH_HANDLER, and skip JIT for any handler-installing function. It then runs on the CEK, whose guard catches correctly. Covers dream-catch-with, host wrap-errors/blog-render, and every other guard / handler-bind user automatically. Verified: minimal direct guard and curried cross-frame guard both return the caught value under JIT (were "Unhandled exception"); the host run's "kaboom" escapes went 2 -> 0. (Remaining host blog/page failures are "Undefined symbol: render-page" — the host's native render fn, absent from the standalone sx_server.exe; identical on CEK, i.e. an environment artifact, not a JIT regression. The combined host binary has render-page.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
74 KiB
74 KiB