Merge pull request #53 from jolt-lang/inline-var-deref

backend: inline the var deref at indirect call sites (fib 1.75x)
This commit is contained in:
Dmitri Sotnikov 2026-06-10 16:42:56 -04:00 committed by GitHub
commit 1d373299a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -286,10 +286,25 @@
:var (let [cell (cell-for ctx (node :ns) (node :name))]
(if (direct-var? ctx cell)
(cell :root) # direct link: embed the fn value
# Indirect: live deref. Quote the cell so it's embedded by
# reference (a bare table in arg position would be re-evaluated as
# a constructor — deep-copying it, and any atom in :root, each call).
(tuple var-get (tuple 'quote cell))))
# Indirect: live deref, with the var-get FN CALL inlined away
# (jolt-8sq): a non-dynamic var's value is always its root, so
# the common case is two native table ops + a branch instead of
# a function call. Dynamic vars take the full var-get (thread-
# binding walk). The cell is quoted so it's embedded by
# reference (a bare table in arg position would be re-evaluated
# as a constructor — deep-copying it, and any atom in :root,
# each call). Redefinition stays live: :root is read per call.
# The :dynamic check must be PER CALL, not at emit: a
# (def ^:dynamic x) in the same compiled unit marks the cell
# dynamic only when the def RUNS, after this site was emitted —
# the same reason JVM Clojure's Var.deref() checks the
# thread-bound bit on every call. Non-dynamic vars (the vast
# majority) pay two native table ops + a branch instead of a
# function call.
(let [qcell (tuple 'quote cell)]
['if ['in qcell :dynamic]
(tuple var-get qcell)
['in qcell :root]])))
# (var x): the var object itself (not its value) — the embedded cell, by
# reference. binding keys its thread-binding frame on this exact cell.
:the-var (tuple 'quote (cell-for ctx (node :ns) (node :name)))