Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm] Option to implement OCaml strings with JavaScript strings #1772

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/build-wasm_of_ocaml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
- name: Set-up Node.js
uses: actions/setup-node@v4
with:
node-version: latest
node-version: 'v24.0.0-v8-canary202412116884e26428'

- name: Set-up OCaml ${{ matrix.ocaml-compiler }}
uses: ocaml/setup-ocaml@v3
Expand Down
55 changes: 45 additions & 10 deletions compiler/bin-wasm_of_ocaml/compile.ml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,35 @@ let with_runtime_files ~runtime_wasm_files f =
in
Wat_preprocess.with_preprocessed_files ~variables:[] ~inputs f

let build_runtime ~runtime_file =
(* Keep this variables in sync with gen/gen.ml *)
let variables = [ "use-js-string", Config.Flag.use_js_string () ] in
match
List.find_opt Runtime_files.precompiled_runtimes ~f:(fun (flags, _) ->
assert (
List.length flags = List.length variables
&& List.for_all2 ~f:(fun (k, _) (k', _) -> String.equal k k') flags variables);
Poly.equal flags variables)
with
| Some (_, contents) -> Fs.write_file ~name:runtime_file ~contents
| None ->
let inputs =
List.map
~f:(fun (module_name, contents) ->
{ Wat_preprocess.module_name
; file = module_name ^ ".wat"
; source = Contents contents
})
Runtime_files.wat_files
in
Runtime.build
~link_options:[ "-g" ]
~opt_options:[ "-g"; "-O2" ]
~variables:
(List.map ~f:(fun (k, v) : (_ * Wat_preprocess.value) -> k, Bool v) variables)
~inputs
~output_file:runtime_file

let link_and_optimize
~profile
~sourcemap_root
Expand All @@ -99,7 +128,7 @@ let link_and_optimize
let enable_source_maps = Option.is_some opt_sourcemap_file in
Fs.with_intermediate_file (Filename.temp_file "runtime" ".wasm")
@@ fun runtime_file ->
Fs.write_file ~name:runtime_file ~contents:Runtime_files.wasm_runtime;
build_runtime ~runtime_file;
Fs.with_intermediate_file (Filename.temp_file "wasm-merged" ".wasm")
@@ fun temp_file ->
opt_with
Expand Down Expand Up @@ -145,7 +174,7 @@ let link_and_optimize

let link_runtime ~profile runtime_wasm_files output_file =
if List.is_empty runtime_wasm_files
then Fs.write_file ~name:output_file ~contents:Runtime_files.wasm_runtime
then build_runtime ~runtime_file:output_file
else
Fs.with_intermediate_file (Filename.temp_file "extra_runtime" ".wasm")
@@ fun extra_runtime ->
Expand All @@ -167,7 +196,7 @@ let link_runtime ~profile runtime_wasm_files output_file =
();
Fs.with_intermediate_file (Filename.temp_file "runtime" ".wasm")
@@ fun runtime_file ->
Fs.write_file ~name:runtime_file ~contents:Runtime_files.wasm_runtime;
build_runtime ~runtime_file;
Binaryen.link
~opt_output_sourcemap:None
~inputs:
Expand All @@ -191,25 +220,25 @@ let generate_prelude ~out_file =
in
let context = Generate.start () in
let debug = Parse_bytecode.Debug.create ~include_cmis:false false in
let _ =
let _, generated_js =
Generate.f
~context
~unit_name:(Some "prelude")
~unit_name:(Some "wasmoo_prelude")
~live_vars:variable_uses
~in_cps
~deadcode_sentinal
~debug
program
in
Generate.output ch ~context;
uinfo.provides
uinfo.provides, generated_js

let build_prelude z =
Fs.with_intermediate_file (Filename.temp_file "prelude" ".wasm")
@@ fun prelude_file ->
Fs.with_intermediate_file (Filename.temp_file "prelude_file" ".wasm")
@@ fun tmp_prelude_file ->
let predefined_exceptions = generate_prelude ~out_file:prelude_file in
let info = generate_prelude ~out_file:prelude_file in
Binaryen.optimize
~profile:(Driver.profile 1)
~input_file:prelude_file
Expand All @@ -218,7 +247,7 @@ let build_prelude z =
~opt_output_sourcemap:None
();
Zip.add_file z ~name:"prelude.wasm" ~file:tmp_prelude_file;
predefined_exceptions
info

let build_js_runtime ~primitives ?runtime_arguments () =
let always_required_js, primitives =
Expand Down Expand Up @@ -396,12 +425,18 @@ let run
let z = Zip.open_out tmp_output_file in
Zip.add_file z ~name:"runtime.wasm" ~file:tmp_wasm_file;
Zip.add_entry z ~name:"runtime.js" ~contents:js_runtime;
let predefined_exceptions = build_prelude z in
let predefined_exceptions, (strings, fragments) = build_prelude z in
Link.add_info
z
~predefined_exceptions
~build_info:(Build_info.create `Runtime)
~unit_data:[]
~unit_data:
[ { Link.unit_name = "wasmoo_prelude"
; unit_info = Unit_info.empty
; strings
; fragments
}
]
();
Zip.close_out z)
else
Expand Down
5 changes: 3 additions & 2 deletions compiler/bin-wasm_of_ocaml/dune
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@
(target runtime_files.ml)
(deps
gen/gen.exe
../../runtime/wasm/runtime.wasm
../../runtime/wasm/runtime.js
../../runtime/wasm/deps.json)
../../runtime/wasm/deps.json
(glob_files ../../runtime/wasm/*.wat)
(glob_files ../../runtime/wasm/runtime-*.wasm))
(action
(with-stdout-to
%{target}
Expand Down
56 changes: 52 additions & 4 deletions compiler/bin-wasm_of_ocaml/gen/gen.ml
Original file line number Diff line number Diff line change
@@ -1,13 +1,61 @@
let read_file ic = really_input_string ic (in_channel_length ic)

(* Keep the two variables below in sync with function build_runtime in
../compile.ml *)

let default_flags = []

let interesting_runtimes = [ [ "use-js-string", false ]; [ "use-js-string", true ] ]

let name_runtime l =
let flags = List.filter_map (fun (k, v) -> if v then Some k else None) l in
String.concat "-" ("runtime" :: (if flags = [] then [ "standard" ] else flags))
^ ".wasm"

let print_flags f flags =
Format.fprintf
f
"@[<2>[ %a ]@]"
(Format.pp_print_list
~pp_sep:(fun f () -> Format.fprintf f ";@ ")
(fun f (k, v) ->
Format.fprintf f "@[\"%s\",@ %s@]" k (if v then "true" else "false")))
flags

let () =
let () = set_binary_mode_out stdout true in
Format.printf
"let wasm_runtime = \"%s\"@."
"let js_runtime = \"%s\"@."
(String.escaped (read_file (open_in_bin Sys.argv.(1))));
Format.printf
"let js_runtime = \"%s\"@."
"let dependencies = \"%s\"@."
(String.escaped (read_file (open_in_bin Sys.argv.(2))));
let wat_files, runtimes =
List.partition
(fun f -> Filename.check_suffix f ".wat")
(Array.to_list (Array.sub Sys.argv 3 (Array.length Sys.argv - 3)))
in
Format.printf
"let dependencies = \"%s\"@."
(String.escaped (read_file (open_in_bin Sys.argv.(3))))
"let wat_files = [%a]@."
(Format.pp_print_list (fun f file ->
Format.fprintf
f
"\"%s\", \"%s\"; "
Filename.(chop_suffix (basename file) ".wat")
(String.escaped (read_file (open_in_bin file)))))
wat_files;
Format.printf
"let precompiled_runtimes = [%a]@."
(Format.pp_print_list (fun f flags ->
let flags = flags @ default_flags in
let name = name_runtime flags in
match List.find_opt (fun file -> Filename.basename file = name) runtimes with
| None -> failwith ("Missing runtime " ^ name)
| Some file ->
Format.fprintf
f
"%a, \"%s\"; "
print_flags
flags
(String.escaped (read_file (open_in_bin file)))))
interesting_runtimes
3 changes: 2 additions & 1 deletion compiler/lib-wasm/code_generation.ml
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ let rec is_smi e =
| RefNull _
| Br_on_cast _
| Br_on_cast_fail _
| Try _ -> false
| Try _
| ExternConvertAny _ -> false
| BinOp ((F32 _ | F64 _), _, _) | RefTest _ | RefEq _ -> true
| IfExpr (_, _, ift, iff) -> is_smi ift && is_smi iff

Expand Down
Loading
Loading