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:
@@ -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,34 +854,37 @@ 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";
|
||||
"scope-define-local"; "scope-resolve";
|
||||
"emit-byte"; "emit-u16"; "emit-i16"; "emit-op"; "emit-const";
|
||||
"current-offset"; "patch-i16"] then
|
||||
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;
|
||||
(match Sx_vm.jit_compile_lambda l env.bindings with
|
||||
| Some cl -> l.l_compiled <- Some cl; incr count
|
||||
| None -> ())
|
||||
| _ -> ()
|
||||
) !jit_allowlist;
|
||||
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";
|
||||
] 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;
|
||||
(match Sx_vm.jit_compile_lambda l env.bindings with
|
||||
| Some cl -> l.l_compiled <- Some cl; incr count
|
||||
| None -> ())
|
||||
| _ -> ()
|
||||
) 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] ->
|
||||
|
||||
Reference in New Issue
Block a user