WIP: bytecode module pre-compilation and loading infrastructure
- compile-modules.js: Node.js build tool, all 23 .sx files compile to .sxbc.json
- api_load_module with shared globals (beginModuleLoad/endModuleLoad batch API)
- api_compile_module for runtime compilation
- sx-platform.js: bytecode-first loader with source fallback, JSON deserializer
- Deferred JIT enable (setTimeout after boot)
Known issues:
- WASM browser: loadModule loads but functions not accessible (env writeback
issue with interned keys)
- WASM browser: compileModule fails ("Not callable: nil" — compile-module
function from bytecode not working correctly in WASM context)
- Node.js js_of_ocaml: full roundtrip works (compile → load → call)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -231,17 +231,46 @@ let api_load src_js =
|
||||
| Eval_error msg -> Js.Unsafe.inject (Js.string ("Error: " ^ msg))
|
||||
| Parse_error msg -> Js.Unsafe.inject (Js.string ("Parse error: " ^ msg))
|
||||
|
||||
(* Shared globals table for batch module loading.
|
||||
Created by beginModuleLoad, accumulated across loadModule calls,
|
||||
flushed to env by endModuleLoad. Ensures closures from early
|
||||
modules can see definitions from later modules. *)
|
||||
let _module_globals : (string, value) Hashtbl.t option ref = ref None
|
||||
|
||||
let api_begin_module_load () =
|
||||
let g = Hashtbl.create 512 in
|
||||
Hashtbl.iter (fun id v -> Hashtbl.replace g (unintern id) v) global_env.bindings;
|
||||
_module_globals := Some g;
|
||||
Js.Unsafe.inject true
|
||||
|
||||
let api_end_module_load () =
|
||||
(match !_module_globals with
|
||||
| Some g ->
|
||||
Hashtbl.iter (fun k v ->
|
||||
Hashtbl.replace global_env.bindings (intern k) v
|
||||
) g;
|
||||
_module_globals := None
|
||||
| None -> ());
|
||||
Js.Unsafe.inject true
|
||||
|
||||
let api_load_module module_js =
|
||||
try
|
||||
let code_val = js_to_value module_js in
|
||||
let code = Sx_vm.code_from_value code_val in
|
||||
let globals = Hashtbl.create 256 in
|
||||
Hashtbl.iter (fun id v -> Hashtbl.replace globals (unintern id) v) global_env.bindings;
|
||||
let globals = match !_module_globals with
|
||||
| Some g -> g (* use shared table *)
|
||||
| None ->
|
||||
(* standalone mode: create temp table *)
|
||||
let g = Hashtbl.create 256 in
|
||||
Hashtbl.iter (fun id v -> Hashtbl.replace g (unintern id) v) global_env.bindings;
|
||||
g
|
||||
in
|
||||
let _result = Sx_vm.execute_module code globals in
|
||||
(* Copy all globals back into env — new defines + unchanged values *)
|
||||
Hashtbl.iter (fun k v ->
|
||||
Hashtbl.replace global_env.bindings (intern k) v
|
||||
) globals;
|
||||
(* If standalone (no batch), copy back immediately *)
|
||||
if !_module_globals = None then
|
||||
Hashtbl.iter (fun k v ->
|
||||
Hashtbl.replace global_env.bindings (intern k) v
|
||||
) globals;
|
||||
Js.Unsafe.inject (Hashtbl.length globals)
|
||||
with
|
||||
| Eval_error msg -> Js.Unsafe.inject (Js.string ("Error: " ^ msg))
|
||||
@@ -653,6 +682,8 @@ let () =
|
||||
Js.Unsafe.set sx (Js.string "renderToHtml") (Js.wrap_callback api_render_to_html);
|
||||
Js.Unsafe.set sx (Js.string "load") (Js.wrap_callback api_load);
|
||||
Js.Unsafe.set sx (Js.string "loadModule") (Js.wrap_callback api_load_module);
|
||||
Js.Unsafe.set sx (Js.string "beginModuleLoad") (Js.wrap_callback (fun () -> api_begin_module_load ()));
|
||||
Js.Unsafe.set sx (Js.string "endModuleLoad") (Js.wrap_callback (fun () -> api_end_module_load ()));
|
||||
Js.Unsafe.set sx (Js.string "compileModule") (wrap api_compile_module);
|
||||
Js.Unsafe.set sx (Js.string "typeOf") (Js.wrap_callback api_type_of);
|
||||
Js.Unsafe.set sx (Js.string "inspect") (Js.wrap_callback api_inspect);
|
||||
|
||||
Reference in New Issue
Block a user