CEK frame records: eliminate Hashtbl for all 29 frame types
Transpiler detects dict literals with a "type" string field and emits CekFrame records instead of Dict(Hashtbl). Maps frame-specific fields to generic record slots: cf_type, cf_env, cf_name, cf_body, cf_remaining, cf_f, cf_args (also evaled), cf_results (also raw-args), cf_extra (ho-type/scheme/indexed/match-val/current-item/...), cf_extra2 (emitted/effect-list/first-render) Runtime get_val handles CekFrame with direct field match — O(1) field access vs Hashtbl.find. Bootstrapper: skip stdlib.sx entirely (already OCaml primitives). Result: 29 CekFrame + 2 CekState = 31 record types, only 8 Hashtbl.create remaining (effect-annotations, empty dicts). Benchmark (200 divs): 2.94s → 1.71s (1.7x speedup from baseline). Real pages: ~same as CekState-only (frames are <20% of allocations; states dominate at 199K/page). Foundation for JIT: record-based value representation enables typed compilation — JIT can emit direct field access instead of hash table lookups. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -428,13 +428,52 @@
|
||||
" with String s -> s | _ -> \"\")")))
|
||||
"; cs_value = " (ml-expr-inner (get d "value") set-vars)
|
||||
" })")
|
||||
;; Regular dict — Hashtbl
|
||||
(str "(let _d = Hashtbl.create " (str (round (len items)))
|
||||
" in " (join "; " (map (fn (k)
|
||||
(str "Hashtbl.replace _d " (ml-quote-string k)
|
||||
" " (ml-expr-inner (get d k) set-vars)))
|
||||
items))
|
||||
"; Dict _d)")))))
|
||||
;; Optimize CEK frame dicts — detected by having a "type" string field.
|
||||
;; Maps frame fields to generic CekFrame record slots.
|
||||
(if (and (some (fn (k) (= k "type")) items)
|
||||
(= (type-of (get d "type")) "string"))
|
||||
(let ((frame-type (get d "type"))
|
||||
(ef (fn (field) (if (some (fn (k) (= k field)) items)
|
||||
(ml-expr-inner (get d field) set-vars) "Nil"))))
|
||||
(str "(CekFrame { cf_type = " (ml-quote-string frame-type)
|
||||
"; cf_env = " (ef "env")
|
||||
"; cf_name = " (if (= frame-type "if") (ef "else") (ef "name"))
|
||||
"; cf_body = " (if (= frame-type "if") (ef "then") (ef "body"))
|
||||
"; cf_remaining = " (ef "remaining")
|
||||
"; cf_f = " (ef "f")
|
||||
"; cf_args = " (cond
|
||||
(some (fn (k) (= k "evaled")) items) (ef "evaled")
|
||||
(some (fn (k) (= k "args")) items) (ef "args")
|
||||
:else "Nil")
|
||||
"; cf_results = " (cond
|
||||
(some (fn (k) (= k "results")) items) (ef "results")
|
||||
(some (fn (k) (= k "raw-args")) items) (ef "raw-args")
|
||||
:else "Nil")
|
||||
"; cf_extra = " (cond
|
||||
(some (fn (k) (= k "ho-type")) items) (ef "ho-type")
|
||||
(some (fn (k) (= k "scheme")) items) (ef "scheme")
|
||||
(some (fn (k) (= k "indexed")) items) (ef "indexed")
|
||||
(some (fn (k) (= k "value")) items) (ef "value")
|
||||
(some (fn (k) (= k "phase")) items) (ef "phase")
|
||||
(some (fn (k) (= k "has-effects")) items) (ef "has-effects")
|
||||
(some (fn (k) (= k "match-val")) items) (ef "match-val")
|
||||
(some (fn (k) (= k "current-item")) items) (ef "current-item")
|
||||
(some (fn (k) (= k "update-fn")) items) (ef "update-fn")
|
||||
(some (fn (k) (= k "head-name")) items) (ef "head-name")
|
||||
:else "Nil")
|
||||
"; cf_extra2 = " (cond
|
||||
(some (fn (k) (= k "emitted")) items) (ef "emitted")
|
||||
(some (fn (k) (= k "effect-list")) items) (ef "effect-list")
|
||||
(some (fn (k) (= k "first-render")) items) (ef "first-render")
|
||||
:else "Nil")
|
||||
" })"))
|
||||
;; Regular dict — Hashtbl
|
||||
(str "(let _d = Hashtbl.create " (str (round (len items)))
|
||||
" in " (join "; " (map (fn (k)
|
||||
(str "Hashtbl.replace _d " (ml-quote-string k)
|
||||
" " (ml-expr-inner (get d k) set-vars)))
|
||||
items))
|
||||
"; Dict _d)"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user