Scalar-replace short-lived record allocations (jolt-15jq) (#132)
scalar-replace already folds non-escaping const-key map literals
((:k {:k a ..}) -> a, and drops a let-bound map that doesn't escape).
Extend the same fold to record constructors: a (->Rec a b c) is a
positional struct whose declared field order lives in the record-shapes
registry, so a field read on a non-escaping ctor folds to the matching
positional arg and the allocation disappears.
Direct form (:field (->Rec ..)) and the let-bound form both handled,
threaded through run-passes via a per-unit shape registry (new
jolt.host/record-shapes accessor). Soundness: ctor args must be pure
(duplicated/discarded like map vals), arg count must equal the field
count, and only declared-field reads fold — a record answers the virtual
:jolt/deftype key with its type tag and any other key with nil, neither
of which is a positional arg, so those keep the allocation. pure? now
treats a record ctor of pure args as pure, so nested records (a Ray
holding a Vec3) fold bottom-up.
Allocation-bound microbench (non-escaping record built + field-read in a
hot loop): 69.6s -> 2.4s, landing on the no-record arithmetic baseline.
The ray tracer is unchanged — its vec3 results escape (returned/stored
each op), so they genuinely allocate; that's a separate problem.
Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
parent
ae593b0f66
commit
048de0200d
4 changed files with 204 additions and 28 deletions
|
|
@ -13,9 +13,9 @@
|
|||
:refer, so jolt.passes stays the only namespace the back end imports.
|
||||
|
||||
Portable Clojure: kernel-tier fns + seed primitives only."
|
||||
(:require [jolt.host :refer [inline-enabled?]]
|
||||
(:require [jolt.host :refer [inline-enabled? record-shapes]]
|
||||
[jolt.passes.fold :refer [const-fold]]
|
||||
[jolt.passes.inline :refer [inline-node flatten-lets scalar-replace dirty]]
|
||||
[jolt.passes.inline :refer [inline-node flatten-lets scalar-replace dirty set-rec-shapes!]]
|
||||
[jolt.passes.types :refer [run-inference
|
||||
check-form infer-body reinfer-def
|
||||
set-rtenv! set-vtypes! join-types
|
||||
|
|
@ -33,7 +33,8 @@
|
|||
type is proven. Otherwise (core + bootstrap) just const-fold, as before."
|
||||
[node ctx]
|
||||
(if (inline-enabled? ctx)
|
||||
(let [opt (loop [i 0 n (const-fold node)]
|
||||
(let [_ (set-rec-shapes! (record-shapes ctx)) ;; record ctor fold (jolt-15jq)
|
||||
opt (loop [i 0 n (const-fold node)]
|
||||
(reset! dirty false)
|
||||
(let [n2 (const-fold (scalar-replace (flatten-lets (inline-node n ctx))))]
|
||||
(if (and @dirty (< i 8))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue