From f3e516feec49ca9ab127faea1a0e9a5a718a1b0d Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 28 Mar 2026 20:04:35 +0000 Subject: [PATCH] sx-http: CSSX source before components in defs, JIT closure bug identified Move client library sources (cssx.sx) before defcomp/defisland definitions in component-defs so defines are evaluated first. Identified root cause of CSSX "Not callable: nil" errors: JIT compiler captures free variable values at compile time instead of looking them up at runtime from vm_globals. When ~cssx/tw's JIT code calls cssx-process-token, it uses the compile-time snapshot (nil) instead of the runtime value (lambda). The function IS in global_env (type-of returns "lambda") but the JIT bytecode doesn't see it. Fix needed: JIT compiler should emit GLOBAL_GET instructions for free variables that reference vm_globals at runtime, not capture at compile. Co-Authored-By: Claude Opus 4.6 (1M context) --- hosts/ocaml/bin/sx_server.ml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index f2eb11b2..29a2698f 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -1653,8 +1653,24 @@ let read_css_file path = (** Pre-compute shell statics and inject into env as __shell-* vars. *) let http_inject_shell_statics env static_dir sx_sxc = - (* Component definitions for client *) + (* Component definitions for client. + Client library sources FIRST (CSSX etc.) so defines are available + before defcomp/defisland bodies that reference them. *) let buf = Buffer.create 65536 in + let project_dir = try Sys.getenv "SX_PROJECT_DIR" with Not_found -> + Filename.dirname (Filename.dirname static_dir) in + let templates_dir = project_dir ^ "/shared/sx/templates" in + let client_libs = [ + templates_dir ^ "/cssx.sx"; + ] in + List.iter (fun path -> + if Sys.file_exists path then begin + let src = In_channel.with_open_text path In_channel.input_all in + Buffer.add_string buf src; + Buffer.add_char buf '\n' + end + ) client_libs; + (* Then component/island definitions *) Hashtbl.iter (fun _sym v -> match v with | Component c -> @@ -1671,22 +1687,6 @@ let http_inject_shell_statics env static_dir sx_sxc = i.i_name ps (serialize_value i.i_body)) | _ -> () ) env.bindings; - (* Prepend client library source files — these define functions that - island components need at runtime (CSSX, signals, etc.). - Read directly from .sx files, same as Quart's _CLIENT_LIBRARY_SOURCES. *) - let project_dir = try Sys.getenv "SX_PROJECT_DIR" with Not_found -> - Filename.dirname (Filename.dirname static_dir) in - let templates_dir = project_dir ^ "/shared/sx/templates" in - let client_libs = [ - templates_dir ^ "/cssx.sx"; - ] in - List.iter (fun path -> - if Sys.file_exists path then begin - let src = In_channel.with_open_text path In_channel.input_all in - Buffer.add_string buf src; - Buffer.add_char buf '\n' - end - ) client_libs; let raw_defs = Buffer.contents buf in (* Component-defs are inlined in