From 9fc13efa1a8ed7379b04830661b53ea20383b5cd Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 28 Mar 2026 16:32:41 +0000 Subject: [PATCH] sx-http: JIT enabled, signals loaded, recursive dir loading, assoc fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable lazy JIT in HTTP mode — pre-compile 24 compiler functions at startup - Load spec/signals.sx + web/engine.sx for reactive primitives - Recursive directory loading for subdirectory components (geography/, etc.) - Re-bind native variadic assoc after stdlib.sx overwrites it - Skip test files, plans/, essays/ directories during HTTP load - Homepage aser: 21-38ms warm, Geography aser: 39-87ms warm Remaining: render-to-html JIT gets disabled by --- hosts/ocaml/bin/sx_server.ml | 89 ++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 13 deletions(-) diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index 5b671e50..6e9161d4 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -1701,29 +1701,41 @@ let http_mode port = let sx_sx = project_dir ^ "/sx/sx" in let t0 = Unix.gettimeofday () in (* Core spec + adapters. - Skip primitives.sx (declarative metadata — all prims are native in OCaml) - and types.sx (gradual type system — not needed for rendering). *) + Skip: primitives.sx (declarative metadata — all prims native in OCaml), + types.sx (gradual types — not needed for rendering), + evaluator.sx (SX-level CEK — native evaluator already compiled in). + The native CEK evaluator is faster — evaluator.sx adds a second SX-level + stepper that's 100x slower. *) let core_files = [ spec_base ^ "/parser.sx"; - spec_base ^ "/render.sx"; spec_base ^ "/evaluator.sx"; + spec_base ^ "/render.sx"; + spec_base ^ "/signals.sx"; + lib_base ^ "/compiler.sx"; web_base ^ "/adapter-html.sx"; web_base ^ "/adapter-sx.sx"; - web_base ^ "/web-forms.sx"; + web_base ^ "/web-forms.sx"; web_base ^ "/engine.sx"; ] in http_load_files env core_files; (* Libraries *) (* Files to skip — declarative metadata, not needed for rendering *) let skip_files = ["primitives.sx"; "types.sx"; "boundary.sx"; - "harness.sx"; "eval-rules.sx"] in - let load_dir dir = + "harness.sx"; "eval-rules.sx"; "vm-inline.sx"] in + let skip_dirs = ["tests"; "test"; "plans"; "essays"; "spec"] in + let rec load_dir dir = if Sys.file_exists dir && Sys.is_directory dir then begin - let files = Sys.readdir dir in - Array.sort String.compare files; + let entries = Sys.readdir dir in + Array.sort String.compare entries; Array.iter (fun f -> - if Filename.check_suffix f ".sx" - && not (List.mem f skip_files) - && not (Filename.check_suffix f ".test.sx") then - http_load_files env [dir ^ "/" ^ f] - ) files + let path = dir ^ "/" ^ f in + if Sys.is_directory path then begin + if not (List.mem f skip_dirs) then + load_dir path + end + else if Filename.check_suffix f ".sx" + && not (List.mem f skip_files) + && not (String.length f > 5 && String.sub f 0 5 = "test-") + && not (Filename.check_suffix f ".test.sx") then + http_load_files env [path] + ) entries end in load_dir lib_base; @@ -1731,6 +1743,57 @@ let http_mode port = load_dir sx_sx; let t1 = Unix.gettimeofday () in Printf.eprintf "[sx-http] All files loaded in %.3fs\n%!" (t1 -. t0); + (* Enable lazy JIT — compile lambdas to bytecode on first call *) + register_jit_hook env; + let jt0 = Unix.gettimeofday () in + let count = ref 0 in + 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-defisland"; "compile-defmacro"; + ] in + List.iter (fun name -> + try + match env_get env name with + | Lambda l -> + l.l_compiled <- Some Sx_vm.jit_failed_sentinel; + (match Sx_vm.jit_compile_lambda l (env_to_vm_globals env) with + | Some cl -> l.l_compiled <- Some cl; incr count + | None -> ()) + | _ -> () + with _ -> () + ) compiler_names; + let jt1 = Unix.gettimeofday () in + Printf.eprintf "[sx-http] JIT pre-compiled %d compiler fns in %.3fs\n%!" !count (jt1 -. jt0); + (* Re-bind native primitives that stdlib.sx may have overwritten with + narrower SX versions. The native assoc handles variadic key/value pairs + which evaluator.sx requires. *) + rebind_host_extensions env; + ignore (env_bind env "assoc" (NativeFn ("assoc", fun args -> + match args with + | Dict d :: rest -> + let d2 = Hashtbl.copy d in + let rec go = function + | [] -> Dict d2 + | String k :: v :: rest -> Hashtbl.replace d2 k v; go rest + | Keyword k :: v :: rest -> Hashtbl.replace d2 k v; go rest + | _ -> raise (Eval_error "assoc: pairs") + in go rest + | _ -> raise (Eval_error "assoc: dict + pairs")))); + (* Also re-bind highlight from SX lib if loaded *) + (try + let hl = env_get env "highlight" in + ignore hl (* already bound by lib/highlight.sx *) + with _ -> + (* Fallback: passthrough highlight *) + ignore (env_bind env "highlight" (NativeFn ("highlight", fun args -> + match args with + | String code :: _ -> SxExpr (Printf.sprintf "(pre :class \"text-sm overflow-x-auto\" (code \"%s\"))" (escape_sx_string code)) + | _ -> Nil)))); (* Inject shell statics *) http_inject_shell_statics env; (* Start TCP server *)