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
|
|
@ -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")))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -611,6 +611,8 @@
|
|||
{:suite "host-interop / class tokens & readers" :label "indexOf int needle is a char code" :expected "1" :actual "(.indexOf \"a=b\" 61)"}
|
||||
{:suite "host-interop / exception + HashMap shims" :label "getMessage on a thrown string" :expected "\"class java.lang.String cannot be cast to class java.lang.Throwable (java.lang.String and java.lang.Throwable are in module java.base of loader 'bootstrap')\"" :actual "(try (throw \"boom\") (catch Throwable e (.getMessage e)))"}
|
||||
{:suite "host-interop / exception + HashMap shims" :label "getMessage on ex-info" :expected "\"bad\"" :actual "(try (throw (ex-info \"bad\" {})) (catch Throwable e (.getMessage e)))"}
|
||||
{:suite "host-interop / exception + HashMap shims" :label "calling a non-fn throws ClassCastException" :expected ":ccx" :actual "(try (1 2) (catch ClassCastException _ :ccx))"}
|
||||
{:suite "host-interop / exception + HashMap shims" :label "non-fn cast is a RuntimeException too" :expected ":rt" :actual "(try ((identity 5)) (catch RuntimeException _ :rt))"}
|
||||
{:suite "host-interop / exception + HashMap shims" :label "HashMap get" :expected "2" :actual "(let [m (HashMap. {:a 1 :b 2})] (.get m :b))"}
|
||||
{:suite "host-interop / exception + HashMap shims" :label "HashMap put + size" :expected "2" :actual "(let [m (HashMap. {})] (.put m :x 1) (.put m :y 2) (.size m))"}
|
||||
{:suite "host-interop / reader-feature toggle" :label "features default to jolt+default" :expected "true" :actual "(contains? (set (__reader-features)) \"jolt\")"}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue