Unify JIT to lazy-only: remove allowlist, all lambdas compile on first call

Replace the manual jit_allowlist (StringSet of ~40 function names) with
universal lazy compilation. Every named lambda gets one compile attempt
on first call; failures are sentineled and never retried.

Compiler internals are still pre-compiled at startup (bootstrapping the
JIT itself), but everything else compiles lazily — no manual curation.

Remove jit-allow command (no longer needed). Remove StringSet module.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 18:34:27 +00:00
parent a6e0e84521
commit 13ba5ee423

View File

@@ -665,32 +665,8 @@ let sx_render_to_html expr env =
CEK, cache result). cek_call checks this before CEK dispatch. *)
let _jit_compiling = ref false (* re-entrancy guard *)
(** Functions allowed for JIT compilation. Others go straight to CEK.
Populated with compiler internals at registration time; extended
dynamically via (jit-allow name) command. *)
module StringSet = Set.Make(String)
let jit_allowlist = ref (StringSet.of_list [
(* Compiler internals *)
"compile"; "compile-module"; "compile-expr"; "compile-symbol";
"compile-dict"; "compile-list"; "compile-if"; "compile-when";
"compile-and"; "compile-or"; "compile-begin"; "compile-let";
"compile-letrec"; "compile-lambda"; "compile-define"; "compile-set";
"compile-quote"; "compile-cond"; "compile-case"; "compile-case-clauses";
"compile-thread"; "compile-thread-step"; "compile-defcomp";
"compile-defmacro"; "compile-quasiquote"; "compile-qq-expr";
"compile-qq-list"; "compile-call";
"make-emitter"; "make-pool"; "make-scope"; "pool-add";
"scope-define-local"; "scope-resolve";
"emit-byte"; "emit-u16"; "emit-i16"; "emit-op"; "emit-const";
"current-offset"; "patch-i16";
(* Parser *)
"sx-parse"; "sx-serialize"; "sx-serialize-dict";
(* Pure transforms *)
"aser"; "resolve-nav-path"; "tw"; "serialize";
"render-to-html"; "render-attrs"; "render-html-element";
"merge-spread-attrs"; "cssx-process-token";
"signal"; "computed"; "freeze-scope"; "freeze-signal";
])
(* JIT compilation is lazy-only: every named lambda gets one compile
attempt on first call. Failures are sentineled (never retried). *)
let register_jit_hook env =
Sx_ref.jit_call_hook := Some (fun f args ->
@@ -710,7 +686,6 @@ let register_jit_hook env =
| None ->
let fn_name = match l.l_name with Some n -> n | None -> "?" in
if !_jit_compiling then None
else if not (StringSet.mem fn_name !jit_allowlist) then None
else begin
_jit_compiling := true;
let t0 = Unix.gettimeofday () in
@@ -879,20 +854,27 @@ let rec dispatch env cmd =
| exn -> send_error (Printexc.to_string exn))
| List [Symbol "vm-compile-adapter"] ->
(* Register JIT hook — all functions in the allowlist compile lazily
on first call. Pre-compile the compiler itself so subsequent
JIT compilations run at VM speed, not CEK speed. *)
(* Register lazy JIT hook — all named lambdas compile on first call.
Pre-compile compiler internals so subsequent JIT compilations
run at VM speed, not CEK speed. *)
register_jit_hook env;
let t0 = Unix.gettimeofday () in
let count = ref 0 in
(* Pre-compile compiler internals only — these bootstrap the JIT.
Everything else (render, aser, parser) compiles lazily on first call. *)
StringSet.iter (fun name ->
if String.length name >= 7 && String.sub name 0 7 = "compile"
|| List.mem name ["make-emitter"; "make-pool"; "make-scope"; "pool-add";
let compiler_names = [
"compile"; "compile-module"; "compile-expr"; "compile-symbol";
"compile-dict"; "compile-list"; "compile-if"; "compile-when";
"compile-and"; "compile-or"; "compile-begin"; "compile-let";
"compile-letrec"; "compile-lambda"; "compile-define"; "compile-set";
"compile-quote"; "compile-cond"; "compile-case"; "compile-case-clauses";
"compile-thread"; "compile-thread-step"; "compile-defcomp";
"compile-defmacro"; "compile-quasiquote"; "compile-qq-expr";
"compile-qq-list"; "compile-call";
"make-emitter"; "make-pool"; "make-scope"; "pool-add";
"scope-define-local"; "scope-resolve";
"emit-byte"; "emit-u16"; "emit-i16"; "emit-op"; "emit-const";
"current-offset"; "patch-i16"] then
"current-offset"; "patch-i16";
] in
List.iter (fun name ->
match Hashtbl.find_opt env.bindings name with
| Some (Lambda l) when l.l_compiled = None ->
l.l_compiled <- Some Sx_vm.jit_failed_sentinel;
@@ -900,13 +882,9 @@ let rec dispatch env cmd =
| Some cl -> l.l_compiled <- Some cl; incr count
| None -> ())
| _ -> ()
) !jit_allowlist;
) compiler_names;
let dt = Unix.gettimeofday () -. t0 in
Printf.eprintf "[jit] Pre-compiled %d compiler functions in %.3fs (lazy JIT active)\n%!" !count dt;
send_ok ()
| List [Symbol "jit-allow"; String name] ->
jit_allowlist := StringSet.add name !jit_allowlist;
Printf.eprintf "[jit] Pre-compiled %d compiler functions in %.3fs (lazy JIT active for all)\n%!" !count dt;
send_ok ()
| List [Symbol "set-request-cookies"; Dict cookies] ->