JIT: use live globals, don't copy — fixes CSSX Not callable: nil
jit_compile_lambda now uses the live globals table directly instead of Hashtbl.copy. Closure bindings that aren't already in globals are injected into the live table. This ensures GLOBAL_GET always sees the latest define values. Previously: Hashtbl.copy created a stale snapshot. Functions defined after the copy (like cssx-process-token from cssx.sx) resolved to nil in JIT-compiled closures. JIT error test now passes — 0 CSSX errors during navigation. 7/8 navigation tests pass. Remaining: back button content update. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -580,23 +580,27 @@ let jit_compile_lambda (l : lambda) globals =
|
||||
so the VM can find them via GLOBAL_GET. The compiler doesn't know
|
||||
about the enclosing scope, so closure vars get compiled as globals. *)
|
||||
let effective_globals =
|
||||
(* Use the LIVE globals table directly. Inject only truly local
|
||||
closure bindings (not already in globals) into the live table.
|
||||
This ensures GLOBAL_GET always sees the latest define values.
|
||||
Previous approach copied globals, creating a stale snapshot. *)
|
||||
let closure = l.l_closure in
|
||||
if Hashtbl.length closure.bindings = 0 && closure.parent = None then
|
||||
globals (* no closure vars — use globals directly *)
|
||||
else begin
|
||||
(* Merge: closure bindings layered on top of globals.
|
||||
Use a shallow copy so we don't pollute the real globals. *)
|
||||
let merged = Hashtbl.copy globals in
|
||||
let rec inject env =
|
||||
Hashtbl.iter (fun id v -> Hashtbl.replace merged (Sx_types.unintern id) v) env.bindings;
|
||||
match env.parent with Some p -> inject p | None -> ()
|
||||
in
|
||||
let count = ref 0 in
|
||||
let rec inject env =
|
||||
Hashtbl.iter (fun id v ->
|
||||
let name = Sx_types.unintern id in
|
||||
if not (Hashtbl.mem globals name) then begin
|
||||
Hashtbl.replace globals name v;
|
||||
incr count
|
||||
end
|
||||
) env.bindings;
|
||||
match env.parent with Some p -> inject p | None -> ()
|
||||
in
|
||||
if Hashtbl.length closure.bindings > 0 || closure.parent <> None then
|
||||
inject closure;
|
||||
let n = Hashtbl.length merged - Hashtbl.length globals in
|
||||
if n > 0 then
|
||||
Printf.eprintf "[jit] %s: injected %d closure bindings\n%!" fn_name n;
|
||||
merged
|
||||
end
|
||||
if !count > 0 then
|
||||
Printf.eprintf "[jit] %s: injected %d closure bindings\n%!" fn_name !count;
|
||||
globals
|
||||
in
|
||||
(match result with
|
||||
| Dict d when Hashtbl.mem d "bytecode" ->
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user