Native bytecode compilation in MCP: 108s → 1.9s (57x faster)
Replace Node.js compile-modules.js with direct Sx_compiler.compile_module calls in mcp_tree.ml. No subprocess, no JIT warm-up, no Node.js. 23 files compile in 1.9 seconds. Also includes rebuilt WASM kernel (iterative cek_run) and all 23 bytecode modules recompiled with native compiler. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -600,16 +600,90 @@ let rec handle_tool name args =
|
||||
let spec_dir = try Sys.getenv "SX_SPEC_DIR" with Not_found -> "spec" in
|
||||
Filename.dirname spec_dir
|
||||
in
|
||||
(* Use compile-modules.js which now delegates to native OCaml *)
|
||||
let cmd = Printf.sprintf "cd %s && node --input-type=commonjs hosts/ocaml/browser/compile-modules.js shared/static/wasm 2>&1" project_dir in
|
||||
let ic = Unix.open_process_in cmd in
|
||||
let lines = ref [] in
|
||||
(try while true do lines := input_line ic :: !lines done with End_of_file -> ());
|
||||
let status = Unix.close_process_in ic in
|
||||
let output = String.concat "\n" (List.rev !lines) in
|
||||
(match status with
|
||||
| Unix.WEXITED 0 -> text_result (Printf.sprintf "OK — bytecode compilation succeeded\n%s" (String.trim output))
|
||||
| _ -> error_result (Printf.sprintf "Bytecode compilation failed:\n%s" output))
|
||||
let sx_dir = project_dir ^ "/shared/static/wasm/sx" in
|
||||
let files = [
|
||||
"render.sx"; "core-signals.sx"; "signals.sx"; "deps.sx"; "router.sx";
|
||||
"page-helpers.sx"; "freeze.sx"; "bytecode.sx"; "compiler.sx"; "vm.sx";
|
||||
"dom.sx"; "browser.sx"; "adapter-html.sx"; "adapter-sx.sx"; "adapter-dom.sx";
|
||||
"boot-helpers.sx"; "hypersx.sx"; "harness.sx"; "harness-reactive.sx";
|
||||
"harness-web.sx"; "engine.sx"; "orchestration.sx"; "boot.sx";
|
||||
] in
|
||||
let t0 = Unix.gettimeofday () in
|
||||
(* JSON serialization for bytecode constants *)
|
||||
let rec const_to_json = function
|
||||
| Number n ->
|
||||
if Float.is_integer n then Printf.sprintf "{\"t\":\"n\",\"v\":%d}" (int_of_float n)
|
||||
else Printf.sprintf "{\"t\":\"n\",\"v\":%g}" n
|
||||
| String s -> Printf.sprintf "{\"t\":\"s\",\"v\":%s}" (json_escape s)
|
||||
| Symbol s -> Printf.sprintf "{\"t\":\"sym\",\"v\":%s}" (json_escape s)
|
||||
| Keyword k -> Printf.sprintf "{\"t\":\"kw\",\"v\":%s}" (json_escape k)
|
||||
| Bool true -> "{\"t\":\"b\",\"v\":true}"
|
||||
| Bool false -> "{\"t\":\"b\",\"v\":false}"
|
||||
| Nil -> "{\"t\":\"nil\"}"
|
||||
| Dict d when Hashtbl.mem d "bytecode" -> code_to_json (Dict d)
|
||||
| List items -> Printf.sprintf "{\"t\":\"list\",\"v\":[%s]}"
|
||||
(String.concat "," (List.map const_to_json items))
|
||||
| ListRef { contents = items } -> Printf.sprintf "{\"t\":\"list\",\"v\":[%s]}"
|
||||
(String.concat "," (List.map const_to_json items))
|
||||
| _ -> "{\"t\":\"nil\"}"
|
||||
and code_to_json code =
|
||||
let bc = match Sx_runtime.get code (String "bytecode") with
|
||||
| List l | ListRef { contents = l } ->
|
||||
String.concat "," (List.map (fun v -> match v with Number n -> string_of_int (int_of_float n) | _ -> "0") l)
|
||||
| _ -> "" in
|
||||
let consts = match Sx_runtime.get code (String "constants") with
|
||||
| List l | ListRef { contents = l } -> String.concat "," (List.map const_to_json l)
|
||||
| _ -> "" in
|
||||
Printf.sprintf "{\"t\":\"code\",\"v\":{\"bytecode\":[%s],\"constants\":[%s]}}" bc consts
|
||||
and json_escape s =
|
||||
let buf = Buffer.create (String.length s + 2) in
|
||||
Buffer.add_char buf '"';
|
||||
String.iter (fun c -> match c with
|
||||
| '"' -> Buffer.add_string buf "\\\"" | '\\' -> Buffer.add_string buf "\\\\"
|
||||
| '\n' -> Buffer.add_string buf "\\n" | '\r' -> Buffer.add_string buf "\\r"
|
||||
| '\t' -> Buffer.add_string buf "\\t"
|
||||
| c -> Buffer.add_char buf c) s;
|
||||
Buffer.add_char buf '"';
|
||||
Buffer.contents buf
|
||||
in
|
||||
let compiled = ref 0 in
|
||||
let skipped = ref 0 in
|
||||
let log = Buffer.create 1024 in
|
||||
List.iter (fun file ->
|
||||
let src_path = sx_dir ^ "/" ^ file in
|
||||
if Sys.file_exists src_path then begin
|
||||
try
|
||||
let src = In_channel.with_open_text src_path In_channel.input_all in
|
||||
let exprs = Sx_parser.parse_all src in
|
||||
let hash = Digest.string src |> Digest.to_hex |> fun s -> String.sub s 0 16 in
|
||||
let code = Sx_compiler.compile_module (List exprs) in
|
||||
(* Serialize to JSON *)
|
||||
let bc = match Sx_runtime.get code (String "bytecode") with
|
||||
| List l | ListRef { contents = l } ->
|
||||
String.concat "," (List.map (fun v -> match v with Number n -> string_of_int (int_of_float n) | _ -> "0") l)
|
||||
| _ -> "" in
|
||||
let consts = match Sx_runtime.get code (String "constants") with
|
||||
| List l | ListRef { contents = l } -> String.concat "," (List.map const_to_json l)
|
||||
| _ -> "" in
|
||||
let json = Printf.sprintf "{\"magic\":\"SXBC\",\"version\":1,\"hash\":\"%s\",\"module\":{\"bytecode\":[%s],\"constants\":[%s]}}"
|
||||
hash bc consts in
|
||||
let json_path = (String.sub src_path 0 (String.length src_path - 3)) ^ ".sxbc.json" in
|
||||
Out_channel.with_open_text json_path (fun oc -> output_string oc json);
|
||||
let kb = String.length json / 1024 in
|
||||
Buffer.add_string log (Printf.sprintf " ok %s → %dK\n" file kb);
|
||||
incr compiled
|
||||
with e ->
|
||||
Buffer.add_string log (Printf.sprintf " SKIP %s — %s\n" file (Printexc.to_string e));
|
||||
incr skipped
|
||||
end
|
||||
) files;
|
||||
let dt = Unix.gettimeofday () -. t0 in
|
||||
let summary = Printf.sprintf "Done: %d compiled, %d skipped in %.1fs\n%s"
|
||||
!compiled !skipped dt (Buffer.contents log) in
|
||||
if !skipped = 0 then
|
||||
text_result (Printf.sprintf "OK — bytecode compilation succeeded\n%s" summary)
|
||||
else
|
||||
text_result (Printf.sprintf "Bytecode compilation partial\n%s" summary)
|
||||
|
||||
| "sx_test" ->
|
||||
let host = args |> member "host" |> to_string_option |> Option.value ~default:"js" in
|
||||
|
||||
Reference in New Issue
Block a user