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:
parent
9bf3d1c80e
commit
57bab5d409
12 changed files with 288 additions and 105 deletions
|
|
@ -81,6 +81,19 @@ fi
|
|||
if ! grep -q '(jv\$app.util\$shout' "$out.build/flat.ss"; then
|
||||
echo " FAIL: --direct-link did not emit a direct app->app call"; exit 1
|
||||
fi
|
||||
# A direct-link build registers fn sources, so an uncaught throw prints a Clojure
|
||||
# stack trace mapping each native frame back to ns/name (file:line).
|
||||
if ! grep -q 'jolt-register-source!' "$out.build/flat.ss"; then
|
||||
echo " FAIL: --direct-link did not emit source registrations"; exit 1
|
||||
fi
|
||||
boom_err="$(cd / && "$out" --boom 2>&1 >/dev/null)"
|
||||
for frame in 'app.util/deep-boom' 'app.util/mid-boom' 'app.core/-main'; do
|
||||
if ! printf '%s' "$boom_err" | grep -q "$frame"; then
|
||||
echo " FAIL: stack trace missing frame $frame"
|
||||
echo "--- got ----"; echo "$boom_err"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# Tree-shaking (opt-in): same result, and an unreachable def (the `twice` macro,
|
||||
# expanded at AOT and never called at runtime) is dropped.
|
||||
if ! JOLT_PWD="$app" bin/joltc build -m app.core -o "$out" --tree-shake >/dev/null 2>&1; then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue