backend: cache resolved var cells per reference site (run-path ~5x)
Profiling jolt-i5if showed <=60-bit arithmetic is already native-fast; the real general overhead in the run/-e/-m path is var resolution. Every var reference compiled to (var-deref ns name), which builds + hashes a fresh "ns/name" string and does a hashtable lookup per access (~45ns). The var cell is interned and def-var! mutates it in place, so caching the resolved cell is sound under redefinition. Generalize the devirt per-site cache-cell mechanism to var value references: a ref inside a fn resolves its cell once into the def's closure, then reads it via var-cell-deref (a field read after the first). var-cell-deref is the cell-based var-deref — binding-aware (dynamic vars + *ns* still resolve) and lenient on an unbound root (a forward-declared var doesn't throw, unlike jolt-var-get). Gated by a runtime flag: ON for runtime-compiled code (compile-eval.ss), OFF for the seed mint and AOT build (emit-image.ss) so the seed stays a byte-fixpoint -- prelude.ss is unchanged, only image.ss picks up the new backend. ~5x on a var-ref-heavy loop (1058ms->205ms); ~1.2x on test.check (its generators are more deftype/dispatch-bound than var-deref-bound). No C/FFI. Corpus rows pin redefinition / dynamic binding / forward ref through a cached ref. make test + shakesmoke green, selfhost holds, SCI 211/218, certify 0-new.
This commit is contained in:
parent
f17b68ccfe
commit
04180c1e4e
6 changed files with 245 additions and 164 deletions
|
|
@ -104,6 +104,12 @@
|
|||
;; is only for the bare -e subset with no prelude. Turn prelude mode on once, here,
|
||||
;; so every analyze->emit on this spine sees the full core.
|
||||
((var-deref "jolt.backend-scheme" "set-prelude-mode!") #t)
|
||||
;; Cache resolved var cells per reference site in runtime-compiled code (the big
|
||||
;; win for libraries / REPL code). emit-image.ss turns this back off so the seed
|
||||
;; mint and AOT build stay byte-deterministic. Guarded: the flag is absent in an
|
||||
;; older seed during the first re-mint pass.
|
||||
(let ((scv (var-deref "jolt.backend-scheme" "set-var-cache!")))
|
||||
(when (procedure? scv) (scv #t)))
|
||||
|
||||
;; (quote X) -> X, else x — unwraps a quoted require spec.
|
||||
(define (ce-unquote x)
|
||||
|
|
|
|||
|
|
@ -117,6 +117,16 @@
|
|||
((eq? cell star-ns-cell) (intern-ns! (chez-current-ns)))
|
||||
(else (var-cell-root cell)))))))
|
||||
|
||||
;; var-deref's read on an ALREADY-RESOLVED cell — what compiled code emits when it
|
||||
;; caches the cell at a reference site. Binding stack first, then *ns* thread-local,
|
||||
;; else the raw root. Lenient on an unbound root (returns the sentinel), matching
|
||||
;; var-deref — NOT the strict jolt-var-get, which throws "Unbound var".
|
||||
(define (var-cell-deref cell)
|
||||
(let ((bv (dyn-binding-value cell)))
|
||||
(cond ((not (eq? bv dyn-no-binding)) bv)
|
||||
((eq? cell star-ns-cell) (intern-ns! (chez-current-ns)))
|
||||
(else (var-cell-root cell)))))
|
||||
|
||||
;; jolt-var-get (vars.ss): the var-get fn + deref/@ on a cell. Stack first, then
|
||||
;; the original (which errors on an unbound root, matching Clojure).
|
||||
(define %dyn-var-get jolt-var-get)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@
|
|||
;; top-level entry: in direct-link mode it binds jv$<fqn> for a top-level def; off
|
||||
;; that mode (the minter, runtime eval) it is exactly emit, so output is unchanged.
|
||||
(define jolt-ce-emit-top (var-deref "jolt.backend-scheme" "emit-top-form"))
|
||||
;; Seed mint and AOT build must stay byte-deterministic, so emit the image with var
|
||||
;; cell-caching OFF (compile-eval.ss turned it on for runtime eval; this file loads
|
||||
;; after it). Guarded for the first re-mint pass off an older seed.
|
||||
(let ((scv (var-deref "jolt.backend-scheme" "set-var-cache!")))
|
||||
(when (procedure? scv) (scv #f)))
|
||||
(define (ei-compile-form ctx f optimize?)
|
||||
(let ((ir (jolt-ce-analyze ctx f)))
|
||||
(jolt-ce-emit-top (if optimize? (jolt-ce-run-passes ir ctx) ir))))
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue