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:
2026-03-19 17:56:50 +00:00
parent c16142d14c
commit d9e80d8544
4 changed files with 110 additions and 36 deletions

View File

@@ -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 dictsdetected 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)"))))))
;; --------------------------------------------------------------------------