Clojure stack traces via source registry + native frame walk

A direct-link build emits (jolt-register-source! short-name ns name file line)
once per fn def — at definition time, so zero per-call cost. On an uncaught
error the reporter walks Chez's native continuation frames (jolt-throw captures
the live continuation via call/cc; host conditions carry their own
&continuation), maps each frame's procedure name through the registry, and
prints a Clojure backtrace 'ns/name (file:line)'. Wired into both the cli and a
built binary's launcher.

Frames are keyed by the short munged fn name Chez actually reports (emit-fn's
letrec self-binding), not jv$ns$name; a cross-namespace collision degrades to
the bare frame name rather than a wrong attribution. The analyzer carries the
original form's position through defn macroexpansion onto the def node.

Calling a non-fn now throws a catchable ClassCastException (via jolt-throw)
naming the operator, instead of a raw Chez error.

Caveats (documented in source-registry.ss): names map only in direct-link/AOT
closed-world builds — the open-world -e/repl/run path falls back to the
top-level location; and pervasive TCO erases tail-call frames, so a mapped
trace shows only the non-tail spine. JOLT_DEBUG_FRAMES dumps raw frame names.

Re-mint (analyzer + backend); prelude byte-identical (direct-link off during
mint). Corpus rows certified, build-smoke asserts the trace.
This commit is contained in:
Yogthos 2026-06-25 21:49:11 -04:00
parent 9bf3d1c80e
commit 57bab5d409
12 changed files with 288 additions and 105 deletions

View file

@ -12,6 +12,10 @@
(defmethod greet :soft [_] "greet:soft")
(defn -main [& args]
;; --boom: throw through a two-deep call chain so build-smoke can assert the
;; native stack trace. Off the normal path, so default output is unchanged.
(when (= (first args) "--boom")
(util/mid-boom "not-a-number"))
;; the resource is baked into the binary (deps.edn :jolt/build :embed), so this
;; resolves with no resources/ dir on disk, run from any cwd.
(println (slurp (io/resource "greeting.txt")))

View file

@ -4,6 +4,15 @@
(defn shout [s]
(str/upper-case (str s "!")))
;; A two-deep non-tail call chain that throws — exercises native stack traces in a
;; direct-link build (build-smoke runs -main with a --boom sentinel arg).
(defn deep-boom [x]
(assert (number? x) "needs a number")
(* x 2))
(defn mid-boom [x]
(inc (deep-boom x)))
(defmacro twice [x]
`(do ~x ~x))