diff --git a/.github/workflows/build-wasm_of_ocaml.yml b/.github/workflows/build-wasm_of_ocaml.yml index 877b34ca4f..177556089b 100644 --- a/.github/workflows/build-wasm_of_ocaml.yml +++ b/.github/workflows/build-wasm_of_ocaml.yml @@ -46,7 +46,7 @@ jobs: - name: Install node uses: actions/setup-node@v4 with: - node-version: 23 + node-version: 'v24.0.0-v8-canary202412116884e26428' - name: Install OCaml ${{ matrix.ocaml-compiler }} uses: ocaml/setup-ocaml@v3 diff --git a/compiler/bin-wasm_of_ocaml/compile.ml b/compiler/bin-wasm_of_ocaml/compile.ml index 9957756643..c51850c03b 100644 --- a/compiler/bin-wasm_of_ocaml/compile.ml +++ b/compiler/bin-wasm_of_ocaml/compile.ml @@ -73,6 +73,32 @@ let output_gen output_file f = Code.Var.set_stable (Config.Flag.stable_var ()); Filename.gen_file output_file f +let build_runtime ~runtime_file = + let variables = [ "use-js-string", Config.Flag.use_js_string () ] in + List.fold_left + ~f:(fun cont (name, contents) -> + fun inputs -> + Fs.with_intermediate_file (Filename.temp_file name ".wat") + @@ fun filename -> + Fs.write_file + ~name:filename + ~contents:(Wat_preprocess.f ~variables ~filename ~contents); + cont ((filename, name) :: inputs)) + ~init:(fun inputs -> + Fs.with_intermediate_file (Filename.temp_file "runtime-merged" ".wasm") + @@ fun merge_file -> + Binaryen.link ~opt_output_sourcemap:None ~inputs ~output_file:merge_file; + Binaryen.optimize + ~profile:None + ~options:[ "-O2" ] + ~opt_input_sourcemap:None + ~input_file:merge_file + ~opt_output_sourcemap:None + ~output_file:runtime_file + ()) + Runtime_files.wat_files + [] + let link_and_optimize ~profile ~sourcemap_root @@ -91,7 +117,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:Wa_runtime.wasm_runtime; + build_runtime ~runtime_file; Fs.with_intermediate_file (Filename.temp_file "wasm-merged" ".wasm") @@ fun temp_file -> opt_with @@ -101,8 +127,9 @@ let link_and_optimize else None) @@ fun opt_temp_sourcemap -> Binaryen.link - ~runtime_files:(runtime_file :: runtime_wasm_files) - ~input_files:wat_files + ~inputs: + (List.map ~f:(fun f -> f, "env") (runtime_file :: runtime_wasm_files) + @ List.map ~f:(fun f -> f, "OCaml") wat_files) ~opt_output_sourcemap:opt_temp_sourcemap ~output_file:temp_file; Fs.with_intermediate_file (Filename.temp_file "wasm-dce" ".wasm") @@ -113,7 +140,7 @@ let link_and_optimize @@ fun opt_temp_sourcemap' -> let primitives = Binaryen.dead_code_elimination - ~dependencies:Wa_runtime.dependencies + ~dependencies:Runtime_files.dependencies ~opt_input_sourcemap:opt_temp_sourcemap ~opt_output_sourcemap:opt_temp_sourcemap' ~input_file:temp_file @@ -124,7 +151,8 @@ let link_and_optimize ~opt_input_sourcemap:opt_temp_sourcemap' ~opt_output_sourcemap:opt_sourcemap ~input_file:temp_file' - ~output_file; + ~output_file + (); Option.iter ~f:(update_sourcemap ~sourcemap_root ~sourcemap_don't_inline_content) opt_sourcemap_file; @@ -133,13 +161,12 @@ let link_and_optimize 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:Wa_runtime.wasm_runtime; + build_runtime ~runtime_file; Fs.with_intermediate_file (Filename.temp_file "wasm-merged" ".wasm") @@ fun temp_file -> Binaryen.link + ~inputs:(List.map ~f:(fun f -> f, "env") (runtime_file :: runtime_wasm_files)) ~opt_output_sourcemap:None - ~runtime_files:(runtime_file :: runtime_wasm_files) - ~input_files:[] ~output_file:temp_file; Binaryen.optimize ~profile @@ -147,6 +174,7 @@ let link_runtime ~profile runtime_wasm_files output_file = ~opt_output_sourcemap:None ~input_file:temp_file ~output_file + () let generate_prelude ~out_file = Filename.gen_file out_file @@ -162,10 +190,10 @@ 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 @@ -173,22 +201,23 @@ let generate_prelude ~out_file = 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 ~output_file:tmp_prelude_file ~opt_input_sourcemap:None - ~opt_output_sourcemap:None; + ~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 = @@ -216,7 +245,7 @@ let build_js_runtime ~primitives ?runtime_arguments () = in let prelude = Link.output_js always_required_js in let init_fun = - match Parse_js.parse (Parse_js.Lexer.of_string Wa_runtime.js_runtime) with + match Parse_js.parse (Parse_js.Lexer.of_string Runtime_files.js_runtime) with | [ (Expression_statement f, _) ] -> f | _ -> assert false in @@ -364,12 +393,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 @@ -411,7 +446,8 @@ let run ~opt_input_sourcemap:None ~opt_output_sourcemap:opt_tmp_map_file ~input_file:wat_file - ~output_file:tmp_wasm_file; + ~output_file:tmp_wasm_file + (); { Link.unit_name; unit_info; strings; fragments } in cont unit_data unit_name tmp_wasm_file opt_tmp_map_file diff --git a/compiler/bin-wasm_of_ocaml/dune b/compiler/bin-wasm_of_ocaml/dune index cd5f1a468a..d80668bbd9 100644 --- a/compiler/bin-wasm_of_ocaml/dune +++ b/compiler/bin-wasm_of_ocaml/dune @@ -22,12 +22,12 @@ (:standard -safe-string))) (rule - (target wa_runtime.ml) + (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)) (action (with-stdout-to %{target} diff --git a/compiler/bin-wasm_of_ocaml/gen/gen.ml b/compiler/bin-wasm_of_ocaml/gen/gen.ml index b7a20c4e3e..a0b8f68e88 100644 --- a/compiler/bin-wasm_of_ocaml/gen/gen.ml +++ b/compiler/bin-wasm_of_ocaml/gen/gen.ml @@ -3,11 +3,18 @@ let read_file ic = really_input_string ic (in_channel_length ic) 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 a = 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))))) + (Array.to_list a) diff --git a/compiler/lib-wasm/binaryen.ml b/compiler/lib-wasm/binaryen.ml index 93b0b7b7fb..eded3b43e3 100644 --- a/compiler/lib-wasm/binaryen.ml +++ b/compiler/lib-wasm/binaryen.ml @@ -45,18 +45,12 @@ let opt_flag flag v = | None -> [] | Some v -> [ flag; Filename.quote v ] -let link ~runtime_files ~input_files ~opt_output_sourcemap ~output_file = +let link ~inputs ~opt_output_sourcemap ~output_file = command ("wasm-merge" :: (common_options () @ List.flatten - (List.map - ~f:(fun runtime_file -> [ Filename.quote runtime_file; "env" ]) - runtime_files) - @ List.flatten - (List.map - ~f:(fun input_file -> [ Filename.quote input_file; "OCaml" ]) - input_files) + (List.map ~f:(fun (file, name) -> [ Filename.quote file; name ]) inputs) @ [ "-o"; Filename.quote output_file ] @ opt_flag "--output-source-map" opt_output_sourcemap)) @@ -114,8 +108,14 @@ let optimization_options = ; [ "-O3"; "--skip-pass=inlining-optimizing"; "--traps-never-happen" ] |] -let optimize ~profile ~opt_input_sourcemap ~input_file ~opt_output_sourcemap ~output_file - = +let optimize + ~profile + ?options + ~opt_input_sourcemap + ~input_file + ~opt_output_sourcemap + ~output_file + () = let level = match profile with | None -> 1 @@ -124,7 +124,7 @@ let optimize ~profile ~opt_input_sourcemap ~input_file ~opt_output_sourcemap ~ou command ("wasm-opt" :: (common_options () - @ optimization_options.(level - 1) + @ Option.value ~default:optimization_options.(level - 1) options @ [ Filename.quote input_file; "-o"; Filename.quote output_file ]) @ opt_flag "--input-source-map" opt_input_sourcemap @ opt_flag "--output-source-map" opt_output_sourcemap) diff --git a/compiler/lib-wasm/binaryen.mli b/compiler/lib-wasm/binaryen.mli index 3e07e06f88..addfef39c9 100644 --- a/compiler/lib-wasm/binaryen.mli +++ b/compiler/lib-wasm/binaryen.mli @@ -17,8 +17,7 @@ *) val link : - runtime_files:string list - -> input_files:string list + inputs:(string * string (*file, module name*)) list -> opt_output_sourcemap:string option -> output_file:string -> unit @@ -33,8 +32,10 @@ val dead_code_elimination : val optimize : profile:Driver.profile option + -> ?options:string list -> opt_input_sourcemap:string option -> input_file:string -> opt_output_sourcemap:string option -> output_file:string -> unit + -> unit diff --git a/compiler/lib-wasm/code_generation.ml b/compiler/lib-wasm/code_generation.ml index cd23a3db7e..03f279eb6b 100644 --- a/compiler/lib-wasm/code_generation.ml +++ b/compiler/lib-wasm/code_generation.ml @@ -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 diff --git a/compiler/lib-wasm/dune b/compiler/lib-wasm/dune index 2a54c9316f..90e6dcddee 100644 --- a/compiler/lib-wasm/dune +++ b/compiler/lib-wasm/dune @@ -4,4 +4,6 @@ (synopsis "Wasm_of_ocaml compiler library") (libraries js_of_ocaml_compiler) (flags - (:standard -w -7-37 -safe-string -open Js_of_ocaml_compiler))) + (:standard -w -7-37 -safe-string -open Js_of_ocaml_compiler)) + (preprocess + (pps sedlex.ppx))) diff --git a/compiler/lib-wasm/gc_target.ml b/compiler/lib-wasm/gc_target.ml index f2e6b7eccd..42af3722b2 100644 --- a/compiler/lib-wasm/gc_target.ml +++ b/compiler/lib-wasm/gc_target.ml @@ -35,14 +35,31 @@ module Type = struct ; typ = W.Array { mut = true; typ = Value value } }) - let string_type = - register_type "string" (fun () -> + let bytes_type = + register_type "bytes" (fun () -> return { supertype = None ; final = true ; typ = W.Array { mut = true; typ = Packed I8 } }) + let string_type = + register_type "string" (fun () -> + return + (if Config.Flag.use_js_string () + then + { supertype = None + ; final = true + ; typ = + W.Struct + [ { mut = false; typ = Value (Ref { nullable = true; typ = Any }) } ] + } + else + { supertype = None + ; final = true + ; typ = W.Array { mut = true; typ = Packed I8 } + })) + let float_type = register_type "float" (fun () -> return @@ -121,7 +138,7 @@ module Type = struct let custom_operations_type = register_type "custom_operations" (fun () -> - let* string = string_type in + let* bytes = bytes_type in let* compare = compare_type in let* hash = hash_type in let* fixed_length = fixed_length_type in @@ -134,7 +151,7 @@ module Type = struct ; typ = W.Struct [ { mut = false - ; typ = Value (Ref { nullable = false; typ = Type string }) + ; typ = Value (Ref { nullable = false; typ = Type bytes }) } ; { mut = false ; typ = Value (Ref { nullable = true; typ = Type compare }) @@ -513,7 +530,8 @@ module Value = struct | ArrayLen e' | StructGet (_, _, _, e') | RefCast (_, e') - | RefTest (_, e') -> effect_free e' + | RefTest (_, e') + | ExternConvertAny e' -> effect_free e' | BinOp (_, e1, e2) | ArrayNew (_, e1, e2) | ArrayNewData (_, _, e1, e2) @@ -793,15 +811,50 @@ module Memory = struct wasm_array_set ~ty:Type.float_array_type (load a) (load i) (unbox_float (load v))) let bytes_length e = - let* ty = Type.string_type in + let* ty = Type.bytes_type in let* e = wasm_cast ty e in return (W.ArrayLen e) let bytes_get e e' = - Value.val_int (wasm_array_get ~ty:Type.string_type e (Value.int_val e')) + Value.val_int (wasm_array_get ~ty:Type.bytes_type e (Value.int_val e')) let bytes_set e e' e'' = - wasm_array_set ~ty:Type.string_type e (Value.int_val e') (Value.int_val e'') + wasm_array_set ~ty:Type.bytes_type e (Value.int_val e') (Value.int_val e'') + + let string_value e = + let* string = Type.string_type in + let* e = wasm_struct_get string (wasm_cast string e) 0 in + return (W.ExternConvertAny e) + + let string_length e = + if Config.Flag.use_js_string () + then + let* f = + register_import + ~import_module:"wasm:js-string" + ~name:"length" + (Fun { W.params = [ Ref { nullable = true; typ = Extern } ]; result = [ I32 ] }) + in + let* e = string_value e in + return (W.Call (f, [ e ])) + else bytes_length e + + let string_get e e' = + if Config.Flag.use_js_string () + then + let* f = + register_import + ~import_module:"wasm:js-string" + ~name:"charCodeAt" + (Fun + { W.params = [ Ref { nullable = true; typ = Extern }; I32 ] + ; result = [ I32 ] + }) + in + let* e = string_value e in + let* e' = Value.int_val e' in + Value.val_int (return (W.Call (f, [ e; e' ]))) + else bytes_get e e' let field e idx = wasm_array_get e (Arith.const (Int32.of_int (idx + 1))) @@ -928,6 +981,21 @@ module Constant = struct | Const_named of string | Mutated + let translate_js_string s = + let* i = register_string s in + let* x = + let* name = unit_name in + register_import + ~import_module: + (match name with + | None -> "strings" + | Some name -> name ^ ".strings") + ~name:(string_of_int i) + (Global { mut = false; typ = Ref { nullable = false; typ = Any } }) + in + let* ty = Type.js_type in + return (Const_named ("str_" ^ s), W.StructNew (ty, [ GlobalGet x ])) + let rec translate_rec c = match c with | Code.Int i -> return (Const, W.RefI31 (Const (I32 (Targetint.to_int32 i)))) @@ -986,38 +1054,29 @@ module Constant = struct | Utf (Utf8 s) -> str_js_utf8 s | Byte s -> str_js_byte s in - let* i = register_string s in - let* x = - let* name = unit_name in - register_import - ~import_module: - (match name with - | None -> "strings" - | Some name -> name ^ ".strings") - ~name:(string_of_int i) - (Global { mut = false; typ = Ref { nullable = false; typ = Any } }) - in - let* ty = Type.js_type in - return (Const_named ("str_" ^ s), W.StructNew (ty, [ GlobalGet x ])) + translate_js_string s | String s -> - let* ty = Type.string_type in - if String.length s >= string_length_threshold - then - let name = Code.Var.fresh_n "string" in - let* () = register_data_segment name s in - return - ( Mutated - , W.ArrayNewData - (ty, name, Const (I32 0l), Const (I32 (Int32.of_int (String.length s)))) - ) + if Config.Flag.use_js_string () + then translate_js_string (str_js_byte s) else - let l = - String.fold_right - ~f:(fun c r -> W.Const (I32 (Int32.of_int (Char.code c))) :: r) - s - ~init:[] - in - return (Const_named ("str_" ^ s), W.ArrayNewFixed (ty, l)) + let* ty = Type.string_type in + if String.length s >= string_length_threshold + then + let name = Code.Var.fresh_n "string" in + let* () = register_data_segment name s in + return + ( Mutated + , W.ArrayNewData + (ty, name, Const (I32 0l), Const (I32 (Int32.of_int (String.length s)))) + ) + else + let l = + String.fold_right + ~f:(fun c r -> W.Const (I32 (Int32.of_int (Char.code c))) :: r) + s + ~init:[] + in + return (Const_named ("str_" ^ s), W.ArrayNewFixed (ty, l)) | Float f -> let* ty = Type.float_type in return (Const, W.StructNew (ty, [ Const (F64 f) ])) diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index d5e590dff2..803c41f91e 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -285,22 +285,29 @@ module Generate (Target : Target_sig.S) = struct seq (Memory.array_set x y z) Value.unit | Extern "caml_floatarray_unsafe_set", [ x; y; z ] -> seq (Memory.float_array_set x y z) Value.unit - | Extern ("caml_string_unsafe_get" | "caml_bytes_unsafe_get"), [ x; y ] -> - Memory.bytes_get x y - | Extern ("caml_string_unsafe_set" | "caml_bytes_unsafe_set"), [ x; y; z ] -> + | Extern "caml_string_unsafe_get", [ x; y ] -> Memory.string_get x y + | Extern "caml_bytes_unsafe_get", [ x; y ] -> Memory.bytes_get x y + | Extern "caml_bytes_unsafe_set", [ x; y; z ] -> seq (Memory.bytes_set x y z) Value.unit - | Extern ("caml_string_get" | "caml_bytes_get"), [ x; y ] -> + | Extern "caml_string_get", [ x; y ] -> + seq + (let* cond = Arith.uge (Value.int_val y) (Memory.string_length x) in + instr (W.Br_if (label_index context bound_error_pc, cond))) + (Memory.string_get x y) + | Extern "caml_bytes_get", [ x; y ] -> seq (let* cond = Arith.uge (Value.int_val y) (Memory.bytes_length x) in instr (W.Br_if (label_index context bound_error_pc, cond))) (Memory.bytes_get x y) - | Extern ("caml_string_set" | "caml_bytes_set"), [ x; y; z ] -> + | Extern "caml_bytes_set", [ x; y; z ] -> seq (let* cond = Arith.uge (Value.int_val y) (Memory.bytes_length x) in let* () = instr (W.Br_if (label_index context bound_error_pc, cond)) in Memory.bytes_set x y z) Value.unit - | Extern ("caml_ml_string_length" | "caml_ml_bytes_length"), [ x ] -> + | Extern "caml_ml_string_length", [ x ] -> + Value.val_int (Memory.string_length x) + | Extern "caml_ml_bytes_length", [ x ] -> Value.val_int (Memory.bytes_length x) | Extern "%int_add", [ x; y ] -> Value.int_add x y | Extern "%int_sub", [ x; y ] -> Value.int_sub x y @@ -776,7 +783,6 @@ module Generate (Target : Target_sig.S) = struct ( Extern ( "caml_string_get" | "caml_bytes_get" - | "caml_string_set" | "caml_bytes_set" | "caml_check_bound" | "caml_check_bound_gen" diff --git a/compiler/lib-wasm/initialize_locals.ml b/compiler/lib-wasm/initialize_locals.ml index 5e15235725..c4ecfe8c4e 100644 --- a/compiler/lib-wasm/initialize_locals.ml +++ b/compiler/lib-wasm/initialize_locals.ml @@ -46,7 +46,8 @@ let rec scan_expression ctx e = | RefCast (_, e') | RefTest (_, e') | Br_on_cast (_, _, _, e') - | Br_on_cast_fail (_, _, _, e') -> scan_expression ctx e' + | Br_on_cast_fail (_, _, _, e') + | ExternConvertAny e' -> scan_expression ctx e' | BinOp (_, e', e'') | ArrayNew (_, e', e'') | ArrayNewData (_, _, e', e'') diff --git a/compiler/lib-wasm/link.ml b/compiler/lib-wasm/link.ml index d043d0833e..fd8b574eb3 100644 --- a/compiler/lib-wasm/link.ml +++ b/compiler/lib-wasm/link.ml @@ -388,7 +388,7 @@ let generate_start_function ~to_link ~out_file = Filename.gen_file out_file @@ fun ch -> let context = Generate.start () in - Generate.add_init_function ~context ~to_link:("prelude" :: to_link); + Generate.add_init_function ~context ~to_link:("wasmoo_prelude" :: to_link); Generate.wasm_output ch ~context; if times () then Format.eprintf " generate start: %a@." Timer.print t1 @@ -669,11 +669,11 @@ let load_information files = match files with | [] -> assert false | runtime :: other_files -> - let build_info, predefined_exceptions, _unit_data = + let build_info, predefined_exceptions, unit_data = Zip.with_open_in runtime read_info in ( predefined_exceptions - , (runtime, (build_info, [])) + , (runtime, (build_info, unit_data)) :: List.map other_files ~f:(fun file -> let build_info, _predefined_exceptions, unit_data = Zip.with_open_in file read_info @@ -775,7 +775,8 @@ let link ~output_file ~linkall ~enable_source_maps ~files = || cmo_file || linkall || unit_info.force_link - || not (StringSet.is_empty (StringSet.inter requires unit_info.provides)) + || (not (StringSet.is_empty (StringSet.inter requires unit_info.provides))) + || String.equal unit_name "wasmoo_prelude" then ( StringSet.diff (StringSet.union unit_info.requires requires) diff --git a/compiler/lib-wasm/target_sig.ml b/compiler/lib-wasm/target_sig.ml index 227da6d972..16c05164c0 100644 --- a/compiler/lib-wasm/target_sig.ml +++ b/compiler/lib-wasm/target_sig.ml @@ -77,6 +77,10 @@ module type S = sig val bytes_set : expression -> expression -> expression -> unit Code_generation.t + val string_length : expression -> expression + + val string_get : expression -> expression -> expression + val box_float : expression -> expression val unbox_float : expression -> expression diff --git a/compiler/lib-wasm/wasm_ast.ml b/compiler/lib-wasm/wasm_ast.ml index a23addc4a2..9ca66d6578 100644 --- a/compiler/lib-wasm/wasm_ast.ml +++ b/compiler/lib-wasm/wasm_ast.ml @@ -166,6 +166,7 @@ type expression = | Br_on_cast_fail of int * ref_type * ref_type * expression | IfExpr of value_type * expression * expression * expression | Try of func_type * instruction list * (var * int * value_type) list + | ExternConvertAny of expression and instruction = | Drop of expression diff --git a/compiler/lib-wasm/wasm_output.ml b/compiler/lib-wasm/wasm_output.ml index febd2c650e..78f38b9ac0 100644 --- a/compiler/lib-wasm/wasm_output.ml +++ b/compiler/lib-wasm/wasm_output.ml @@ -658,6 +658,11 @@ end = struct output_instruction st ch (Br (l + 1, Some (Pop ty)))) catches; output_byte ch 0X0B + | ExternConvertAny e' -> + Feature.require gc; + output_expression st ch e'; + output_byte ch 0xFB; + output_byte ch 0x1B and output_instruction st ch i = match i with @@ -871,7 +876,8 @@ end = struct | RefCast (_, e') | RefTest (_, e') | Br_on_cast (_, _, _, e') - | Br_on_cast_fail (_, _, _, e') -> expr_function_references e' set + | Br_on_cast_fail (_, _, _, e') + | ExternConvertAny e' -> expr_function_references e' set | BinOp (_, e', e'') | ArrayNew (_, e', e'') | ArrayNewData (_, _, e', e'') diff --git a/compiler/lib-wasm/wat_output.ml b/compiler/lib-wasm/wat_output.ml index 27c2307801..cc332d7d87 100644 --- a/compiler/lib-wasm/wat_output.ml +++ b/compiler/lib-wasm/wat_output.ml @@ -457,6 +457,7 @@ let expression_or_instructions ctx st in_function = @ instruction (Wasm_ast.Br (i + 1, Some (Pop ty)))))) catches)) ] + | ExternConvertAny e' -> [ List (Atom "extern.convert_any" :: expression e') ] and instruction i = match i with | Drop e -> [ List (Atom "drop" :: expression e) ] diff --git a/compiler/lib-wasm/wat_preprocess.ml b/compiler/lib-wasm/wat_preprocess.ml new file mode 100644 index 0000000000..8f72c10d11 --- /dev/null +++ b/compiler/lib-wasm/wat_preprocess.ml @@ -0,0 +1,394 @@ +exception Syntax_error of (Lexing.position * Lexing.position) * string + +let sign = [%sedlex.regexp? Opt ('+' | '-')] + +let digit = [%sedlex.regexp? '0' .. '9'] + +let hexdigit = [%sedlex.regexp? '0' .. '9' | 'a' .. 'f' | 'A' .. 'F'] + +let num = [%sedlex.regexp? digit, Star (Opt '_', digit)] + +let hexnum = [%sedlex.regexp? hexdigit, Star (Opt '_', hexdigit)] + +let uN = [%sedlex.regexp? num | "0x", hexnum] + +let sN = [%sedlex.regexp? sign, uN] + +let iN = [%sedlex.regexp? uN | sN] + +let float = [%sedlex.regexp? num, Opt ('.', Opt num), Opt (('e' | 'E'), sign, num)] + +let hexfloat = + [%sedlex.regexp? "0x", hexnum, Opt ('.', Opt hexnum), Opt (('p' | 'P'), sign, num)] + +let fN = [%sedlex.regexp? sign, (float | hexfloat | "inf" | "nan" | "nan:", hexnum)] + +let idchar = + [%sedlex.regexp? + ( '0' .. '9' + | 'A' .. 'Z' + | 'a' .. 'z' + | '!' + | '#' + | '$' + | '%' + | '&' + | '\'' + | '*' + | '+' + | '-' + | '.' + | '/' + | ':' + | '<' + | '=' + | '>' + | '?' + | '@' + | '\\' + | '^' + | '_' + | '`' + | '|' + | '~' )] + +let id = [%sedlex.regexp? '$', Plus idchar] + +let linechar = [%sedlex.regexp? Sub (any, (10 | 13))] + +let newline = [%sedlex.regexp? 10 | 13 | 13, 10] + +let linecomment = [%sedlex.regexp? ";;", Star linechar, (newline | eof)] + +let format = [%sedlex.regexp? '\n' | 9] + +(* +let space = [%sedlex.regexp? ' ' | format | comment] +*) +let keyword = [%sedlex.regexp? Plus idchar] + +let rec comment lexbuf = + match%sedlex lexbuf with + | ";)" -> () + | "(;" -> + comment lexbuf; + comment lexbuf + | ';' | '(' | Plus (Sub (any, (';' | '('))) -> comment lexbuf + | _ -> + raise + (Syntax_error + (Sedlexing.lexing_positions lexbuf, Printf.sprintf "Malformed comment.\n")) + +let string_buffer = Buffer.create 256 + +let rec string lexbuf = + match%sedlex lexbuf with + | '"' -> + Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); + let s = Buffer.contents string_buffer in + Buffer.clear string_buffer; + s + | Plus (Sub (any, (0 .. 31 | 0x7f | '"' | '\\'))) + | "\\t" | "\\n" | "\\r" | "\\'" | "\\\"" | "\\\\" + | '\\', hexdigit, hexdigit + | "\\u{", hexnum, "}" -> + Buffer.add_string string_buffer (Sedlexing.Utf8.lexeme lexbuf); + string lexbuf + | _ -> + raise + (Syntax_error + (Sedlexing.lexing_positions lexbuf, Printf.sprintf "Malformed string.\n")) + +type pos = + { loc : Lexing.position + ; byte_loc : int + } + +type token = + | LPAREN + | RPAREN + | ATOM of string + | EOF + +let locs lexbuf = + let loc, loc' = Sedlexing.lexing_positions lexbuf in + let byte_loc, byte_loc' = Sedlexing.bytes_loc lexbuf in + { loc; byte_loc }, { loc = loc'; byte_loc = byte_loc' } + +let rec token lexbuf = + match%sedlex lexbuf with + | '(' -> LPAREN, locs lexbuf + | ')' -> RPAREN, locs lexbuf + | uN | sN | fN | keyword -> ATOM (Sedlexing.Utf8.lexeme lexbuf), locs lexbuf + | '"' -> + let string_start = + { loc = Sedlexing.lexing_position_start lexbuf + ; byte_loc = Sedlexing.lexeme_bytes_start lexbuf + } + in + Buffer.add_char string_buffer '"'; + let str = string lexbuf in + ( ATOM str + , ( string_start + , { loc = Sedlexing.lexing_position_curr lexbuf + ; byte_loc = Sedlexing.lexeme_bytes_end lexbuf + } ) ) + | newline | linecomment -> token lexbuf + | Plus (' ' | '\t') -> token lexbuf + | "(;" -> + comment lexbuf; + token lexbuf + | eof -> EOF, locs lexbuf + | _ -> + raise + (Syntax_error (Sedlexing.lexing_positions lexbuf, Printf.sprintf "Syntax error.\n")) + +type t = + { loc : pos * pos + ; desc : desc + } + +and desc = + | Atom of string + | List of t list + +let rec parse_list lexbuf toplevel start_loc acc = + let tok, (loc, loc') = token lexbuf in + match tok with + | LPAREN -> + let lst, loc = parse_list lexbuf false loc [] in + parse_list lexbuf toplevel start_loc ({ desc = List lst; loc } :: acc) + | RPAREN -> + if toplevel + then + raise + (Syntax_error + ( Sedlexing.lexing_positions lexbuf + , Printf.sprintf "Missing closing parenthesis.\n" )); + List.rev acc, (start_loc, loc') + | EOF -> + if not toplevel + then + raise + (Syntax_error + ( Sedlexing.lexing_positions lexbuf + , Printf.sprintf "Unexpected end of file.\n" )); + List.rev acc, (start_loc, loc') + | ATOM s -> + parse_list lexbuf toplevel start_loc ({ loc = loc, loc'; desc = Atom s } :: acc) + +let parse lexbuf = + parse_list + lexbuf + true + { loc = Sedlexing.lexing_position_start lexbuf + ; byte_loc = Sedlexing.lexeme_bytes_end lexbuf + } + [] + +let report_syntax_error loc msg = + let location = MenhirLib.LexerUtil.range loc in + Format.eprintf "%s%s%!" location msg; + exit 1 + +module StringMap = Map.Make (String) + +type st = + { text : string + ; mutable pos : pos + ; variables : bool StringMap.t + ; buf : Buffer.t + ; mutable head : int + ; head_buf : Buffer.t + } + +let write st pos' = + Buffer.add_substring st.buf st.text st.pos.byte_loc (pos'.byte_loc - st.pos.byte_loc); + st.pos <- pos' + +let skip st (pos' : pos) = + let lines = pos'.loc.pos_lnum - st.pos.loc.pos_lnum in + let cols = + pos'.loc.pos_cnum + - pos'.loc.pos_bol + - if lines > 0 then 0 else st.pos.loc.pos_cnum - st.pos.loc.pos_cnum + in + Buffer.add_string st.buf (String.make lines '\n'); + Buffer.add_string st.buf (String.make cols ' '); + st.pos <- pos' + +let pred_position { loc; byte_loc } = + { loc = { loc with pos_cnum = loc.pos_cnum - 1 }; byte_loc = byte_loc - 1 } + +let eval st cond = + match cond with + | { desc = Atom s; loc = pos, pos' } -> + if not (StringMap.mem s st.variables) + then + raise + (Syntax_error ((pos.loc, pos'.loc), Printf.sprintf "Unknown variable '%s'.\n" s)); + StringMap.find s st.variables + | { loc = pos, pos'; _ } -> + raise (Syntax_error ((pos.loc, pos'.loc), Printf.sprintf "Syntax error.\n")) + +let rec rewrite_list st l = List.iter (rewrite st) l + +and rewrite st elt = + match elt with + | { desc = + List + ({ desc = Atom "try"; _ } + :: ( { desc = List ({ desc = Atom "result"; _ } :: _); _ } + :: { desc = List ({ desc = Atom "do"; loc = _, pos_after_do } :: body) + ; loc = _, pos_after_body + } + :: _ + | { desc = List ({ desc = Atom "do"; loc = _, pos_after_do } :: body) + ; loc = _, pos_after_body + } + :: _ )) + ; loc = pos, pos' + } + when StringMap.find "trap-on-exception" st.variables -> + write st pos; + Buffer.add_string st.buf "(block"; + skip st pos_after_do; + rewrite_list st body; + write st pos_after_body; + skip st pos' + | { desc = List ({ desc = Atom "throw"; _ } :: _); loc = pos, pos' } + when StringMap.find "trap-on-exception" st.variables -> + write st pos; + Buffer.add_string st.buf "(unreachable)"; + skip st pos' + | { desc = + List + [ { desc = Atom "#if"; _ } + ; cond + ; { desc = List ({ desc = Atom "#then"; loc = _, pos_after_then } :: then_body) + ; loc = _, pos_after_then_body + } + ] + ; loc = pos, pos' + } -> + write st pos; + if eval st cond + then ( + skip st pos_after_then; + rewrite_list st then_body; + write st (pred_position pos_after_then_body); + skip st pos') + else skip st pos' + | { desc = + List + [ { desc = Atom "#if"; _ } + ; cond + ; { desc = List ({ desc = Atom "#then"; loc = _, pos_after_then } :: then_body) + ; loc = _, pos_after_then_body + } + ; { desc = List ({ desc = Atom "#else"; loc = _, pos_after_else } :: else_body) + ; loc = _, pos_after_else_body + } + ] + ; loc = pos, pos' + } -> + write st pos; + if eval st cond + then ( + skip st pos_after_then; + rewrite_list st then_body; + write st (pred_position pos_after_then_body); + skip st pos') + else ( + skip st pos_after_else; + rewrite_list st else_body; + write st (pred_position pos_after_else_body); + skip st pos') + | { desc = + List + [ { desc = Atom "#string"; _ } + ; { desc = Atom name; _ } + ; { desc = Atom value; _ } + ] + ; loc = pos, pos' + } -> + write st pos; + (if + StringMap.mem "use-js-string" st.variables + && StringMap.find "use-js-string" st.variables + then ( + Printf.bprintf + st.head_buf + "(import \"\" %s (global %s$string externref)) " + value + name; + Printf.bprintf + st.buf + "(global %s (ref eq) (struct.new $string (any.convert_extern (global.get \ + %s$string))))" + name + name) + else + let s = String.sub value 1 (String.length value - 2) in + Printf.bprintf + st.buf + "(global %s (ref eq) (array.new_fixed $bytes %d%a))" + name + (String.length s) + (fun f s -> + String.iter (fun c -> Printf.bprintf f " (i32.const %d)" (Char.code c)) s) + s); + skip st pos' + | { desc = + List + [ { desc = Atom "#jsstring"; _ } + ; { desc = Atom name; _ } + ; { desc = Atom value; _ } + ] + ; loc = pos, pos' + } -> + write st pos; + Printf.bprintf + st.head_buf + "(import \"\" %s (global %s$string externref)) " + value + name; + Printf.bprintf + st.buf + "(global %s (ref eq) (struct.new $js (any.convert_extern (global.get \ + %s$string))))" + name + name; + skip st pos' + | { desc = List ({ desc = Atom "module"; loc = _, pos } :: _ as l); _ } -> + st.head <- pos.byte_loc; + rewrite_list st l + | { desc = List l; _ } -> rewrite_list st l + | _ -> () + +let f ~variables ~filename ~contents:text = + let variables = ("trap-on-exception", false) :: variables in + let variables = + List.fold_left (fun m (k, v) -> StringMap.add k v m) StringMap.empty variables + in + let lexbuf = Sedlexing.Utf8.from_string text in + Sedlexing.set_filename lexbuf filename; + try + let t, (pos, end_pos) = parse lexbuf in + let st = + { text + ; pos + ; variables + ; buf = Buffer.create (String.length text) + ; head_buf = Buffer.create 128 + ; head = 0 + } + in + rewrite_list st t; + write st end_pos; + let head = Buffer.contents st.head_buf in + let contents = Buffer.contents st.buf in + String.sub contents 0 st.head + ^ head + ^ String.sub contents st.head (String.length contents - st.head) + with Syntax_error (loc, msg) -> report_syntax_error loc msg diff --git a/compiler/lib-wasm/wat_preprocess.mli b/compiler/lib-wasm/wat_preprocess.mli new file mode 100644 index 0000000000..63e6f287a2 --- /dev/null +++ b/compiler/lib-wasm/wat_preprocess.mli @@ -0,0 +1 @@ +val f : variables:(string * bool) list -> filename:string -> contents:string -> string diff --git a/compiler/lib/config.ml b/compiler/lib/config.ml index 29f39a1f02..ec6fb742ac 100644 --- a/compiler/lib/config.ml +++ b/compiler/lib/config.ml @@ -193,5 +193,7 @@ let target () = let set_target (t : [ `JavaScript | `Wasm ]) = (match t with | `JavaScript -> Targetint.set_num_bits 32 - | `Wasm -> Targetint.set_num_bits 31); + | `Wasm -> + Targetint.set_num_bits 31; + Flag.disable "use-js-string"); target_ := (t :> [ `JavaScript | `Wasm | `None ]) diff --git a/compiler/tests-jsoo/dune b/compiler/tests-jsoo/dune index 26f79c9284..de7d202c4d 100644 --- a/compiler/tests-jsoo/dune +++ b/compiler/tests-jsoo/dune @@ -45,7 +45,7 @@ (libraries unix compiler-libs.common js_of_ocaml-compiler) (foreign_stubs (language c) - (names bigarray_stubs)) + (names bigarray_stubs jsoo_runtime_stubs)) (inline_tests (modes js wasm best)) (preprocess diff --git a/compiler/tests-jsoo/jsoo_runtime_stubs.c b/compiler/tests-jsoo/jsoo_runtime_stubs.c new file mode 100644 index 0000000000..aa8ff04e0f --- /dev/null +++ b/compiler/tests-jsoo/jsoo_runtime_stubs.c @@ -0,0 +1,7 @@ + +#include + +CAMLprim value caml_jsoo_flags_use_js_string(value v_unit) +{ + return Val_false; +} diff --git a/compiler/tests-jsoo/test_obj.ml b/compiler/tests-jsoo/test_obj.ml index 84ea39f0da..269fe2bdc2 100644 --- a/compiler/tests-jsoo/test_obj.ml +++ b/compiler/tests-jsoo/test_obj.ml @@ -45,13 +45,10 @@ let%expect_test "is_int" = (* https://github.com/ocsigen/js_of_ocaml/issues/666 *) (* https://github.com/ocsigen/js_of_ocaml/pull/725 *) +external use_js_string : unit -> bool = "caml_jsoo_flags_use_js_string" + let%expect_test "dup" = - let magic = "abcd" in - let js_string_enabled = - match Sys.backend_type with - | Other "js_of_ocaml" -> Array.unsafe_get (Obj.magic magic) 0 == "b" - | _ -> false - in + let js_string_enabled = use_js_string () in let s = "Hello" in let s' : string = Obj.obj (Obj.dup (Obj.repr s)) in print_bool (s = s'); diff --git a/dune b/dune index 292467727b..7fa05d513d 100644 --- a/dune +++ b/dune @@ -4,7 +4,10 @@ (:standard -w +a-4-40-41-42-44-48-58-66-70)) (binaries (tools/node_wrapper.exe as node) - (tools/node_wrapper.exe as node.exe))) + (tools/node_wrapper.exe as node.exe)) + (wasm_of_ocaml + (flags + (:standard --enable use-js-string)))) (with-effects (js_of_ocaml (compilation_mode separate) diff --git a/runtime/js/marshal.js b/runtime/js/marshal.js index 7e4aec531a..33676514bb 100644 --- a/runtime/js/marshal.js +++ b/runtime/js/marshal.js @@ -863,7 +863,7 @@ var caml_output_val = (function () { } if (intern_obj_table) writer.obj_counter = intern_obj_table.objs.length; writer.finalize(); - return writer.chunk; + return new Uint8Array(writer.chunk); }; })(); @@ -880,10 +880,10 @@ function caml_output_value_to_bytes(v, flags) { } //Provides: caml_output_value_to_buffer -//Requires: caml_output_val, caml_failwith, caml_blit_bytes +//Requires: caml_output_val, caml_failwith, caml_blit_bytes, caml_bytes_of_array function caml_output_value_to_buffer(s, ofs, len, v, flags) { var t = caml_output_val(v, flags); if (t.length > len) caml_failwith("Marshal.to_buffer: buffer overflow"); - caml_blit_bytes(t, 0, s, ofs, t.length); + caml_blit_bytes(caml_bytes_of_array(t), 0, s, ofs, t.length); return 0; } diff --git a/runtime/js/mlBytes.js b/runtime/js/mlBytes.js index 8566487548..aff366daab 100644 --- a/runtime/js/mlBytes.js +++ b/runtime/js/mlBytes.js @@ -78,7 +78,7 @@ function caml_subarray_to_jsbytes(a, i, len) { if (i === 0 && len <= 4096 && len === a.length) return f.apply(null, a); var s = ""; for (; 0 < len; i += 1024, len -= 1024) - s += f.apply(null, a.slice(i, i + Math.min(len, 1024))); + s += f.apply(null, a.subarray(i, i + Math.min(len, 1024))); return s; } diff --git a/runtime/wasm/args.ml b/runtime/wasm/args.ml deleted file mode 100644 index 16cd0418a5..0000000000 --- a/runtime/wasm/args.ml +++ /dev/null @@ -1,4 +0,0 @@ -let () = - for i = 1 to Array.length Sys.argv - 1 do - Format.printf "%s@.%s@." Sys.argv.(i) (Filename.chop_suffix Sys.argv.(i) ".wat") - done diff --git a/runtime/wasm/array.wat b/runtime/wasm/array.wat index 00d01e8082..6c41a84257 100644 --- a/runtime/wasm/array.wat +++ b/runtime/wasm/array.wat @@ -20,11 +20,12 @@ (func $caml_invalid_argument (param (ref eq)))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $float (struct (field f64))) (type $float_array (array (mut f64))) - (data $Array_make "Array.make") + (#string $Array_make "Array.make") (global $empty_array (ref eq) (array.new_fixed $block 1 (ref.i31 (i32.const 0)))) @@ -34,10 +35,7 @@ (local $sz i32) (local $b (ref $block)) (local $f f64) (local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n)))) (if (i32.lt_s (local.get $sz) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $Array_make - (i32.const 0) (i32.const 10))))) + (then (call $caml_invalid_argument (global.get $Array_make)))) (if (i32.eqz (local.get $sz)) (then (return (global.get $empty_array)))) (drop (block $not_float (result (ref eq)) (local.set $f @@ -56,10 +54,7 @@ (local $sz i32) (local $f f64) (local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n)))) (if (i32.lt_s (local.get $sz) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $Array_make - (i32.const 0) (i32.const 10))))) + (then (call $caml_invalid_argument (global.get $Array_make)))) (if (i32.eqz (local.get $sz)) (then (return (global.get $empty_array)))) (local.set $f (struct.get $float 0 @@ -73,10 +68,7 @@ (local $sz i32) (local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n)))) (if (i32.lt_s (local.get $sz) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $Array_make - (i32.const 0) (i32.const 10))))) + (then (call $caml_invalid_argument (global.get $Array_make)))) (if (i32.eqz (local.get $sz)) (then (return (global.get $empty_array)))) (array.new $float_array (f64.const 0) (local.get $sz))) diff --git a/runtime/wasm/backtrace.wat b/runtime/wasm/backtrace.wat index ea4d0e46aa..b90e8f02b4 100644 --- a/runtime/wasm/backtrace.wat +++ b/runtime/wasm/backtrace.wat @@ -20,7 +20,8 @@ (func $caml_invalid_argument (param (ref eq)))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (func (export "caml_get_exception_raw_backtrace") (param (ref eq)) (result (ref eq)) @@ -38,14 +39,12 @@ (param (ref eq)) (result (ref eq)) (ref.i31 (i32.const 0))) - (data $raw_backtrace_slot_err + (#string $raw_backtrace_slot_err "Printexc.get_raw_backtrace_slot: index out of bounds") (func (export "caml_raw_backtrace_slot") (param (ref eq) (ref eq)) (result (ref eq)) - (call $caml_invalid_argument - (array.new_data $string $raw_backtrace_slot_err - (i32.const 0) (i32.const 52))) + (call $caml_invalid_argument (global.get $raw_backtrace_slot_err)) (ref.i31 (i32.const 0))) (func (export "caml_convert_raw_backtrace_slot") diff --git a/runtime/wasm/bigarray.wat b/runtime/wasm/bigarray.wat index 812055eca7..0c545eb476 100644 --- a/runtime/wasm/bigarray.wat +++ b/runtime/wasm/bigarray.wat @@ -69,14 +69,20 @@ (import "bindings" "ta_subarray" (func $ta_subarray (param (ref extern)) (param i32) (param i32) (result (ref extern)))) + (import "bindings" "ta_blit_from_bytes" + (func $ta_blit_from_bytes + (param (ref $bytes)) (param i32) (param (ref extern)) (param i32) + (param i32))) + (import "bindings" "ta_blit_to_bytes" + (func $ta_blit_to_bytes + (param (ref extern)) (param i32) (param (ref $bytes)) (param i32) + (param i32))) (import "bindings" "ta_blit_from_string" (func $ta_blit_from_string - (param (ref $string)) (param i32) (param (ref extern)) (param i32) - (param i32))) - (import "bindings" "ta_blit_to_string" - (func $ta_blit_to_string - (param (ref extern)) (param i32) (param (ref $string)) (param i32) + (param anyref) (param i32) (param (ref extern)) (param i32) (param i32))) + (import "bindings" "ta_to_string" + (func $ta_to_string (param (ref extern)) (result (ref any)))) (import "fail" "caml_bound_error" (func $caml_bound_error)) (import "fail" "caml_raise_out_of_memory" (func $caml_raise_out_of_memory)) (import "fail" "caml_invalid_argument" @@ -124,9 +130,12 @@ (func $caml_deserialize_int_4 (param (ref eq)) (result i32))) (import "marshal" "caml_deserialize_int_8" (func $caml_deserialize_int_8 (param (ref eq)) (result i64))) + (import "jsstring" "jsstring_length" + (func $jsstring_length (param anyref) (result i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $float (struct (field f64))) (type $float_array (array (mut f64))) @@ -141,7 +150,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -153,7 +162,7 @@ (global $bigarray_ops (export "bigarray_ops") (ref $custom_operations) (struct.new $custom_operations - (array.new_fixed $string 9 ;; "_bigarr02" + (array.new_fixed $bytes 9 ;; "_bigarr02" (i32.const 95) (i32.const 98) (i32.const 105) (i32.const 103) (i32.const 97) (i32.const 114) (i32.const 114) (i32.const 48) (i32.const 50)) @@ -516,7 +525,7 @@ (i32.mul (i32.add (i32.const 4) (local.get $num_dims)) (i32.const 4)) (i32.mul (i32.add (i32.const 4) (local.get $num_dims)) (i32.const 8)))) - (data $intern_overflow + (#string $intern_overflow "input_value: cannot read bigarray with 64-bit OCaml ints") (func $bigarray_deserialize @@ -589,10 +598,7 @@ (br $done)) ;; int (if (call $caml_deserialize_uint_1 (local.get $s)) - (then - (call $caml_failwith - (array.new_data $string $intern_overflow - (i32.const 0) (i32.const 56)))))) + (then (call $caml_failwith (global.get $intern_overflow))))) ;; int32 (loop $loop (if (i32.lt_u (local.get $i) (local.get $len)) @@ -701,8 +707,8 @@ (global $CAML_BA_MAX_NUM_DIMS i32 (i32.const 16)) - (data $ba_create_bad_dims "Bigarray.create: bad number of dimensions") - (data $ba_create_negative_dim "Bigarray.create: negative dimension") + (#string $ba_create_bad_dims "Bigarray.create: bad number of dimensions") + (#string $ba_create_negative_dim "Bigarray.create: negative dimension") (func (export "caml_ba_create") (param $vkind (ref eq)) (param $layout (ref eq)) (param $d (ref eq)) @@ -716,8 +722,7 @@ (if (i32.gt_u (local.get $num_dims) (global.get $CAML_BA_MAX_NUM_DIMS)) (then (call $caml_invalid_argument - (array.new_data $string $ba_create_bad_dims - (i32.const 0) (i32.const 41))))) + (global.get $ba_create_bad_dims)))) (local.set $dim (array.new $int_array (i32.const 0) (local.get $num_dims))) (local.set $i (i32.const 0)) @@ -732,8 +737,7 @@ (if (i32.lt_s (local.get $n) (i32.const 0)) (then (call $caml_invalid_argument - (array.new_data $string $ba_create_negative_dim - (i32.const 0) (i32.const 35))))) + (global.get $ba_create_negative_dim)))) (array.set $int_array (local.get $dim) (local.get $i) (local.get $n)) (local.set $i (i32.add (local.get $i) (i32.const 1))) @@ -747,8 +751,8 @@ (local.get $kind) (i31.get_s (ref.cast (ref i31) (local.get $layout))))) - (data $ta_unsupported_kind "Typed_array.to_genarray: unsupported kind") - (data $ta_too_large "Typed_array.to_genarray: too large") + (#string $ta_unsupported_kind "Typed_array.to_genarray: unsupported kind") + (#string $ta_too_large "Typed_array.to_genarray: too large") (func (export "caml_ba_from_typed_array") (param (ref eq)) (result (ref eq)) (local $data (ref extern)) @@ -759,18 +763,12 @@ (ref.as_non_null (extern.convert_any (call $unwrap (local.get 0)))))) (local.set $kind (call $ta_kind (local.get $data))) (if (i32.lt_s (local.get $kind) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $ta_unsupported_kind - (i32.const 0) (i32.const 41))))) + (then (call $caml_invalid_argument (global.get $ta_unsupported_kind)))) (if (i32.eq (local.get $kind) (i32.const 13)) ;; Uint8ClampedArray (then (local.set $kind (i32.const 3)))) (local.set $len (call $ta_length (local.get $data))) (if (i32.lt_s (local.get $len) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $ta_too_large - (i32.const 0) (i32.const 34))))) + (then (call $caml_invalid_argument (global.get $ta_too_large)))) (struct.new $bigarray (global.get $bigarray_ops) (local.get $data) @@ -944,7 +942,7 @@ (struct.get $float 0 (ref.cast (ref $float) (local.get $v)))) (return)) - (data $Bigarray_dim "Bigarray.dim") + (#string $Bigarray_dim "Bigarray.dim") (func $caml_ba_dim (export "caml_ba_dim") (param (ref eq)) (param (ref eq)) (result (ref eq)) @@ -955,9 +953,7 @@ (ref.cast (ref $bigarray) (local.get 0)))) (local.set $i (i31.get_s (ref.cast (ref i31) (local.get 1)))) (if (i32.ge_u (local.get $i) (array.len (local.get $dim))) - (then (call $caml_invalid_argument - (array.new_data $string $Bigarray_dim - (i32.const 0) (i32.const 12))))) + (then (call $caml_invalid_argument (global.get $Bigarray_dim)))) (ref.i31 (array.get $int_array (local.get $dim) (local.get $i)))) (func (export "caml_ba_dim_1") (param (ref eq)) (result (ref eq)) @@ -1303,7 +1299,7 @@ (local.get $v)) (ref.i31 (i32.const 0))) - (data $too_many_indices "Bigarray.slice: too many indices") + (#string $too_many_indices "Bigarray.slice: too many indices") (func (export "caml_ba_slice") (param $vb (ref eq)) (param $vind (ref eq)) (result (ref eq)) @@ -1319,10 +1315,7 @@ (local.set $num_dims (struct.get $bigarray $ba_num_dims (local.get $b))) (if (i32.gt_u (local.get $num_inds) (struct.get $bigarray $ba_num_dims (local.get $b))) - (then - (call $caml_invalid_argument - (array.new_data $string $too_many_indices - (i32.const 0) (i32.const 32))))) + (then (call $caml_invalid_argument (global.get $too_many_indices)))) (local.set $sub_dim (array.new $int_array (i32.const 0) (i32.sub (local.get $num_dims) (local.get $num_inds)))) @@ -1386,7 +1379,7 @@ (struct.get $bigarray $ba_kind (local.get $b)) (struct.get $bigarray $ba_layout (local.get $b)))) - (data $bad_subarray "Bigarray.sub: bad sub-array") + (#string $bad_subarray "Bigarray.sub: bad sub-array") (func (export "caml_ba_sub") (param $vba (ref eq)) (param $vofs (ref eq)) (param $vlen (ref eq)) @@ -1436,10 +1429,7 @@ (i32.gt_s (i32.add (local.get $ofs) (local.get $len)) (array.get $int_array (local.get $dim) (local.get $changed_dim)))) - (then - (call $caml_invalid_argument - (array.new_data $string $bad_subarray - (i32.const 0) (i32.const 27))))) + (then (call $caml_invalid_argument (global.get $bad_subarray)))) (local.set $new_dim (array.new $int_array (i32.const 0) (local.get $num_dims))) (array.copy $int_array $int_array @@ -1546,7 +1536,7 @@ (struct.get $float 0 (ref.cast (ref $float) (local.get $v)))) (return (ref.i31 (i32.const 0)))) - (data $dim_mismatch "Bigarray.blit: dimension mismatch") + (#string $dim_mismatch "Bigarray.blit: dimension mismatch") (func (export "caml_ba_blit") (param $vsrc (ref eq)) (param $vdst (ref eq)) (result (ref eq)) @@ -1560,10 +1550,7 @@ (local.set $len (struct.get $bigarray $ba_num_dims (local.get $dst))) (if (i32.ne (local.get $len) (struct.get $bigarray $ba_num_dims (local.get $src))) - (then - (call $caml_invalid_argument - (array.new_data $string $dim_mismatch - (i32.const 0) (i32.const 33))))) + (then (call $caml_invalid_argument (global.get $dim_mismatch)))) (local.set $sdim (struct.get $bigarray $ba_dim (local.get $src))) (local.set $ddim (struct.get $bigarray $ba_dim (local.get $dst))) (loop $loop @@ -1573,9 +1560,7 @@ (array.get $int_array (local.get $sdim) (local.get $i)) (array.get $int_array (local.get $ddim) (local.get $i))) (then - (call $caml_invalid_argument - (array.new_data $string $dim_mismatch - (i32.const 0) (i32.const 33))))) + (call $caml_invalid_argument (global.get $dim_mismatch)))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br $loop)))) (call $ta_blit @@ -1583,9 +1568,9 @@ (struct.get $bigarray $ba_data (local.get $dst))) (ref.i31 (i32.const 0))) - (data $bad_number_dim "Bigarray.reshape: bad number of dimensions") - (data $negative_dim "Bigarray.reshape: negative dimension") - (data $size_mismatch "Bigarray.reshape: size mismatch") + (#string $bad_number_dim "Bigarray.reshape: bad number of dimensions") + (#string $negative_dim "Bigarray.reshape: negative dimension") + (#string $size_mismatch "Bigarray.reshape: size mismatch") (func (export "caml_ba_reshape") (param $vb (ref eq)) (param $vd (ref eq)) (result (ref eq)) @@ -1598,9 +1583,7 @@ (local.set $b (ref.cast (ref $bigarray) (local.get $vb))) (if (i32.gt_u (local.get $num_dims) (global.get $CAML_BA_MAX_NUM_DIMS)) (then - (call $caml_invalid_argument - (array.new_data $string $bad_number_dim - (i32.const 0) (i32.const 42))))) + (call $caml_invalid_argument (global.get $bad_number_dim)))) (local.set $num_elts (i64.const 1)) (local.set $dim (array.new $int_array (i32.const 0) (local.get $num_dims))) (loop $loop @@ -1613,9 +1596,7 @@ (i32.add (local.get $i) (i32.const 1)))))) (if (i32.lt_s (local.get $d) (i32.const 0)) (then - (call $caml_invalid_argument - (array.new_data $string $negative_dim - (i32.const 0) (i32.const 36))))) + (call $caml_invalid_argument (global.get $negative_dim)))) (array.set $int_array (local.get $dim) (local.get $i) (local.get $d)) (local.set $num_elts @@ -1629,10 +1610,7 @@ (if (i32.ne (i32.wrap_i64 (local.get $num_elts)) (call $caml_ba_get_size (struct.get $bigarray $ba_dim (local.get $b)))) - (then - (call $caml_invalid_argument - (array.new_data $string $size_mismatch - (i32.const 0) (i32.const 31))))) + (then (call $caml_invalid_argument (global.get $size_mismatch)))) (struct.new $bigarray (global.get $bigarray_ops) (struct.get $bigarray $ba_data (local.get $b)) @@ -2020,29 +1998,44 @@ (i32.wrap_i64 (i64.shr_u (local.get $d) (i64.const 32)))) (ref.i31 (i32.const 0))) - (export "caml_bytes_of_array" (func $caml_string_of_array)) - (func $caml_string_of_array (export "caml_string_of_array") +(#if use-js-string +(#then + (func (export "caml_string_of_array") (param (ref eq)) (result (ref eq)) ;; used to convert a typed array to a string + (local $a (ref extern)) + (local.set $a + (ref.as_non_null (extern.convert_any (call $unwrap (local.get 0))))) + (struct.new $string (call $ta_to_string (local.get $a)))) +) +(#else + (export "caml_string_of_array" (func $caml_bytes_of_array)) +)) + + (func $caml_bytes_of_array (export "caml_bytes_of_array") + (param (ref eq)) (result (ref eq)) + ;; used to convert a typed array to bytes (local $a (ref extern)) (local $len i32) - (local $s (ref $string)) + (local $s (ref $bytes)) (local.set $a (ref.as_non_null (extern.convert_any (call $unwrap (local.get 0))))) (local.set $len (call $ta_length (local.get $a))) - (local.set $s (array.new $string (i32.const 0) (local.get $len))) - (call $ta_blit_to_string + (local.set $s (array.new $bytes (i32.const 0) (local.get $len))) + (call $ta_blit_to_bytes (local.get $a) (i32.const 0) (local.get $s) (i32.const 0) (local.get $len)) (local.get $s)) - (export "caml_uint8_array_of_bytes" (func $caml_uint8_array_of_string)) - (func $caml_uint8_array_of_string (export "caml_uint8_array_of_string") +(#if use-js-string +(#then + (func (export "caml_uint8_array_of_string") (param (ref eq)) (result (ref eq)) ;; Convert a string to a typed array (local $ta (ref extern)) (local $len i32) - (local $s (ref $string)) - (local.set $s (ref.cast (ref $string) (local.get 0))) - (local.set $len (array.len (local.get $s))) + (local $s anyref) + (local.set $s + (struct.get $string 0 (ref.cast (ref $string) (local.get 0)))) + (local.set $len (call $jsstring_length (local.get $s))) (local.set $ta (call $ta_create (i32.const 3) ;; Uint8Array @@ -2051,6 +2044,26 @@ (local.get $s) (i32.const 0) (local.get $ta) (i32.const 0) (local.get $len)) (call $wrap (any.convert_extern (local.get $ta)))) +) +(#else + (export "caml_uint8_array_of_string" (func $caml_uint8_array_of_bytes)) +)) + + (func $caml_uint8_array_of_bytes (export "caml_uint8_array_of_bytes") + (param (ref eq)) (result (ref eq)) + ;; Convert bytes to a typed array + (local $ta (ref extern)) (local $len i32) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (local.set $len (array.len (local.get $s))) + (local.set $ta + (call $ta_create + (i32.const 3) ;; Uint8Array + (local.get $len))) + (call $ta_blit_from_bytes + (local.get $s) (i32.const 0) (local.get $ta) (i32.const 0) + (local.get $len)) + (call $wrap (any.convert_extern (local.get $ta)))) (func (export "caml_ba_get_kind") (param (ref eq)) (result i32) (struct.get $bigarray $ba_kind (ref.cast (ref $bigarray) (local.get 0)))) @@ -2083,13 +2096,13 @@ (func (export "string_set") (param $s externref) (param $i i32) (param $v i32) - (array.set $string - (ref.cast (ref null $string) (any.convert_extern (local.get $s))) + (array.set $bytes + (ref.cast (ref null $bytes) (any.convert_extern (local.get $s))) (local.get $i) (local.get $v))) (func (export "string_get") (param $s externref) (param $i i32) (result i32) - (array.get $string - (ref.cast (ref null $string) (any.convert_extern (local.get $s))) + (array.get $bytes + (ref.cast (ref null $bytes) (any.convert_extern (local.get $s))) (local.get $i))) ) diff --git a/runtime/wasm/bigstring.wat b/runtime/wasm/bigstring.wat index 94a9621743..a0dc1f3f8e 100644 --- a/runtime/wasm/bigstring.wat +++ b/runtime/wasm/bigstring.wat @@ -48,18 +48,39 @@ (func $ta_length (param (ref extern)) (result i32))) (import "bindings" "ta_bytes" (func $ta_bytes (param anyref) (result anyref))) + (import "bindings" "ta_blit_from_bytes" + (func $ta_blit_from_bytes + (param (ref $bytes)) (param i32) (param (ref extern)) (param i32) + (param i32))) + (import "bindings" "ta_blit_to_bytes" + (func $ta_blit_to_bytes + (param (ref extern)) (param i32) (param (ref $bytes)) (param i32) + (param i32))) (import "bindings" "ta_blit_from_string" (func $ta_blit_from_string - (param (ref $string)) (param i32) (param (ref extern)) (param i32) - (param i32))) - (import "bindings" "ta_blit_to_string" - (func $ta_blit_to_string - (param (ref extern)) (param i32) (param (ref $string)) (param i32) + (param anyref) (param i32) (param (ref extern)) (param i32) (param i32))) (import "hash" "caml_hash_mix_int" (func $caml_hash_mix_int (param i32) (param i32) (result i32))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) + (type $js (struct (field anyref))) + +(#if use-js-string +(#then + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) (func (export "caml_hash_mix_bigstring") (param $h i32) (param $b (ref eq)) (result i32) @@ -98,13 +119,13 @@ (local.set $h (call $caml_hash_mix_int (local.get $h) (local.get $w)))) (i32.xor (local.get $h) (local.get $len))) - (data $buffer "buffer") + (#jsstring $buffer "buffer") (func (export "bigstring_to_array_buffer") (param $bs (ref eq)) (result (ref eq)) (return_call $caml_js_get (call $caml_ba_to_typed_array (local.get $bs)) - (array.new_data $string $buffer (i32.const 0) (i32.const 6)))) + (global.get $buffer))) (export "bigstring_to_typed_array" (func $caml_ba_to_typed_array)) @@ -160,10 +181,16 @@ (local $i i32) (local $pos1 i32) (local $pos2 i32) (local $len i32) (local $c1 i32) (local $c2 i32) (local $d1 (ref extern)) - (local $s2 (ref $string)) +(#if use-js-string +(#then + (local $s2 externref) +) +(#else + (local $s2 (ref $bytes)) +)) (local.set $d1 (call $caml_ba_get_data (local.get $s1))) (local.set $pos1 (i31.get_s (ref.cast (ref i31) (local.get $vpos1)))) - (local.set $s2 (ref.cast (ref $string) (local.get $vs2))) + (local.set $s2 (call $string_val (local.get $vs2))) (local.set $pos2 (i31.get_s (ref.cast (ref i31) (local.get $vpos2)))) (local.set $len (i31.get_s (ref.cast (ref i31) (local.get $vlen)))) (loop $loop @@ -173,7 +200,7 @@ (call $ta_get_ui8 (local.get $d1) (i32.add (local.get $pos1) (local.get $i)))) (local.set $c2 - (array.get_u $string (local.get $s2) + (call $string_get (local.get $s2) (i32.add (local.get $pos2) (local.get $i)))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $loop (i32.eq (local.get $c1) (local.get $c2))) @@ -203,22 +230,46 @@ (br $loop)))) (ref.i31 (i32.const -1))) +(#if use-js-string +(#then + (func (export "caml_bigstring_blit_string_to_ba") + (param $str1 (ref eq)) (param $vpos1 (ref eq)) + (param $ba2 (ref eq)) (param $vpos2 (ref eq)) + (param $vlen (ref eq)) (result (ref eq)) + (local $pos1 i32) (local $pos2 i32) (local $len i32) + (local $s1 anyref) + (local $d2 (ref extern)) + (local.set $s1 + (struct.get $string 0 (ref.cast (ref $string) (local.get $str1)))) + (local.set $pos1 (i31.get_s (ref.cast (ref i31) (local.get $vpos1)))) + (local.set $d2 (call $caml_ba_get_data (local.get $ba2))) + (local.set $pos2 (i31.get_s (ref.cast (ref i31) (local.get $vpos2)))) + (local.set $len (i31.get_s (ref.cast (ref i31) (local.get $vlen)))) + (call $ta_blit_from_string + (local.get $s1) (local.get $pos1) + (local.get $d2) (local.get $pos2) + (local.get $len)) + (ref.i31 (i32.const 0))) +) +(#else (export "caml_bigstring_blit_string_to_ba" (func $caml_bigstring_blit_bytes_to_ba)) +)) + (func $caml_bigstring_blit_bytes_to_ba (export "caml_bigstring_blit_bytes_to_ba") (param $str1 (ref eq)) (param $vpos1 (ref eq)) (param $ba2 (ref eq)) (param $vpos2 (ref eq)) (param $vlen (ref eq)) (result (ref eq)) (local $pos1 i32) (local $pos2 i32) (local $len i32) - (local $s1 (ref $string)) + (local $s1 (ref $bytes)) (local $d2 (ref extern)) - (local.set $s1 (ref.cast (ref $string) (local.get $str1))) + (local.set $s1 (ref.cast (ref $bytes) (local.get $str1))) (local.set $pos1 (i31.get_s (ref.cast (ref i31) (local.get $vpos1)))) (local.set $d2 (call $caml_ba_get_data (local.get $ba2))) (local.set $pos2 (i31.get_s (ref.cast (ref i31) (local.get $vpos2)))) (local.set $len (i31.get_s (ref.cast (ref i31) (local.get $vlen)))) - (call $ta_blit_from_string + (call $ta_blit_from_bytes (local.get $s1) (local.get $pos1) (local.get $d2) (local.get $pos2) (local.get $len)) @@ -230,13 +281,13 @@ (param $vlen (ref eq)) (result (ref eq)) (local $pos1 i32) (local $pos2 i32) (local $len i32) (local $d1 (ref extern)) - (local $s2 (ref $string)) + (local $s2 (ref $bytes)) (local.set $d1 (call $caml_ba_get_data (local.get $ba1))) (local.set $pos1 (i31.get_s (ref.cast (ref i31) (local.get $vpos1)))) - (local.set $s2 (ref.cast (ref $string) (local.get $str2))) + (local.set $s2 (ref.cast (ref $bytes) (local.get $str2))) (local.set $pos2 (i31.get_s (ref.cast (ref i31) (local.get $vpos2)))) (local.set $len (i31.get_s (ref.cast (ref i31) (local.get $vlen)))) - (call $ta_blit_to_string + (call $ta_blit_to_bytes (local.get $d1) (local.get $pos1) (local.get $s2) (local.get $pos2) (local.get $len)) diff --git a/runtime/wasm/compare.wat b/runtime/wasm/compare.wat index affa2a2765..5e4252adf7 100644 --- a/runtime/wasm/compare.wat +++ b/runtime/wasm/compare.wat @@ -38,7 +38,8 @@ (func $jsstring_compare (param anyref) (param anyref) (result i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $float (struct (field f64))) (type $float_array (array (mut f64))) (type $js (struct (field anyref))) @@ -62,7 +63,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -161,7 +162,7 @@ (global $unordered (export "unordered") i32 (i32.const 0x80000000)) (func $compare_strings - (param $s1 (ref $string)) (param $s2 (ref $string)) (result i32) + (param $s1 (ref $bytes)) (param $s2 (ref $bytes)) (result i32) (local $l1 i32) (local $l2 i32) (local $len i32) (local $i i32) (local $c1 i32) (local $c2 i32) (if (ref.eq (local.get $s1) (local.get $s2)) @@ -175,9 +176,9 @@ (if (i32.lt_s (local.get $i) (local.get $len)) (then (local.set $c1 - (array.get_u $string (local.get $s1) (local.get $i))) + (array.get_u $bytes (local.get $s1) (local.get $i))) (local.set $c2 - (array.get_u $string (local.get $s2) (local.get $i))) + (array.get_u $bytes (local.get $s2) (local.get $i))) (if (i32.ne (local.get $c1) (local.get $c2)) (then (if (i32.le_u (local.get $c1) (local.get $c2)) @@ -215,9 +216,9 @@ (call $clear_compare_stack) (local.get $res)) - (data $abstract_value "compare: abstract value") - (data $functional_value "compare: functional value") - (data $continuation_value "compare: continuation value") + (#string $abstract_value "compare: abstract value") + (#string $functional_value "compare: functional value") + (#string $continuation_value "compare: continuation value") (func $do_compare_val (param $stack (ref $compare_stack)) @@ -228,7 +229,7 @@ (local $s1 i32) (local $s2 i32) (local $f1 f64) (local $f2 f64) (local $fa1 (ref $float_array)) (local $fa2 (ref $float_array)) - (local $str1 (ref $string)) (local $str2 (ref $string)) + (local $str1 (ref $bytes)) (local $str2 (ref $bytes)) (local $c1 (ref $custom)) (local $c2 (ref $custom)) (local $js1 anyref) (local $js2 anyref) (local $tuple (tuple (ref eq) (ref eq))) @@ -394,10 +395,10 @@ (br $next_item))) (drop (block $v1_not_string (result (ref eq)) (local.set $str1 - (br_on_cast_fail $v1_not_string (ref eq) (ref $string) + (br_on_cast_fail $v1_not_string (ref eq) (ref $bytes) (local.get $v1))) (local.set $str2 - (br_on_cast_fail $heterogeneous (ref eq) (ref $string) + (br_on_cast_fail $heterogeneous (ref eq) (ref $bytes) (local.get $v2))) (local.set $res (call $compare_strings (local.get $str1) (local.get $str2))) @@ -477,9 +478,7 @@ (br_if $next_item (i32.eqz (local.get $res))) (return (local.get $res))) (call $clear_compare_stack) - (call $caml_invalid_argument - (array.new_data $string $abstract_value - (i32.const 0) (i32.const 23))) + (call $caml_invalid_argument (global.get $abstract_value)) (ref.i31 (i32.const 0)))) (drop (block $v1_not_js (result (ref eq)) (local.set $js1 @@ -514,8 +513,7 @@ (i32.eqz (call $caml_is_closure (local.get $v2))))) (call $clear_compare_stack) (call $caml_invalid_argument - (array.new_data $string $functional_value - (i32.const 0) (i32.const 25))))) + (global.get $functional_value)))) (if (call $caml_is_continuation (local.get $v1)) (then (drop (br_if $heterogeneous(ref.i31 (i32.const 0)) @@ -523,8 +521,7 @@ (call $caml_is_continuation (local.get $v2))))) (call $clear_compare_stack) (call $caml_invalid_argument - (array.new_data $string $continuation_value - (i32.const 0) (i32.const 27))))) + (global.get $continuation_value)))) (ref.i31 (i32.const 0)))) ;; fall through ;; heterogeneous comparison (local.set $t1 @@ -550,8 +547,7 @@ (then (call $clear_compare_stack) (call $caml_invalid_argument - (array.new_data $string $abstract_value - (i32.const 0) (i32.const 23))))) + (global.get $abstract_value)))) (return (local.get $res))) (if (call $compare_stack_is_not_empty (local.get $stack)) (then diff --git a/runtime/wasm/custom.wat b/runtime/wasm/custom.wat index 4d48e9e075..526d36ca62 100644 --- a/runtime/wasm/custom.wat +++ b/runtime/wasm/custom.wat @@ -22,11 +22,11 @@ (import "int64" "int64_ops" (global $int64_ops (ref $custom_operations))) (import "bigarray" "bigarray_ops" (global $bigarray_ops (ref $custom_operations))) - (import "string" "caml_string_equal" - (func $caml_string_equal + (import "string" "caml_bytes_equal" + (func $caml_bytes_equal (param (ref eq)) (param (ref eq)) (result (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) (type $compare (func (param (ref eq)) (param (ref eq)) (param i32) (result i32))) (type $hash @@ -38,7 +38,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -109,14 +109,14 @@ (local.get $ops) (global.get $custom_operations)))) (func (export "caml_find_custom_operations") - (param $id (ref $string)) (result (ref null $custom_operations)) + (param $id (ref $bytes)) (result (ref null $custom_operations)) (local $l (ref null $custom_operations_list)) (block $not_found (local.set $l (br_on_null $not_found (global.get $custom_operations))) (loop $loop (if (i31.get_u (ref.cast (ref i31) - (call $caml_string_equal (local.get $id) + (call $caml_bytes_equal (local.get $id) (struct.get $custom_operations $id (struct.get $custom_operations_list $ops (local.get $l)))))) diff --git a/runtime/wasm/dune b/runtime/wasm/dune index 90422c0f9d..d20394961f 100644 --- a/runtime/wasm/dune +++ b/runtime/wasm/dune @@ -1,7 +1,9 @@ (install (section lib) (package wasm_of_ocaml-compiler) - (files runtime.wasm runtime.js)) + (files + (glob_files *.wat) + runtime.js)) (rule (target version-dependent.wat) @@ -28,57 +30,3 @@ (< %{ocaml_version} 5.1.0)) (action (copy %{deps} %{target}))) - -(rule - (target runtime.wasm) - (deps runtime.merged.wasm) - (action - (run - wasm-opt - -g - --enable-gc - --enable-exception-handling - --enable-reference-types - --enable-tail-call - --enable-strings - --enable-multivalue - --enable-bulk-memory - %{deps} - -O3 - -o - %{target}))) - -(rule - (target runtime.merged.wasm) - (deps - args - (glob_files *.wat)) - (action - (progn - (bash - "which wasm-merge > /dev/null || (echo 'Error: Binaryen tools not found in the PATH'; false)") - (bash - "wasm-merge --version | grep -q 'version \\(11[89]\\|1[2-9][0-9]\\)' || (echo 'Error: Binaryen version 118 or greater is currently required'; false)") - (run - wasm-merge - -g - --enable-gc - --enable-exception-handling - --enable-reference-types - --enable-tail-call - --enable-strings - --enable-multivalue - --enable-bulk-memory - %{read-lines:args} - -o - %{target})))) - -(rule - (target args) - (deps - args.ml - (glob_files *.wat)) - (action - (with-stdout-to - %{target} - (run ocaml %{deps})))) diff --git a/runtime/wasm/effect.wat b/runtime/wasm/effect.wat index f061f0800b..fe34c789a8 100644 --- a/runtime/wasm/effect.wat +++ b/runtime/wasm/effect.wat @@ -38,7 +38,8 @@ (func $resume_fiber (param externref) (param (ref eq)))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq)))) (type $closure (sub (struct (;(field i32);) (field (ref $function_1))))) (type $function_3 @@ -118,23 +119,19 @@ (field $cont (ref $cont)) (field $next (ref null $fiber))))) - (data $effect_unhandled "Effect.Unhandled") + (#string $effect_unhandled "Effect.Unhandled") (func $raise_unhandled (param $eff (ref eq)) (param (ref eq)) (result (ref eq)) - (local $effect_unhandled (ref $string)) - (local.set $effect_unhandled - (array.new_data $string $effect_unhandled - (i32.const 0) (i32.const 16))) + (local $effect_unhandled (ref $bytes)) (block $null (call $caml_raise_with_arg (br_on_null $null - (call $caml_named_value - (local.get $effect_unhandled))) + (call $caml_named_value (global.get $effect_unhandled))) (local.get $eff))) (call $caml_raise_constant (array.new_fixed $block 3 (ref.i31 (i32.const 248)) - (local.get $effect_unhandled) + (global.get $effect_unhandled) (call $caml_fresh_oo_id (ref.i31 (i32.const 0))))) (ref.i31 (i32.const 0))) @@ -215,7 +212,7 @@ (return_call_ref $cont_func (local.get $p) (local.get $k) (struct.get $cont $cont_func (local.get $k)))) - (data $already_resumed "Effect.Continuation_already_resumed") + (#string $already_resumed "Effect.Continuation_already_resumed") (func (export "%resume") (param $stack (ref eq)) (param $f (ref eq)) (param $v (ref eq)) @@ -227,8 +224,7 @@ (call $caml_raise_constant (ref.as_non_null (call $caml_named_value - (array.new_data $string $already_resumed - (i32.const 0) (i32.const 35))))))) + (global.get $already_resumed)))))) (return_call $capture_continuation (ref.func $do_resume) (struct.new $pair @@ -638,9 +634,7 @@ (return (local.get $k)))) (call $caml_raise_constant (ref.as_non_null - (call $caml_named_value - (array.new_data $string $already_resumed - (i32.const 0) (i32.const 35))))) + (call $caml_named_value (global.get $already_resumed)))) (ref.i31 (i32.const 0))) (func (export "caml_perform_effect") diff --git a/runtime/wasm/fail.wat b/runtime/wasm/fail.wat index e3dc000d55..ae69a113b5 100644 --- a/runtime/wasm/fail.wat +++ b/runtime/wasm/fail.wat @@ -21,7 +21,8 @@ (import "bindings" "jstag" (tag $javascript_exception (param externref))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (tag $ocaml_exception (export "ocaml_exception") (param (ref eq))) (export "javascript_exception" (tag $javascript_exception)) @@ -60,7 +61,7 @@ (return_call $caml_raise_with_arg (array.get $block (global.get $caml_global_data) (global.get $FAILURE_EXN)) - (local.get 0))) + (local.get $arg))) (global $INVALID_EXN i32 (i32.const 3)) @@ -71,12 +72,10 @@ (global.get $INVALID_EXN)) (local.get 0))) - (data $index_out_of_bounds "index out of bounds") + (#string $index_out_of_bounds "index out of bounds") (func (export "caml_bound_error") - (return_call $caml_invalid_argument - (array.new_data $string $index_out_of_bounds - (i32.const 0) (i32.const 19)))) + (return_call $caml_invalid_argument (global.get $index_out_of_bounds))) (global $END_OF_FILE_EXN i32 (i32.const 4)) diff --git a/runtime/wasm/float.wat b/runtime/wasm/float.wat index 50e0b200d0..92de6d33d0 100644 --- a/runtime/wasm/float.wat +++ b/runtime/wasm/float.wat @@ -16,7 +16,6 @@ ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. (module - (import "jslib" "unwrap" (func $unwrap (param (ref eq)) (result anyref))) (import "bindings" "format_float" (func $format_float (param i32) (param i32) (param i32) (param f64) (result anyref))) @@ -28,13 +27,36 @@ (func $caml_invalid_argument (param (ref eq)))) (import "ints" "lowercase_hex_table" (global $lowercase_hex_table (ref $chars))) - (import "jsstring" "jsstring_of_string" - (func $jsstring_of_string (param (ref $string)) (result anyref))) - (import "jsstring" "string_of_jsstring" - (func $string_of_jsstring (param anyref) (result (ref $string)))) + (import "jsstring" "jsstring_of_bytes" + (func $jsstring_of_bytes (param (ref $bytes)) (result anyref))) + (import "jsstring" "bytes_of_jsstring" + (func $bytes_of_jsstring (param anyref) (result (ref $bytes)))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) - (type $float (struct (field f64))) - (type $string (array (mut i8))) +(#if use-js-string +(#then + (import "wasm:js-string" "length" + (func $string_length (param externref) (result i32))) + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_length (param $s (ref $bytes)) (result i32) + (array.len (local.get $s))) + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) + + (type $float (struct (field f64))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $block (array (mut (ref eq)))) (type $chars (array i8)) @@ -55,7 +77,7 @@ (local $b i64) (local $prec i32) (local $style i32) (local $sign i32) (local $exp i32) (local $m i64) (local $i i32) (local $j i32) (local $d i32) (local $txt (ref $chars)) - (local $len i32) (local $s (ref $string)) + (local $len i32) (local $s (ref $bytes)) (local $unit i64) (local $half i64) (local $mask i64) (local $frac i64) (local.set $prec (i31.get_s (ref.cast (ref i31) (local.get 1)))) (local.set $style (i31.get_s (ref.cast (ref i31) (local.get 2)))) @@ -73,7 +95,7 @@ (i32.or (local.get $sign) (i32.ne (local.get $style) (i32.const 45)))) ;; '-' (local.set $s - (block $sign (result (ref $string)) + (block $sign (result (ref $bytes)) (if (i32.eq (local.get $exp) (i32.const 0x7FF)) (then (local.set $txt @@ -84,9 +106,9 @@ (global.get $nan)))) (local.set $len (array.len (local.get $txt))) (local.set $s - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.add (local.get $i) (local.get $len)))) - (array.copy $string $chars + (array.copy $bytes $chars (local.get $s) (local.get $i) (local.get $txt) (i32.const 0) (local.get $len)) (br $sign (local.get $s)))) @@ -144,37 +166,37 @@ (i32.add (i32.const 6) (local.get $j)))) (if (i32.eqz (local.get $prec)) (then (local.set $len (i32.sub (local.get $len) (i32.const 1))))) - (local.set $s (array.new $string (i32.const 0) (local.get $len))) + (local.set $s (array.new $bytes (i32.const 0) (local.get $len))) (if (i32.ge_s (local.get $exp) (i32.const 0)) (then (local.set $d (local.get $exp))) (else (local.set $d (i32.sub (i32.const 0) (local.get $exp))))) (loop $write (local.set $len (i32.sub (local.get $len) (i32.const 1))) - (array.set $string (local.get $s) (local.get $len) + (array.set $bytes (local.get $s) (local.get $len) (i32.add (i32.const 48) (i32.rem_u (local.get $d) (i32.const 10)))) (local.set $d (i32.div_u (local.get $d) (i32.const 10))) (br_if $write (local.get $d))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.sub (local.get $len) (i32.const 1)) (select (i32.const 43) (i32.const 45) (i32.ge_s (local.get $exp) (i32.const 0)))) - (array.set $string (local.get $s) (local.get $i) (i32.const 48)) ;; '0' - (array.set $string (local.get $s) (i32.add (local.get $i) (i32.const 1)) + (array.set $bytes (local.get $s) (local.get $i) (i32.const 48)) ;; '0' + (array.set $bytes (local.get $s) (i32.add (local.get $i) (i32.const 1)) (i32.const 120)) ;; 'x' - (array.set $string (local.get $s) (i32.add (local.get $i) (i32.const 2)) + (array.set $bytes (local.get $s) (i32.add (local.get $i) (i32.const 2)) (i32.add (i32.wrap_i64 (i64.shr_u (local.get $m) (i64.const 52))) (i32.const 48))) ;; '0' (local.set $i (i32.add (local.get $i) (i32.const 3))) (if (i32.gt_s (local.get $prec) (i32.const 0)) (then - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (i32.const 46)) ;; '.' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $frac (i64.shl (local.get $m) (i64.const 12))) (loop $write - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (array.get_u $chars (global.get $lowercase_hex_table) (i32.wrap_i64 (i64.shr_u (local.get $frac) (i64.const 60))))) @@ -182,35 +204,43 @@ (local.set $prec (i32.sub (local.get $prec) (i32.const 1))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $write (i32.gt_s (local.get $prec) (i32.const 0)))))) - (array.set $string (local.get $s) (local.get $i) (i32.const 112)) + (array.set $bytes (local.get $s) (local.get $i) (i32.const 112)) (local.get $s))) (if (local.get $sign) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 45))) ;; '-' (else (if (i32.ne (local.get $style) (i32.const 45)) ;; '-' (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (local.get $style)))))) - (local.get $s)) + (return_call $caml_string_of_bytes (local.get $s))) - (data $format_error "format_float: bad format") + (#string $format_error "format_float: bad format") (func $parse_format - (param $s (ref $string)) (result i32 i32 i32 i32) + (param $v (ref eq)) (result i32 i32 i32 i32) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $i i32) (local $len i32) (local $c i32) (local $sign_style i32) (local $precision i32) (local $conversion i32) (local $uppercase i32) - (local.set $len (array.len (local.get $s))) + (local.set $s (call $string_val (local.get $v))) + (local.set $len (call $string_length (local.get $s))) (local.set $i (i32.const 1)) (block $return (block $bad_format (br_if $bad_format (i32.lt_u (local.get $len) (i32.const 2))) (br_if $bad_format - (i32.ne (array.get_u $string (local.get $s) (i32.const 0)) + (i32.ne (call $string_get (local.get $s) (i32.const 0)) (i32.const 37))) ;; '%' - (local.set $c (array.get_u $string (local.get $s) (i32.const 1))) + (local.set $c (call $string_get (local.get $s) (i32.const 1))) (if (i32.eq (local.get $c) (i32.const 43)) ;; '+' (then (local.set $sign_style (i32.const 1)) @@ -221,13 +251,13 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))))) (br_if $bad_format (i32.eq (local.get $i) (local.get $len))) (br_if $bad_format - (i32.ne (array.get_u $string (local.get $s) (local.get $i)) + (i32.ne (call $string_get (local.get $s) (local.get $i)) (i32.const 46))) ;; '.' (loop $precision (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $bad_format (i32.eq (local.get $i) (local.get $len))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.and (i32.ge_u (local.get $c) (i32.const 48)) ;; '0' (i32.le_u (local.get $c) (i32.const 57))) ;; '9' (then @@ -243,9 +273,7 @@ (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 69))) ;; 'E' (br_if $return (i32.le_u (local.get $conversion) (i32.const 2)))) - (call $caml_invalid_argument - (array.new_data $string $format_error - (i32.const 0) (i32.const 22)))) + (call $caml_invalid_argument (global.get $format_error))) (tuple.make 4 (local.get $sign_style) (local.get $precision) @@ -264,12 +292,11 @@ (local $negative i32) (local $exp i32) (local $m i64) (local $i i32) (local $len i32) (local $c i32) - (local $s (ref $string)) (local $txt (ref $chars)) + (local $s (ref $bytes)) (local $txt (ref $chars)) (local $num anyref) (local.set $f (struct.get $float 0 (ref.cast (ref $float) (local.get 1)))) (local.set $b (i64.reinterpret_f64 (local.get $f))) - (local.set $format - (call $parse_format (ref.cast (ref $string) (local.get 0)))) + (local.set $format (call $parse_format (local.get 0))) (local.set $sign_style (tuple.extract 4 0 (local.get $format))) (local.set $precision (tuple.extract 4 1 (local.get $format))) (local.set $conversion (tuple.extract 4 2 (local.get $format))) @@ -280,7 +307,7 @@ (i32.or (local.get $negative) (i32.ne (local.get $sign_style) (i32.const 0)))) (local.set $s - (block $sign (result (ref $string)) + (block $sign (result (ref $bytes)) (local.set $exp (i32.and (i32.wrap_i64 (i64.shr_u (local.get $b) (i64.const 52))) (i32.const 0x7FF))) @@ -298,9 +325,9 @@ (global.get $nan)))) (local.set $len (array.len (local.get $txt))) (local.set $s - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.add (local.get $i) (local.get $len)))) - (array.copy $string $chars + (array.copy $bytes $chars (local.get $s) (local.get $i) (local.get $txt) (i32.const 0) (local.get $len)) (br $sign (local.get $s)))) @@ -309,52 +336,60 @@ (local.get $precision) (local.get $conversion) (local.get $i) (f64.abs (local.get $f)))) - (local.set $s (call $string_of_jsstring (local.get $num))) + (local.set $s (call $bytes_of_jsstring (local.get $num))) (br $sign (local.get $s)))) (if (local.get $negative) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 45))) ;; '-' (else (if (local.get $sign_style) (then (if (i32.eq (local.get $sign_style) (i32.const 1)) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 43))) ;; '+' (else - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 32)))))))) ;; ' ' (if (local.get $uppercase) (then (local.set $i (i32.const 0)) (local.set $len (array.len (local.get $s))) (loop $uppercase - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (array.get_u $bytes (local.get $s) (local.get $i))) (if (i32.and (i32.ge_u (local.get $c) (i32.const 97)) ;; 'a' (i32.le_u (local.get $c) (i32.const 122))) ;; 'z' (then - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (i32.sub (local.get $c) (i32.const 32))))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $uppercase (i32.lt_u (local.get $i) (local.get $len)))))) - (local.get $s)) + (return_call $caml_string_of_bytes (local.get $s))) - (data $float_of_string "float_of_string") + (#string $float_of_string "float_of_string") - (func $caml_float_of_hex (param $s (ref $string)) (param $i i32) (result f64) + (func $caml_float_of_hex +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (result f64) (local $len i32) (local $c i32) (local $d i32) (local $m i64) (local $f f64) (local $negative i32) (local $dec_point i32) (local $exp i32) (local $adj i32) (local $n_bits i32) (local $m_bits i32) (local $x_bits i32) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (local.set $dec_point (i32.const -1)) (block $error (loop $parse (if (i32.lt_u (local.get $i) (local.get $len)) (then (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.eq (local.get $c) (i32.const 46)) ;; '.' (then @@ -367,7 +402,7 @@ (then (br_if $error (i32.eq (local.get $i) (local.get $len))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.eq (local.get $c) (i32.const 45)) ;; '-' (then @@ -375,7 +410,7 @@ (br_if $error (i32.eq (local.get $i) (local.get $len))) (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))))) @@ -384,7 +419,7 @@ (br_if $error (i32.eq (local.get $i) (local.get $len))) (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))))) @@ -404,7 +439,7 @@ (if (i32.ne (local.get $i) (local.get $len)) (then (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) @@ -479,28 +514,42 @@ (if (local.get $exp) (then (local.set $f (call $ldexp (local.get $f) (local.get $exp))))) (return (local.get $f))) - (call $caml_failwith - (array.new_data $string $float_of_string (i32.const 0) (i32.const 15))) + (call $caml_failwith (global.get $float_of_string)) (f64.const 0)) - (func $on_whitespace (param $s (ref $string)) (param $i i32) (result i32) + (func $on_whitespace +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (result i32) (local $c i32) - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (call $string_get (local.get $s) (local.get $i))) (i32.or (i32.eq (local.get $c) (i32.const 32)) ;; ' ' (i32.le_u (i32.sub (local.get $c) (i32.const 9)) (i32.const 4)))) (func (export "caml_float_of_string") (param (ref eq)) (result (ref eq)) - (local $s (ref $string)) (local $len i32) (local $i i32) (local $j i32) - (local $s' (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) + (local $len i32) (local $i i32) (local $j i32) + (local $s' (ref $bytes)) (local $negative i32) (local $c i32) (local $f f64) - (local.set $s (ref.cast (ref $string) (local.get 0))) - (local.set $len (array.len (local.get $s))) + (local.set $s (call $string_val (local.get 0))) + (local.set $len (call $string_length (local.get $s))) (loop $count (if (i32.lt_u (local.get $i) (local.get $len)) (then (if (i32.eq (i32.const 95) ;; '_' - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (then (local.set $j (i32.add (local.get $j) (i32.const 1))))) (local.set $i (i32.add (local.get $i) (i32.const 1))) @@ -508,7 +557,7 @@ (if (local.get $j) (then (local.set $s' - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.sub (local.get $len) (local.get $j)))) (local.set $i (i32.const 0)) (local.set $j (i32.const 0)) @@ -516,17 +565,25 @@ (if (i32.lt_u (local.get $i) (local.get $len)) (then (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.ne (local.get $c) (i32.const 95)) ;; '_' (then - (array.set $string (local.get $s') + (array.set $bytes (local.get $s') (local.get $j) (local.get $c)) (local.set $j (i32.add (local.get $j) (i32.const 1))))) (br $copy)))) (local.set $len (array.len (local.get $s'))) - (local.set $s (local.get $s')))) +(#if use-js-string +(#then + (local.set $s + (extern.convert_any (call $jsstring_of_bytes (local.get $s')))) +) +(#else + (local.set $s (local.get $s')) +)) + )) (local.set $i (i32.const 0)) (loop $skip_spaces (if (i32.lt_u (local.get $i) (local.get $len)) @@ -540,7 +597,7 @@ (br_if $error (call $on_whitespace (local.get $s) (i32.sub (local.get $len) (i32.const 1)))) - (local.set $c (array.get_u $string (local.get $s) (i32.const 0))) + (local.set $c (call $string_get (local.get $s) (i32.const 0))) (if (i32.eq (local.get $c) (i32.const 45)) ;; '-' (then (local.set $negative (i32.const 1)) @@ -550,11 +607,11 @@ (local.set $i (i32.const 1)))) (if (i32.lt_u (i32.add (local.get $i) (i32.const 2)) (local.get $len)) (then - (if (i32.eq (array.get_u $string (local.get $s) (local.get $i)) + (if (i32.eq (call $string_get (local.get $s) (local.get $i)) (i32.const 48)) ;; '0' (then (if (i32.eq (i32.and - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.add (local.get $i) (i32.const 1))) (i32.const 0xdf)) (i32.const 88)) ;; 'X' @@ -567,17 +624,17 @@ (return (struct.new $float (local.get $f))))))))) (if (i32.eq (i32.add (local.get $i) (i32.const 3)) (local.get $len)) (then - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 78)) (then ;; 'N' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 65)) (then ;; 'A' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 78)) ;; 'N' (then @@ -587,12 +644,12 @@ (i32.const 73)) (then ;; 'I' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 78)) (then ;; 'N' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 70)) ;; 'F' (then @@ -604,34 +661,34 @@ (local.get $negative)))))))))))) (if (i32.eq (i32.add (local.get $i) (i32.const 8)) (local.get $len)) (then - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 73)) (then ;; 'I' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 78)) (then ;; 'N' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 70)) (then ;; 'F' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))) + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 73)) (then ;; 'I' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) (i32.const 78)) (then ;; 'N' (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) @@ -639,7 +696,7 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) (i32.const 0xdf)) @@ -647,7 +704,7 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $c - (array.get_u $string + (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (i32.and (local.get $c) @@ -661,11 +718,18 @@ (local.get $negative)))) )))))))))))))))))) (local.set $f - (call $parse_float (call $jsstring_of_string (local.get $s)))) + (call $parse_float +(#if use-js-string +(#then + (any.convert_extern (local.get $s)) +) +(#else + (call $jsstring_of_bytes (local.get $s)) +)) + )) (br_if $error (f64.ne (local.get $f) (local.get $f))) (return (struct.new $float (local.get $f)))) - (call $caml_failwith - (array.new_data $string $float_of_string (i32.const 0) (i32.const 15))) + (call $caml_failwith (global.get $float_of_string)) (return (ref.i31 (i32.const 0)))) (func (export "caml_nextafter_float") diff --git a/runtime/wasm/fs.wat b/runtime/wasm/fs.wat index f01d5612d0..203f90c8ae 100644 --- a/runtime/wasm/fs.wat +++ b/runtime/wasm/fs.wat @@ -16,7 +16,6 @@ ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. (module - (import "jslib" "log_str" (func $log_str (param (ref $string)))) (import "bindings" "getcwd" (func $getcwd (result anyref))) (import "bindings" "chdir" (func $chdir (param anyref))) (import "bindings" "mkdir" (func $mkdir (param anyref) (param i32))) @@ -42,8 +41,11 @@ (tag $javascript_exception (param externref))) (import "sys" "caml_handle_sys_error" (func $caml_handle_sys_error (param externref))) + (import "string" "caml_string_concat" + (func $caml_string_concat (param (ref eq) (ref eq)) (result (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (func (export "caml_sys_getcwd") (param (ref eq)) (result (ref eq)) @@ -109,23 +111,12 @@ (return_call $file_exists (call $unwrap (call $caml_jsstring_of_string (local.get $name))))) - (data $no_such_file ": No such file or directory") - - (func $caml_raise_no_such_file (param $vname (ref eq)) - (local $name (ref $string)) (local $msg (ref $string)) - (local $len i32) - (local.set $name (ref.cast (ref $string) (local.get $vname))) - (local.set $len (array.len (local.get $name))) - (local.set $msg - (array.new $string (i32.const 0) - (i32.add (local.get $len) (i32.const 27)))) - (array.copy $string $string - (local.get $msg) (i32.const 0) - (local.get $name) (i32.const 0) - (local.get $len)) - (array.init_data $string $no_such_file - (local.get $msg) (local.get $len) (i32.const 0) (i32.const 27)) - (call $caml_raise_sys_error (local.get $msg))) + (#string $no_such_file ": No such file or directory") + + (func $caml_raise_no_such_file (param $name (ref eq)) + (call $caml_raise_sys_error + (call $caml_string_concat + (local.get $name) (global.get $no_such_file)))) (data $caml_read_file_content "caml_read_file_content") diff --git a/runtime/wasm/hash.wat b/runtime/wasm/hash.wat index 543df44919..c6c5630e76 100644 --- a/runtime/wasm/hash.wat +++ b/runtime/wasm/hash.wat @@ -24,7 +24,8 @@ (func $jsstring_hash (param i32) (param anyref) (result i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $float (struct (field f64))) (type $js (struct (field anyref))) @@ -39,7 +40,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -109,8 +110,8 @@ (then (local.set $i (i32.const 0)))) (return_call $caml_hash_mix_int (local.get $h) (local.get $i))) - (func $caml_hash_mix_string (export "caml_hash_mix_string") - (param $h i32) (param $s (ref $string)) (result i32) + (func $caml_hash_mix_bytes + (param $h i32) (param $s (ref $bytes)) (result i32) (local $i i32) (local $len i32) (local $w i32) (local.set $len (array.len (local.get $s))) (local.set $i (i32.const 0)) @@ -122,15 +123,15 @@ (local.get $h) (i32.or (i32.or - (array.get_u $string (local.get $s) (local.get $i)) - (i32.shl (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (local.get $i)) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $i) (i32.const 1))) (i32.const 8))) (i32.or - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $i) (i32.const 2))) (i32.const 16)) - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $i) (i32.const 3))) (i32.const 24)))))) (local.set $i (i32.add (local.get $i) (i32.const 4))) @@ -143,20 +144,36 @@ (br_table $0_bytes $1_byte $2_bytes $3_bytes (i32.and (local.get $len) (i32.const 3)))) (local.set $w - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $i) (i32.const 2))) (i32.const 16)))) (local.set $w (i32.or (local.get $w) - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $i) (i32.const 1))) (i32.const 8))))) (local.set $w (i32.or (local.get $w) - (array.get_u $string (local.get $s) (local.get $i)))) + (array.get_u $bytes (local.get $s) (local.get $i)))) (local.set $h (call $caml_hash_mix_int (local.get $h) (local.get $w)))) (i32.xor (local.get $h) (local.get $len))) + (func $caml_hash_mix_string + (param $h i32) (param $s (ref $string)) (result i32) + (return_call $jsstring_hash + (local.get $h) (struct.get $js 0 (local.get $s)))) + +(; +(#if use-js-string +(#then + (export "caml_hash_mix_string" (func $caml_hash_mix_string)) +) +(#else + (export "caml_hash_mix_string" (func $caml_hash_mix_bytes)) +)) +;) + (export "caml_hash_mix_string" (func $caml_hash_mix_bytes)) ;; ZZZ Fix base + (global $HASH_QUEUE_SIZE i32 (i32.const 256)) (global $MAX_FORWARD_DEREFERENCE i32 (i32.const 1000)) @@ -205,10 +222,10 @@ (i32.const 1)))) (local.set $num (i32.sub (local.get $num) (i32.const 1))) (br $loop))) - (drop (block $not_string (result (ref eq)) + (drop (block $not_bytes (result (ref eq)) (local.set $h - (call $caml_hash_mix_string (local.get $h) - (br_on_cast_fail $not_string (ref eq) (ref $string) + (call $caml_hash_mix_bytes (local.get $h) + (br_on_cast_fail $not_bytes (ref eq) (ref $bytes) (local.get $v)))) (local.set $num (i32.sub (local.get $num) (i32.const 1))) (br $loop))) @@ -312,6 +329,8 @@ (ref.i31 (i32.and (call $caml_hash_mix_final (local.get $h)) (i32.const 0x3FFFFFFF)))) +(#if use-js-string +(#then (func (export "caml_string_hash") (param (ref eq)) (param (ref eq)) (result (ref eq)) (local $h i32) @@ -323,3 +342,16 @@ (ref.cast (ref $string) (local.get 1)))) (i32.const 0x3FFFFFFF)))) ) +(#else + (func (export "caml_string_hash") + (param (ref eq)) (param (ref eq)) (result (ref eq)) + (local $h i32) + (ref.i31 + (i32.and + (call $caml_hash_mix_final + (call $caml_hash_mix_bytes + (i31.get_s (ref.cast (ref i31) (local.get 0))) + (ref.cast (ref $bytes) (local.get 1)))) + (i32.const 0x3FFFFFFF)))) +)) +) diff --git a/runtime/wasm/int32.wat b/runtime/wasm/int32.wat index 79ce5095d8..a1d362df1d 100644 --- a/runtime/wasm/int32.wat +++ b/runtime/wasm/int32.wat @@ -18,7 +18,7 @@ (module (import "ints" "parse_int" (func $parse_int - (param (ref eq)) (param i32) (param (ref $string)) (result i32))) + (param (ref eq)) (param i32) (param (ref eq)) (result i32))) (import "ints" "format_int" (func $format_int (param (ref eq)) (param i32) (param i32) (result (ref eq)))) @@ -32,7 +32,8 @@ (import "marshal" "caml_deserialize_int_4" (func $caml_deserialize_int_4 (param (ref eq)) (result i32))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $compare (func (param (ref eq)) (param (ref eq)) (param i32) (result i32))) (type $hash @@ -44,7 +45,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -56,7 +57,7 @@ (global $int32_ops (export "int32_ops") (ref $custom_operations) (struct.new $custom_operations - (array.new_fixed $string 2 (i32.const 95) (i32.const 105)) ;; "_i" + (array.new_fixed $bytes 2 (i32.const 95) (i32.const 105)) ;; "_i" (ref.func $int32_cmp) (ref.null $compare) (ref.func $int32_hash) @@ -117,12 +118,7 @@ (i32.rotl (i32.and (local.get $i) (i32.const 0xFF00FF00)) (i32.const 8)))) - (global $INT32_ERRMSG (ref $string) - (array.new_fixed $string 15 ;; "Int32.of_string" - (i32.const 73) (i32.const 110) (i32.const 116) (i32.const 51) - (i32.const 50) (i32.const 46) (i32.const 111) (i32.const 102) - (i32.const 95) (i32.const 115) (i32.const 116) (i32.const 114) - (i32.const 105) (i32.const 110) (i32.const 103))) + (#string $INT32_ERRMSG "Int32.of_string") (func (export "caml_int32_of_string") (param $v (ref eq)) (result (ref eq)) (return_call $caml_copy_int32 @@ -137,7 +133,7 @@ (global $nativeint_ops (export "nativeint_ops") (ref $custom_operations) (struct.new $custom_operations - (array.new_fixed $string 2 (i32.const 95) (i32.const 110)) ;; "_n" + (array.new_fixed $bytes 2 (i32.const 95) (i32.const 110)) ;; "_n" (ref.func $int32_cmp) (ref.null $compare) (ref.func $int32_hash) @@ -153,15 +149,12 @@ (struct.get $int32 1 (ref.cast (ref $int32) (local.get $v)))) (tuple.make 2 (i32.const 4) (i32.const 8))) - (data $integer_too_large "input_value: native integer value too large") + (#string $integer_too_large "input_value: native integer value too large") (func $nativeint_deserialize (param $s (ref eq)) (result (ref eq)) (result i32) (if (i32.ne (call $caml_deserialize_uint_1 (local.get $s)) (i32.const 1)) - (then - (call $caml_failwith - (array.new_data $string $integer_too_large - (i32.const 0) (i32.const 43))))) + (then (call $caml_failwith (global.get $integer_too_large)))) (tuple.make 2 (struct.new $int32 (global.get $nativeint_ops) (call $caml_deserialize_int_4 (local.get $s))) @@ -171,12 +164,7 @@ (param $i i32) (result (ref eq)) (struct.new $int32 (global.get $nativeint_ops) (local.get $i))) - (global $NATIVEINT_ERRMSG (ref $string) - (array.new_fixed $string 16 ;; "Nativeint.of_string" - (i32.const 78) (i32.const 97) (i32.const 116) (i32.const 105) - (i32.const 118) (i32.const 101) (i32.const 46) (i32.const 111) - (i32.const 102) (i32.const 95) (i32.const 115) (i32.const 116) - (i32.const 114) (i32.const 105) (i32.const 110) (i32.const 103))) + (#string $NATIVEINT_ERRMSG "Nativeint.of_string") (func (export "caml_nativeint_of_string") (param $v (ref eq)) (result (ref eq)) diff --git a/runtime/wasm/int64.wat b/runtime/wasm/int64.wat index de7e64c52b..e7926a1065 100644 --- a/runtime/wasm/int64.wat +++ b/runtime/wasm/int64.wat @@ -18,11 +18,25 @@ (module (import "ints" "parse_sign_and_base" (func $parse_sign_and_base - (param (ref $string)) (result i32 i32 i32 i32))) +(#if use-js-string +(#then + (param externref) +) +(#else + (param (ref $bytes)) +)) + (result i32 i32 i32 i32))) (import "ints" "parse_digit" (func $parse_digit (param i32) (result i32))) (import "ints" "parse_int_format" (func $parse_int_format - (param (ref $string)) (result i32 i32 i32 i32 i32))) +(#if use-js-string +(#then + (param externref) +) +(#else + (param (ref $bytes)) +)) + (result i32 i32 i32 i32 i32))) (import "fail" "caml_failwith" (func $caml_failwith (param (ref eq)))) (import "marshal" "caml_serialize_int_8" (func $caml_serialize_int_8 (param (ref eq)) (param i64))) @@ -32,8 +46,31 @@ (global $lowercase_hex_table (ref $chars))) (import "ints" "uppercase_hex_table" (global $uppercase_hex_table (ref $chars))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) + +(#if use-js-string +(#then + (import "wasm:js-string" "length" + (func $string_length (param externref) (result i32))) + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_length (param $s (ref $bytes)) (result i32) + (array.len (local.get $s))) + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $compare (func (param (ref eq)) (param (ref eq)) (param i32) (result i32))) (type $hash @@ -45,7 +82,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -57,7 +94,7 @@ (global $int64_ops (export "int64_ops") (ref $custom_operations) (struct.new $custom_operations - (array.new_fixed $string 2 (i32.const 95) (i32.const 106)) ;; "_j" + (array.new_fixed $bytes 2 (i32.const 95) (i32.const 106)) ;; "_j" (ref.func $int64_cmp) (ref.null $compare) (ref.func $int64_hash) @@ -128,12 +165,7 @@ (ref.i31 (i32.sub (i64.gt_s (local.get $i1) (local.get $i2)) (i64.lt_s (local.get $i1) (local.get $i2))))) - (global $INT64_ERRMSG (ref $string) - (array.new_fixed $string 15 ;; "Int64.of_string" - (i32.const 73) (i32.const 110) (i32.const 116) (i32.const 54) - (i32.const 52) (i32.const 46) (i32.const 111) (i32.const 102) - (i32.const 95) (i32.const 115) (i32.const 116) (i32.const 114) - (i32.const 105) (i32.const 110) (i32.const 103))) + (#string $INT64_ERRMSG "Int64.of_string") ;; Parse a sequence of digits into an i64 as dicted by $base, ;; $signedness and $sign. The sequence is read in $s starting from $i. @@ -142,17 +174,24 @@ ;; package "integers". (func $caml_i64_of_digits (export "caml_i64_of_digits") (param $base i32) (param $signedness i32) (param $sign i32) - (param $s (ref $string)) (param $i i32) (param $errmsg (ref $string)) +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (param $errmsg (ref eq)) (result i64) (local $len i32) (local $d i32) (local $c i32) (local $res i64) (local $threshold i64) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (if (i32.eqz (local.get $len)) (then (call $caml_failwith (local.get $errmsg)))) (local.set $threshold (i64.div_u (i64.const -1) (i64.extend_i32_u (local.get $base)))) (local.set $d - (call $parse_digit (array.get_u $string (local.get $s) (local.get $i)))) + (call $parse_digit (call $string_get (local.get $s) (local.get $i)))) (if (i32.ge_u (local.get $d) (local.get $base)) (then (call $caml_failwith (local.get $errmsg)))) (local.set $res (i64.extend_i32_u (local.get $d))) @@ -160,7 +199,7 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.lt_s (local.get $i) (local.get $len)) (then - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (call $string_get (local.get $s) (local.get $i))) (br_if $loop (i32.eq (local.get $c) (i32.const 95))) ;; '_' (local.set $d (call $parse_digit (local.get $c))) (if (i32.ge_u (local.get $d) (local.get $base)) @@ -191,10 +230,16 @@ (local.get $res)) (func (export "caml_int64_of_string") (param $v (ref eq)) (result (ref eq)) - (local $s (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $i i32) (local $signedness i32) (local $sign i32) (local $base i32) (local $t (tuple i32 i32 i32 i32)) - (local.set $s (ref.cast (ref $string) (local.get $v))) + (local.set $s (call $string_val (local.get $v))) (local.set $t (call $parse_sign_and_base (local.get $s))) (local.set $i (tuple.extract 4 0 (local.get $t))) (local.set $signedness (tuple.extract 4 1 (local.get $t))) @@ -212,7 +257,7 @@ (data $caml_int64_create_lo_mi_hi "caml_int64_create_lo_mi_hi") (func $format_int64_default (param $d i64) (result (ref eq)) - (local $s (ref $string)) + (local $s (ref $bytes)) (local $negative i32) (local $i i32) (local $n i64) (if (i64.lt_s (local.get $d) (i64.const 0)) (then @@ -224,26 +269,33 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $n (i64.div_u (local.get $n) (i64.const 10))) (br_if $count (i64.ne (local.get $n) (i64.const 0)))) - (local.set $s (array.new $string (i32.const 0) (local.get $i))) + (local.set $s (array.new $bytes (i32.const 0) (local.get $i))) (loop $write (local.set $i (i32.sub (local.get $i) (i32.const 1))) - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (i32.add (i32.const 48) (i32.wrap_i64 (i64.rem_u (local.get $d) (i64.const 10))))) (local.set $d (i64.div_u (local.get $d) (i64.const 10))) (br_if $write (i64.ne (local.get $d) (i64.const 0)))) (if (local.get $negative) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 45)))) ;; '-' - (local.get $s)) + (return_call $caml_string_of_bytes (local.get $s))) (type $chars (array i8)) (func (export "caml_int64_format") (param (ref eq)) (param (ref eq)) (result (ref eq)) (local $d i64) - (local $s (ref $string)) +(#if use-js-string +(#then + (local $fmt externref) +) +(#else + (local $fmt (ref $bytes)) +)) + (local $s (ref $bytes)) (local $format (tuple i32 i32 i32 i32 i32)) (local $sign_style i32) (local $alternate i32) (local $signed i32) (local $base i64) (local $uppercase i32) @@ -251,14 +303,14 @@ (local $i i32) (local $n i64) (local $chars (ref $chars)) - (local.set $s (ref.cast (ref $string) (local.get 0))) + (local.set $fmt (call $string_val (local.get 0))) (local.set $d (struct.get $int64 1 (ref.cast (ref $int64) (local.get 1)))) - (if (i32.eq (array.len (local.get $s)) (i32.const 2)) + (if (i32.eq (call $string_length (local.get $fmt)) (i32.const 2)) (then - (if (i32.eq (array.get_u $string (local.get $s) (i32.const 1)) + (if (i32.eq (call $string_get (local.get $fmt) (i32.const 1)) (i32.const 100)) ;; 'd' (then (return_call $format_int64_default (local.get $d)))))) - (local.set $format (call $parse_int_format (local.get $s))) + (local.set $format (call $parse_int_format (local.get $fmt))) (local.set $sign_style (tuple.extract 5 0 (local.get $format))) (local.set $alternate (tuple.extract 5 1 (local.get $format))) (local.set $signed (tuple.extract 5 2 (local.get $format))) @@ -293,39 +345,39 @@ (global.get $uppercase_hex_table) (global.get $lowercase_hex_table) (local.get $uppercase))) - (local.set $s (array.new $string (i32.const 0) (local.get $i))) + (local.set $s (array.new $bytes (i32.const 0) (local.get $i))) (loop $write (local.set $i (i32.sub (local.get $i) (i32.const 1))) - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (array.get_u $chars (local.get $chars) (i32.wrap_i64 (i64.rem_u (local.get $d) (local.get $base))))) (local.set $d (i64.div_u (local.get $d) (local.get $base))) (br_if $write (i64.ne (local.get $d) (i64.const 0)))) (if (local.get $negative) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 45))) ;; '-' (else (if (local.get $sign_style) (then (if (i32.eq (local.get $sign_style) (i32.const 1)) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 43))) ;; '+' (else - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 32)))))))) ;; ' ' (if (local.get $alternate) (then (if (local.get $i) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 48)) ;; '0' (if (i64.eq (local.get $base) (i64.const 16)) (then - (array.set $string (local.get $s) (i32.const 1) + (array.set $bytes (local.get $s) (i32.const 1) (select (i32.const 88) (i32.const 120) ;; 'X' 'x' (local.get $uppercase))))))))) - (local.get $s)) + (return_call $caml_string_of_bytes (local.get $s))) ) diff --git a/runtime/wasm/ints.wat b/runtime/wasm/ints.wat index 1744e733f7..65f8a205b8 100644 --- a/runtime/wasm/ints.wat +++ b/runtime/wasm/ints.wat @@ -19,8 +19,31 @@ (import "fail" "caml_failwith" (func $caml_failwith (param (ref eq)))) (import "fail" "caml_invalid_argument" (func $caml_invalid_argument (param (ref eq)))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) - (type $string (array (mut i8))) +(#if use-js-string +(#then + (import "wasm:js-string" "length" + (func $string_length (param externref) (result i32))) + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_length (param $s (ref $bytes)) (result i32) + (array.len (local.get $s))) + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) + + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (func (export "caml_format_int") (param (ref eq)) (param (ref eq)) (result (ref eq)) @@ -29,17 +52,24 @@ (i31.get_s (ref.cast (ref i31) (local.get 1))) (i32.const 1))) (func $parse_sign_and_base (export "parse_sign_and_base") - (param $s (ref $string)) (result i32 i32 i32 i32) +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (result i32 i32 i32 i32) (local $i i32) (local $len i32) (local $c i32) (local $signedness i32) (local $sign i32) (local $base i32) (local.set $i (i32.const 0)) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (local.set $signedness (i32.const 1)) (local.set $sign (i32.const 1)) (local.set $base (i32.const 10)) (if (i32.ne (local.get $len) (i32.const 0)) (then - (local.set $c (array.get_u $string (local.get $s) (i32.const 0))) + (local.set $c (call $string_get (local.get $s) (i32.const 0))) (if (i32.eq (local.get $c) (i32.const 45)) (then (local.set $sign (i32.const -1)) @@ -47,11 +77,11 @@ (else (if (i32.eq (local.get $c) (i32.const 43)) (then (local.set $i (i32.const 1)))))))) (if (i32.lt_s (i32.add (local.get $i) (i32.const 1)) (local.get $len)) - (then (if (i32.eq (array.get_u $string (local.get $s) (local.get $i)) + (then (if (i32.eq (call $string_get (local.get $s) (local.get $i)) (i32.const 48)) (then (local.set $c - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.add (local.get $i) (i32.const 1)))) (if (i32.or (i32.eq (local.get $c) (i32.const 88)) (i32.eq (local.get $c) (i32.const 120))) @@ -94,15 +124,21 @@ (return (i32.const -1))) (func $parse_int (export "parse_int") - (param $v (ref eq)) (param $nbits i32) (param $errmsg (ref $string)) + (param $v (ref eq)) (param $nbits i32) (param $errmsg (ref eq)) (result i32) - (local $s (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $i i32) (local $len i32) (local $d i32) (local $c i32) (local $signedness i32) (local $sign i32) (local $base i32) (local $res i32) (local $threshold i32) (local $t (tuple i32 i32 i32 i32)) - (local.set $s (ref.cast (ref $string) (local.get $v))) - (local.set $len (array.len (local.get $s))) + (local.set $s (call $string_val (local.get $v))) + (local.set $len (call $string_length (local.get $s))) (if (i32.eqz (local.get $len)) (then (call $caml_failwith (local.get $errmsg)))) (local.set $t (call $parse_sign_and_base (local.get $s))) @@ -114,7 +150,7 @@ (if (i32.ge_s (local.get $i) (local.get $len)) (then (call $caml_failwith (local.get $errmsg)))) (local.set $d - (call $parse_digit (array.get_u $string (local.get $s) (local.get $i)))) + (call $parse_digit (call $string_get (local.get $s) (local.get $i)))) (if (i32.ge_u (local.get $d) (local.get $base)) (then (call $caml_failwith (local.get $errmsg)))) (local.set $res (local.get $d)) @@ -122,7 +158,7 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.lt_s (local.get $i) (local.get $len)) (then - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (call $string_get (local.get $s) (local.get $i))) (br_if $loop (i32.eq (local.get $c) (i32.const 95))) ;; '_' (local.set $d (call $parse_digit (local.get $c))) (if (i32.ge_u (local.get $d) (local.get $base)) @@ -157,12 +193,7 @@ (then (local.set $res (i32.sub (i32.const 0) (local.get $res))))) (local.get $res)) - (global $INT_ERRMSG (ref $string) - (array.new_fixed $string 13 ;; "int.of_string" - (i32.const 105) (i32.const 110) (i32.const 116) (i32.const 95) - (i32.const 111) (i32.const 102) (i32.const 95) (i32.const 115) - (i32.const 116) (i32.const 114) (i32.const 105) (i32.const 110) - (i32.const 103))) + (#string $INT_ERRMSG "int_of_string") (func (export "caml_int_of_string") (param $v (ref eq)) (result (ref eq)) @@ -196,7 +227,7 @@ (i32.const 67) (i32.const 68) (i32.const 69) (i32.const 70))) (func $format_int_default (param $d i32) (result (ref eq)) - (local $s (ref $string)) + (local $s (ref $bytes)) (local $negative i32) (local $i i32) (local $n i32) (if (i32.lt_s (local.get $d) (i32.const 0)) (then @@ -208,36 +239,43 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (local.set $n (i32.div_u (local.get $n) (i32.const 10))) (br_if $count (local.get $n))) - (local.set $s (array.new $string (i32.const 0) (local.get $i))) + (local.set $s (array.new $bytes (i32.const 0) (local.get $i))) (loop $write (local.set $i (i32.sub (local.get $i) (i32.const 1))) - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (i32.add (i32.const 48) (i32.rem_u (local.get $d) (i32.const 10)))) (local.set $d (i32.div_u (local.get $d) (i32.const 10))) (br_if $write (local.get $d))) (if (local.get $negative) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 45)))) ;; '-' - (local.get $s)) + (return_call $caml_string_of_bytes (local.get $s))) - (data $format_error "format_int: bad format") + (#string $format_error "format_int: bad format") (func $parse_int_format (export "parse_int_format") - (param $s (ref $string)) (result i32 i32 i32 i32 i32) +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (result i32 i32 i32 i32 i32) (local $i i32) (local $len i32) (local $c i32) (local $sign_style i32) (local $alternate i32) (local $base i32) (local $signed i32) (local $uppercase i32) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (local.set $i (i32.const 1)) (block $return (block $bad_format (br_if $bad_format (i32.lt_u (local.get $len) (i32.const 2))) (br_if $bad_format - (i32.ne (array.get_u $string (local.get $s) (i32.const 0)) + (i32.ne (call $string_get (local.get $s) (i32.const 0)) (i32.const 37))) ;; '%' - (local.set $c (array.get_u $string (local.get $s) (i32.const 1))) + (local.set $c (call $string_get (local.get $s) (i32.const 1))) (if (i32.eq (local.get $c) (i32.const 43)) ;; '+' (then (local.set $sign_style (i32.const 1)) @@ -251,7 +289,7 @@ (local.set $alternate (i32.const 1)) (local.set $i (i32.add (local.get $i) (i32.const 1))))) (br_if $bad_format (i32.eq (local.get $i) (local.get $len))) - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) + (local.set $c (call $string_get (local.get $s) (local.get $i))) (if (i32.or (i32.or (i32.eq (local.get $c) (i32.const 76)) ;; 'L' (i32.eq (local.get $c) (i32.const 108))) ;; 'l' (i32.eq (local.get $c) (i32.const 110))) ;; 'n' @@ -259,7 +297,7 @@ (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $bad_format (i32.eq (local.get $i) (local.get $len))) (local.set $c - (array.get_u $string (local.get $s) (local.get $i))))) + (call $string_get (local.get $s) (local.get $i))))) (br_if $bad_format (i32.ne (i32.add (local.get $i) (i32.const 1)) (local.get $len))) (if (i32.or (i32.eq (local.get $c) (i32.const 100)) ;; 'd' @@ -283,9 +321,7 @@ (else (br $bad_format))))))))))) (br $return)) - (call $caml_invalid_argument - (array.new_data $string $format_error - (i32.const 0) (i32.const 22)))) + (call $caml_invalid_argument (global.get $format_error))) (tuple.make 5 (local.get $sign_style) (local.get $alternate) @@ -295,7 +331,14 @@ (func $format_int (export "format_int") (param (ref eq)) (param $d i32) (param $small i32) (result (ref eq)) - (local $s (ref $string)) +(#if use-js-string +(#then + (local $fmt externref) +) +(#else + (local $fmt (ref $bytes)) +)) + (local $s (ref $bytes)) (local $format (tuple i32 i32 i32 i32 i32)) (local $sign_style i32) (local $alternate i32) (local $signed i32) (local $base i32) (local $uppercase i32) @@ -303,13 +346,13 @@ (local $i i32) (local $n i32) (local $chars (ref $chars)) - (local.set $s (ref.cast (ref $string) (local.get 0))) - (if (i32.eq (array.len (local.get $s)) (i32.const 2)) + (local.set $fmt (call $string_val (local.get 0))) + (if (i32.eq (call $string_length (local.get $fmt)) (i32.const 2)) (then - (if (i32.eq (array.get_u $string (local.get $s) (i32.const 1)) + (if (i32.eq (call $string_get (local.get $fmt) (i32.const 1)) (i32.const 100)) ;; 'd' (then (return_call $format_int_default (local.get $d)))))) - (local.set $format (call $parse_int_format (local.get $s))) + (local.set $format (call $parse_int_format (local.get $fmt))) (local.set $sign_style (tuple.extract 5 0 (local.get $format))) (local.set $alternate (tuple.extract 5 1 (local.get $format))) (local.set $signed (tuple.extract 5 2 (local.get $format))) @@ -350,38 +393,38 @@ (global.get $uppercase_hex_table) (global.get $lowercase_hex_table) (local.get $uppercase))) - (local.set $s (array.new $string (i32.const 0) (local.get $i))) + (local.set $s (array.new $bytes (i32.const 0) (local.get $i))) (loop $write (local.set $i (i32.sub (local.get $i) (i32.const 1))) - (array.set $string (local.get $s) (local.get $i) + (array.set $bytes (local.get $s) (local.get $i) (array.get_u $chars (local.get $chars) (i32.rem_u (local.get $d) (local.get $base)))) (local.set $d (i32.div_u (local.get $d) (local.get $base))) (br_if $write (local.get $d))) (if (local.get $negative) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 45))) ;; '-' (else (if (local.get $sign_style) (then (if (i32.eq (local.get $sign_style) (i32.const 1)) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 43))) ;; '+' (else - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 32)))))))) ;; ' ' (if (local.get $alternate) (then (if (local.get $i) (then - (array.set $string (local.get $s) (i32.const 0) + (array.set $bytes (local.get $s) (i32.const 0) (i32.const 48)) ;; '0' (if (i32.eq (local.get $base) (i32.const 16)) (then - (array.set $string (local.get $s) (i32.const 1) + (array.set $bytes (local.get $s) (i32.const 1) (select (i32.const 88) (i32.const 120) ;; 'X' 'x' (local.get $uppercase))))))))) - (local.get $s)) + (return_call $caml_string_of_bytes (local.get $s))) ) diff --git a/runtime/wasm/io.wat b/runtime/wasm/io.wat index 76e02a2d39..3fcc28b120 100644 --- a/runtime/wasm/io.wat +++ b/runtime/wasm/io.wat @@ -55,13 +55,17 @@ (func $ta_set_ui8 (param (ref extern)) (param i32) (param i32))) ;; ZZZ ?? (import "bindings" "ta_get_ui8" (func $ta_get_ui8 (param (ref extern)) (param i32) (result i32))) + (import "bindings" "ta_blit_from_bytes" + (func $ta_blit_from_bytes + (param (ref $bytes)) (param i32) (param (ref extern)) (param i32) + (param i32))) + (import "bindings" "ta_blit_to_bytes" + (func $ta_blit_to_bytes + (param (ref extern)) (param i32) (param (ref $bytes)) (param i32) + (param i32))) (import "bindings" "ta_blit_from_string" (func $ta_blit_from_string - (param (ref $string)) (param i32) (param (ref extern)) (param i32) - (param i32))) - (import "bindings" "ta_blit_to_string" - (func $ta_blit_to_string - (param (ref extern)) (param i32) (param (ref $string)) (param i32) + (param anyref) (param i32) (param (ref extern)) (param i32) (param i32))) (import "custom" "custom_compare_id" (func $custom_compare_id @@ -77,6 +81,8 @@ (tag $javascript_exception (param externref))) (import "sys" "caml_handle_sys_error" (func $caml_handle_sys_error (param externref))) + (import "string" "caml_bytes_of_string" + (func $caml_bytes_of_string (param (ref eq)) (result (ref eq)))) (import "bindings" "map_new" (func $map_new (result (ref extern)))) (import "bindings" "map_get" @@ -89,7 +95,8 @@ (func $map_delete (param (ref extern)) (param i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $offset_array (array (mut i64))) (type $compare @@ -103,7 +110,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -120,7 +127,7 @@ (global $channel_ops (ref $custom_operations) (struct.new $custom_operations - (array.new_fixed $string 5 ;; "_chan" + (array.new_fixed $bytes 5 ;; "_chan" (i32.const 95) (i32.const 99) (i32.const 104) (i32.const 97) (i32.const 110)) (ref.func $custom_compare_id) @@ -351,7 +358,7 @@ (return (call $ta_get_ui8 (local.get $buf) (i32.const 0)))) (func $caml_getblock (export "caml_getblock") - (param $vch (ref eq)) (param $s (ref $string)) + (param $vch (ref eq)) (param $s (ref $bytes)) (param $pos i32) (param $len i32) (result i32) (local $ch (ref $channel)) @@ -367,7 +374,7 @@ (then (if (i32.gt_u (local.get $len) (local.get $avail)) (then (local.set $len (local.get $avail)))) - (call $ta_blit_to_string + (call $ta_blit_to_bytes (struct.get $channel $buffer (local.get $ch)) (struct.get $channel $curr (local.get $ch)) (local.get $s) (local.get $pos) @@ -382,7 +389,7 @@ (struct.set $channel $max (local.get $ch) (local.get $nread)) (if (i32.gt_u (local.get $len) (local.get $nread)) (then (local.set $len (local.get $nread)))) - (call $ta_blit_to_string + (call $ta_blit_to_bytes (struct.get $channel $buffer (local.get $ch)) (i32.const 0) (local.get $s) (local.get $pos) @@ -391,7 +398,7 @@ (local.get $len)) (func (export "caml_really_getblock") - (param $ch (ref eq)) (param $s (ref $string)) + (param $ch (ref eq)) (param $s (ref $bytes)) (param $pos i32) (param $len i32) (result i32) (local $read i32) (local $n i32) @@ -412,12 +419,12 @@ (func (export "caml_ml_input") (param $vch (ref eq)) (param $vs (ref eq)) (param $vpos (ref eq)) (param $vlen (ref eq)) (result (ref eq)) - (local $ch (ref $channel)) (local $s (ref $string)) + (local $ch (ref $channel)) (local $s (ref $bytes)) (local $pos i32) (local $len i32) (local $curr i32) (local $i i32) (local $avail i32) (local $nread i32) (local $buf (ref extern)) (local.set $ch (ref.cast (ref $channel) (local.get $vch))) - (local.set $s (ref.cast (ref $string) (local.get $vs))) + (local.set $s (ref.cast (ref $bytes) (local.get $vs))) (local.set $pos (i31.get_u (ref.cast (ref i31) (local.get $vpos)))) (local.set $len (i31.get_u (ref.cast (ref i31) (local.get $vlen)))) (local.set $buf (struct.get $channel $buffer (local.get $ch))) @@ -438,7 +445,7 @@ (local.set $curr (i32.const 0)) (if (i32.gt_u (local.get $len) (local.get $nread)) (then (local.set $len (local.get $nread)))))))) - (call $ta_blit_to_string + (call $ta_blit_to_bytes (local.get $buf) (local.get $curr) (local.get $s) (local.get $pos) (local.get $len)) (struct.set $channel $curr (local.get $ch) @@ -721,7 +728,27 @@ (i32.eqz (local.get $towrite))) (func $caml_putblock - (param $ch (ref $channel)) (param $s (ref $string)) (param $pos i32) + (param $ch (ref $channel)) (param $s (ref $bytes)) (param $pos i32) + (param $len i32) (result i32) + (local $free i32) (local $curr i32) + (local $buf (ref extern)) + (local.set $curr (struct.get $channel $curr (local.get $ch))) + (local.set $free + (i32.sub (struct.get $channel $size (local.get $ch)) (local.get $curr))) + (if (i32.ge_u (local.get $len) (local.get $free)) + (then (local.set $len (local.get $free)))) + (local.set $buf (struct.get $channel $buffer (local.get $ch))) + (call $ta_blit_from_bytes + (local.get $s) (local.get $pos) + (local.get $buf) (local.get $curr) (local.get $len)) + (struct.set $channel $curr (local.get $ch) + (i32.add (local.get $curr) (local.get $len))) + (if (i32.ge_u (local.get $len) (local.get $free)) + (then (drop (call $caml_flush_partial (local.get $ch))))) + (local.get $len)) + + (func $caml_putblock_string + (param $ch (ref $channel)) (param $s anyref) (param $pos i32) (param $len i32) (result i32) (local $free i32) (local $curr i32) (local $buf (ref extern)) @@ -741,7 +768,7 @@ (local.get $len)) (func (export "caml_really_putblock") - (param $ch (ref eq)) (param $s (ref $string)) + (param $ch (ref eq)) (param $s (ref $bytes)) (param $pos i32) (param $len i32) (local $written i32) (loop $loop @@ -754,8 +781,34 @@ (local.set $len (i32.sub (local.get $len) (local.get $written))) (br $loop))))) - (export "caml_ml_output_bytes" (func $caml_ml_output)) +(#if use-js-string +(#then (func $caml_ml_output (export "caml_ml_output") + (param $ch (ref eq)) (param $s (ref eq)) (param $vpos (ref eq)) + (param $vlen (ref eq)) (result (ref eq)) + (local $pos i32) (local $len i32) (local $written i32) + (local.set $pos (i31.get_u (ref.cast (ref i31) (local.get $vpos)))) + (local.set $len (i31.get_u (ref.cast (ref i31) (local.get $vlen)))) + (loop $loop + (if (i32.gt_u (local.get $len) (i32.const 0)) + (then + (local.set $written + (call $caml_putblock_string + (ref.cast (ref $channel) (local.get $ch)) + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s))) + (local.get $pos) (local.get $len))) + (local.set $pos (i32.add (local.get $pos) (local.get $written))) + (local.set $len (i32.sub (local.get $len) (local.get $written))) + (br $loop)))) + (call $caml_flush_if_unbuffered (local.get $ch)) + (ref.i31 (i32.const 0))) +) +(#else + (export "caml_ml_output" (func $caml_ml_output_bytes)) +)) + + (func $caml_ml_output_bytes (export "caml_ml_output_bytes") (param $ch (ref eq)) (param $s (ref eq)) (param $vpos (ref eq)) (param $vlen (ref eq)) (result (ref eq)) (local $pos i32) (local $len i32) (local $written i32) @@ -766,7 +819,7 @@ (then (local.set $written (call $caml_putblock (ref.cast (ref $channel) (local.get $ch)) - (ref.cast (ref $string) (local.get $s)) + (ref.cast (ref $bytes) (local.get $s)) (local.get $pos) (local.get $len))) (local.set $pos (i32.add (local.get $pos) (local.get $written))) (local.set $len (i32.sub (local.get $len) (local.get $written))) diff --git a/runtime/wasm/jslib.wat b/runtime/wasm/jslib.wat index b15f2809a7..b28a52c0de 100644 --- a/runtime/wasm/jslib.wat +++ b/runtime/wasm/jslib.wat @@ -16,7 +16,6 @@ ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. (module - (import "bindings" "log" (func $log_js (param anyref))) (import "bindings" "identity" (func $to_float (param anyref) (result f64))) (import "bindings" "identity" (func $from_float (param f64) (result anyref))) (import "bindings" "identity" (func $to_bool (param anyref) (result i32))) @@ -85,13 +84,22 @@ (func $caml_is_closure (param (ref eq)) (result i32))) (import "obj" "caml_is_last_arg" (func $caml_is_last_arg (param (ref eq)) (result i32))) + (import "jsstring" "jsstring_of_bytes" + (func $jsstring_of_bytes (param (ref $bytes)) (result anyref))) + (import "jsstring" "bytes_of_jsstring" + (func $bytes_of_jsstring (param anyref) (result (ref $bytes)))) (import "jsstring" "jsstring_of_string" - (func $jsstring_of_string (param (ref $string)) (result anyref))) + (func $jsstring_of_string (param (ref eq)) (result (ref eq)))) (import "jsstring" "string_of_jsstring" - (func $string_of_jsstring (param anyref) (result (ref $string)))) + (func $string_of_jsstring (param (ref eq)) (result (ref eq)))) + (import "jsstring" "jsbytes_of_bytes" + (func $jsbytes_of_bytes (param (ref $bytes)) (result anyref))) + (import "jsstring" "bytes_of_jsbytes" + (func $bytes_of_jsbytes (param anyref) (result (ref $bytes)))) + (import "jsstring" "jsstring_of_subbytes" + (func $jsstring_of_subbytes (param (ref $bytes) i32 i32) (result anyref))) (import "jsstring" "jsstring_of_substring" - (func $jsstring_of_substring - (param (ref $string) i32 i32) (result anyref))) + (func $jsstring_of_substring (param (ref eq) i32 i32) (result (ref eq)))) (import "int32" "caml_copy_int32" (func $caml_copy_int32 (param i32) (result (ref eq)))) (import "int32" "Int32_val" @@ -104,7 +112,8 @@ (type $block (array (mut (ref eq)))) (type $float (struct (field f64))) (type $float_array (array (mut f64))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $js (struct (field anyref))) (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq)))) (type $closure (sub (struct (;(field i32);) (field (ref $function_1))))) @@ -187,9 +196,9 @@ (func (export "caml_js_meth_call") (param $o (ref eq)) (param $f (ref eq)) (param $args (ref eq)) (result (ref eq)) - (if (ref.test (ref $string) (local.get $f)) + (if (ref.test (ref $bytes) (local.get $f)) (then - (local.set $f (call $caml_jsbytes_of_string (local.get $f))))) + (local.set $f (call $caml_jsbytes_of_bytes (local.get $f))))) (return_call $wrap (call $meth_call (call $unwrap (local.get $o)) (call $unwrap (local.get $f)) @@ -197,9 +206,9 @@ (func (export "caml_js_get") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (if (ref.test (ref $string) (local.get 1)) + (if (ref.test (ref $bytes) (local.get 1)) (then - (local.set 1 (call $caml_jsbytes_of_string (local.get 1))))) + (local.set 1 (call $caml_jsbytes_of_bytes (local.get 1))))) (return_call $wrap (call $get (ref.as_non_null (extern.convert_any (call $unwrap (local.get 0)))) @@ -207,18 +216,18 @@ (func (export "caml_js_set") (param (ref eq)) (param (ref eq)) (param (ref eq)) (result (ref eq)) - (if (ref.test (ref $string) (local.get 1)) + (if (ref.test (ref $bytes) (local.get 1)) (then - (local.set 1 (call $caml_jsbytes_of_string (local.get 1))))) + (local.set 1 (call $caml_jsbytes_of_bytes (local.get 1))))) (call $set (call $unwrap (local.get 0)) (call $unwrap (local.get 1)) (call $unwrap (local.get 2))) (ref.i31 (i32.const 0))) (func (export "caml_js_delete") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (if (ref.test (ref $string) (local.get 1)) + (if (ref.test (ref $bytes) (local.get 1)) (then - (local.set 1 (call $caml_jsbytes_of_string (local.get 1))))) + (local.set 1 (call $caml_jsbytes_of_bytes (local.get 1))))) (call $delete (call $unwrap (local.get 0)) (call $unwrap (local.get 1))) (ref.i31 (i32.const 0))) @@ -455,126 +464,86 @@ (local.get $acc))))))))) (return_call $unwrap (local.get $acc))) - (export "caml_js_from_string" (func $caml_jsstring_of_string)) + (export "caml_js_from_string" (func $jsstring_of_string)) + +(#if use-js-string +(#then + (export "caml_jsstring_of_string" (func $jsstring_of_string)) + (func $caml_jsstring_of_string (param (ref eq)) (result (ref eq)) + (return_call $jsstring_of_string (local.get 0))) +) +(#else (func $caml_jsstring_of_string (export "caml_jsstring_of_string") (param (ref eq)) (result (ref eq)) - (local $s (ref $string)) - (local.set $s (ref.cast (ref $string) (local.get 0))) - (return (struct.new $js (call $jsstring_of_string (local.get $s))))) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (return (struct.new $js (call $jsstring_of_bytes (local.get $s))))) +)) +(#if use-js-string +(#then + (func (export "caml_jsstring_of_substring") + (param $s (ref eq)) (param $i (ref eq)) (param $l (ref eq)) + (result (ref eq)) + (return_call $jsstring_of_substring + (local.get $s) + (i31.get_u (ref.cast (ref i31) (local.get $i))) + (i31.get_u (ref.cast (ref i31) (local.get $l))))) +) +(#else (func (export "caml_jsstring_of_substring") (param $s (ref eq)) (param $i (ref eq)) (param $l (ref eq)) (result (ref eq)) (return (struct.new $js - (call $jsstring_of_substring - (ref.cast (ref $string) (local.get $s)) + (call $jsstring_of_subbytes + (ref.cast (ref $bytes) (local.get $s)) (i31.get_u (ref.cast (ref i31) (local.get $i))) (i31.get_u (ref.cast (ref i31) (local.get $l))))))) +)) - (func $caml_jsbytes_of_string (export "caml_jsbytes_of_string") +(#if use-js-string +(#then + (func (export "caml_jsbytes_of_string") (param (ref eq)) (result (ref eq)) - (local $s (ref $string)) - (local $s' (ref $string)) - (local $l i32) (local $i i32) (local $n i32) (local $c i32) - (local.set $s (ref.cast (ref $string) (local.get 0))) - (local.set $l (array.len (local.get $s))) - (local.set $i (i32.const 0)) - (local.set $n (i32.const 0)) - (loop $count - (if (i32.lt_u (local.get $i) (local.get $l)) - (then - (if (i32.ge_u (array.get_u $string (local.get $s) (local.get $i)) - (i32.const 128)) - (then (local.set $n (i32.add (local.get $n) (i32.const 1))))) - (local.set $i (i32.add (local.get $i) (i32.const 1))) - (br $count)))) - (if (i32.eqz (local.get $n)) - (then - (return - (struct.new $js - (call $jsstring_of_string (local.get $s)))))) - (local.set $s' - (array.new $string (i32.const 0) - (i32.add (local.get $i) (local.get $n)))) - (local.set $i (i32.const 0)) - (local.set $n (i32.const 0)) - (loop $fill - (if (i32.lt_u (local.get $i) (local.get $l)) - (then - (local.set $c (array.get_u $string (local.get $s) (local.get $i))) - (if (i32.lt_u (local.get $c) (i32.const 128)) - (then - (array.set $string - (local.get $s') (local.get $n) (local.get $c)) - (local.set $n (i32.add (local.get $n) (i32.const 1)))) - (else - (array.set $string (local.get $s') - (local.get $n) - (i32.or (i32.shr_u (local.get $c) (i32.const 6)) - (i32.const 0xC0))) - (array.set $string (local.get $s') - (i32.add (local.get $n) (i32.const 1)) - (i32.or (i32.const 0x80) - (i32.and (local.get $c) (i32.const 0x3F)))) - (local.set $n (i32.add (local.get $n) (i32.const 2))))) - (local.set $i (i32.add (local.get $i) (i32.const 1))) - (br $fill)))) - (return (struct.new $js (call $jsstring_of_string (local.get $s'))))) + (local.get 0)) +) +(#else + (export "caml_jsbytes_of_string" (func $caml_jsbytes_of_bytes)) +)) + (func $caml_jsbytes_of_bytes + (param (ref eq)) (result (ref eq)) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (return (struct.new $js (call $jsbytes_of_bytes (local.get $s))))) + +(#if use-js-string +(#then + (export "caml_js_to_string" (func $string_of_jsstring)) + (export "caml_string_of_jsstring" (func $string_of_jsstring)) + (func $caml_string_of_jsstring (param (ref eq)) (result (ref eq)) + (return_call $string_of_jsstring (local.get 0))) +) +(#else (export "caml_js_to_string" (func $caml_string_of_jsstring)) (func $caml_string_of_jsstring (export "caml_string_of_jsstring") (param $s (ref eq)) (result (ref eq)) - (return_call $string_of_jsstring + (return_call $bytes_of_jsstring (struct.get $js 0 (ref.cast (ref $js) (local.get $s))))) +)) +(#if use-js-string +(#then (func (export "caml_string_of_jsbytes") (param $s (ref eq)) (result (ref eq)) - (local $l i32) (local $i i32) (local $n i32) (local $c i32) - (local $s' (ref $string)) (local $s'' (ref $string)) - (local.set $s' - (call $string_of_jsstring - (struct.get $js 0 (ref.cast (ref $js) (local.get $s))))) - (local.set $l (array.len (local.get $s'))) - (local.set $i (i32.const 0)) - (local.set $n (i32.const 0)) - (loop $count - (if (i32.lt_u (local.get $i) (local.get $l)) - (then - (if (i32.ge_u (array.get_u $string (local.get $s') (local.get $i)) - (i32.const 0xC0)) - (then (local.set $n (i32.add (local.get $n) (i32.const 1))))) - (local.set $i (i32.add (local.get $i) (i32.const 1))) - (br $count)))) - (if (i32.eqz (local.get $n)) (then (return (local.get $s')))) - (local.set $s'' - (array.new $string (i32.const 0) - (i32.sub (local.get $i) (local.get $n)))) - (local.set $i (i32.const 0)) - (local.set $n (i32.const 0)) - (loop $fill - (if (i32.lt_u (local.get $i) (local.get $l)) - (then - (local.set $c - (array.get_u $string (local.get $s') (local.get $i))) - (if (i32.lt_u (local.get $c) (i32.const 0xC0)) - (then - (array.set $string - (local.get $s'') (local.get $n) (local.get $c)) - (local.set $i (i32.add (local.get $i) (i32.const 1)))) - (else - (array.set $string (local.get $s'') - (local.get $n) - (i32.sub - (i32.add - (i32.shl (local.get $c) (i32.const 6)) - (array.get_u $string (local.get $s') - (i32.add (local.get $i) (i32.const 1)))) - (i32.const 0x3080))) - (local.set $i (i32.add (local.get $i) (i32.const 2))))) - (local.set $n (i32.add (local.get $n) (i32.const 1))) - (br $fill)))) - (local.get $s'')) + (local.get 0)) +) +(#else + (func (export "caml_string_of_jsbytes") (param $s (ref eq)) (result (ref eq)) + (return_call $bytes_of_jsbytes + (struct.get $js 0 (ref.cast (ref $js) (local.get $s))))) +)) (func (export "caml_list_to_js_array") (param (ref eq)) (result (ref eq)) @@ -629,12 +598,9 @@ (br $loop)))) (local.get $l)) - (global $jsError (ref $string) - (array.new_fixed $string 7 ;; 'jsError' - (i32.const 106) (i32.const 115) (i32.const 69) (i32.const 114) - (i32.const 114) (i32.const 111) (i32.const 114))) + (#string $jsError "jsError") - (data $toString "toString") + (#string $toString "toString") (func (export "caml_wrap_exception") (param externref) (result (ref eq)) (local $exn anyref) @@ -653,9 +619,7 @@ (call $meth_call (local.get $exn) (call $unwrap - (call $caml_jsstring_of_string - (array.new_data $string $toString - (i32.const 0) (i32.const 8)))) + (call $caml_jsstring_of_string (global.get $toString))) (any.convert_extern (call $new_array (i32.const 0)))))))) (func (export "caml_js_error_option_of_exception") @@ -687,7 +651,15 @@ (array.get $block (local.get $exn) (i32.const 2))))))) (call $wrap (ref.null any))) - (func (export "log_str") (param $s (ref $string)) - (call $log_js - (call $unwrap (call $caml_jsstring_of_string (local.get $s))))) + (func (export "caml_jsoo_flags_use_js_string") + (param (ref eq)) (result (ref eq)) + (ref.i31 +(#if use-js-string +(#then + (i32.const 1) +) +(#else + (i32.const 0) +)) + )) ) diff --git a/runtime/wasm/jslib_js_of_ocaml.wat b/runtime/wasm/jslib_js_of_ocaml.wat index 3b26b553ce..7c1b014fc3 100644 --- a/runtime/wasm/jslib_js_of_ocaml.wat +++ b/runtime/wasm/jslib_js_of_ocaml.wat @@ -32,7 +32,8 @@ (func $caml_js_html_entities (param anyref) (result anyref))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $js (struct (field anyref))) (func (export "caml_js_html_escape") (param (ref eq)) (result (ref eq)) (return_call $wrap @@ -42,19 +43,18 @@ (return_call $wrap (call $caml_js_html_entities (call $unwrap (local.get 0))))) - (data $console "console") + (#jsstring $console "console") (func (export "caml_js_get_console") (param (ref eq)) (result (ref eq)) (return_call $caml_js_get (call $caml_js_global (ref.i31 (i32.const 0))) - (array.new_data $string $console (i32.const 0) (i32.const 7)))) + (global.get $console))) - (data $XMLHttpRequest "XMLHttpRequest") + (#jsstring $XMLHttpRequest "XMLHttpRequest") (func (export "caml_xmlhttprequest_create") (param (ref eq)) (result (ref eq)) (return_call $caml_js_new (call $caml_js_get (call $caml_js_global (ref.i31 (i32.const 0))) - (array.new_data $string $XMLHttpRequest - (i32.const 0) (i32.const 14))) + (global.get $XMLHttpRequest)) (array.new_fixed $block 1 (ref.i31 (i32.const 0))))) ) diff --git a/runtime/wasm/jsstring.wat b/runtime/wasm/jsstring.wat index 93956d3282..2f64b1b5fc 100644 --- a/runtime/wasm/jsstring.wat +++ b/runtime/wasm/jsstring.wat @@ -22,19 +22,23 @@ (func $is_string (param externref) (result i32))) (import "wasm:js-string" "hash" (func $hash_string (param i32) (param anyref) (result i32))) + (import "wasm:js-string" "length" + (func $string_length (param externref) (result i32))) + (import "wasm:js-string" "substring" + (func $string_sub (param externref i32 i32) (result (ref extern)))) (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (param (ref null $wstring)) (param i32) (param i32) (result (ref extern)))) - + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) (import "wasm:text-decoder" "decodeStringFromUTF8Array" (func $decodeStringFromUTF8Array - (param (ref null $string)) (param i32) (param i32) + (param (ref null $bytes)) (param i32) (param i32) (result (ref extern)))) (import "wasm:text-encoder" "encodeStringToUTF8Array" (func $encodeStringToUTF8Array - (param externref) (result (ref $string)))) - + (param externref) (result (ref $bytes)))) (import "bindings" "read_string" (func $read_string (param i32) (result anyref))) (import "bindings" "read_string_stream" @@ -43,8 +47,13 @@ (func $write_string (param anyref) (result i32))) (import "bindings" "append_string" (func $append_string (param anyref) (param anyref) (result anyref))) + (import "js" "caml_utf16_of_utf8" + (func $utf16_of_utf8 (param anyref) (result anyref))) + (import "js" "caml_utf8_of_utf16" + (func $utf8_of_utf16 (param anyref) (result anyref))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $wstring (array (mut i16))) (global $text_converters_available (mut i32) (i32.const 0)) @@ -64,10 +73,10 @@ (i32.const 0) (call $compare_strings (call $decodeStringFromUTF8Array - (array.new_fixed $string 1 (i32.const 0)) + (array.new_fixed $bytes 1 (i32.const 0)) (i32.const 0) (i32.const 1)) (call $decodeStringFromUTF8Array - (array.new_fixed $string 1 (i32.const 1)) + (array.new_fixed $bytes 1 (i32.const 1)) (i32.const 0) (i32.const 1))))) (global.set $string_builtins_available (i32.ne @@ -96,11 +105,13 @@ (func (export "jsstring_test") (param $s anyref) (result i32) (return_call $is_string (extern.convert_any (local.get $s)))) + (func (export "jsstring_length") (param $s anyref) (result i32) + (return_call $string_length (extern.convert_any (local.get $s)))) + (export "jsstring_hash" (func $hash_string)) - ;; Used by package zarith_stubs_js - (func $jsstring_of_substring (export "jsstring_of_substring") - (param $s (ref $string)) (param $pos i32) (param $len i32) + (func $jsstring_of_subbytes (export "jsstring_of_subbytes") + (param $s (ref $bytes)) (param $pos i32) (param $len i32) (result anyref) (local $i i32) (local $c i32) (if (global.get $text_converters_available) @@ -118,7 +129,7 @@ (if (i32.lt_u (local.get $i) (local.get $len)) (then (local.set $c - (array.get $string (local.get $s) + (array.get $bytes (local.get $s) (i32.add (local.get $pos) (local.get $i)))) (br_if $continue (i32.ge_u (local.get $c) (i32.const 128))) @@ -130,19 +141,163 @@ (any.convert_extern (call $fromCharCodeArray (global.get $buffer) (i32.const 0) (local.get $len)))))) - (return_call $jsstring_of_substring_fallback + (return_call $jsstring_of_subbytes_fallback (local.get $s) (local.get $pos) (local.get $len))) - (func (export "jsstring_of_string") (param $s (ref $string)) (result anyref) - (return_call $jsstring_of_substring + (func $jsstring_of_bytes (export "jsstring_of_bytes") + (param $s (ref $bytes)) (result anyref) + (return_call $jsstring_of_subbytes (local.get $s) (i32.const 0) (array.len (local.get $s)))) - (func (export "string_of_jsstring") (param $s anyref) (result (ref $string)) + (func $bytes_of_jsstring (export "bytes_of_jsstring") + (param $s anyref) (result (ref $bytes)) (if (global.get $text_converters_available) (then (return_call $encodeStringToUTF8Array (extern.convert_any (local.get $s))))) - (return_call $string_of_jsstring_fallback (local.get $s))) + (return_call $bytes_of_jsstring_fallback (local.get $s))) + + (func $string_is_ascii (param $vs (ref eq)) (result i32) + (local $s externref) (local $len i32) (local $i i32) + (local.set $s + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $vs))))) + (local.set $len (call $string_length (local.get $s))) + (loop $loop + (if (i32.lt_u (local.get $i) (local.get $len)) + (then + (if (i32.ge_u (call $string_get (local.get $s) (local.get $i)) + (i32.const 128)) + (then (return (i32.const 0)))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br $loop)))) + (i32.const 1)) + + (func $jsstring_of_string (export "jsstring_of_string") + (param $s (ref eq)) (result (ref eq)) + (if (result (ref eq)) (call $string_is_ascii (local.get $s)) + (then + (local.get $s)) + (else + (return + (struct.new $string + (call $utf16_of_utf8 + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s))))))))) + + (func (export "jsstring_of_substring") + (param $s (ref eq)) (param $i i32) (param $l i32) (result (ref eq)) + (return_call $jsstring_of_string + (struct.new $string + (any.convert_extern + (call $string_sub + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s)))) + (local.get $i) + (i32.add (local.get $i) (local.get $l))))))) + + (func (export "string_of_jsstring") + (param $s (ref eq)) (result (ref eq)) + (if (result (ref eq)) (call $string_is_ascii (local.get $s)) + (then + (local.get $s)) + (else + (return + (struct.new $string + (call $utf8_of_utf16 + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s))))))))) + + (func (export "jsbytes_of_bytes") (param $s (ref $bytes)) (result anyref) + (local $s' (ref $bytes)) + (local $l i32) (local $i i32) (local $n i32) (local $c i32) + (local.set $l (array.len (local.get $s))) + (local.set $i (i32.const 0)) + (local.set $n (i32.const 0)) + (loop $count + (if (i32.lt_u (local.get $i) (local.get $l)) + (then + (if (i32.ge_u (array.get_u $bytes (local.get $s) (local.get $i)) + (i32.const 128)) + (then (local.set $n (i32.add (local.get $n) (i32.const 1))))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br $count)))) + (if (i32.eqz (local.get $n)) + (then + (return_call $jsstring_of_bytes (local.get $s)))) + (local.set $s' + (array.new $bytes (i32.const 0) + (i32.add (local.get $i) (local.get $n)))) + (local.set $i (i32.const 0)) + (local.set $n (i32.const 0)) + (loop $fill + (if (i32.lt_u (local.get $i) (local.get $l)) + (then + (local.set $c (array.get_u $bytes (local.get $s) (local.get $i))) + (if (i32.lt_u (local.get $c) (i32.const 128)) + (then + (array.set $bytes + (local.get $s') (local.get $n) (local.get $c)) + (local.set $n (i32.add (local.get $n) (i32.const 1)))) + (else + (array.set $bytes (local.get $s') + (local.get $n) + (i32.or (i32.shr_u (local.get $c) (i32.const 6)) + (i32.const 0xC0))) + (array.set $bytes (local.get $s') + (i32.add (local.get $n) (i32.const 1)) + (i32.or (i32.const 0x80) + (i32.and (local.get $c) (i32.const 0x3F)))) + (local.set $n (i32.add (local.get $n) (i32.const 2))))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br $fill)))) + (return_call $jsstring_of_bytes (local.get $s'))) + + (func (export "bytes_of_jsbytes") (param $s anyref) (result (ref $bytes)) + (local $l i32) (local $i i32) (local $n i32) (local $c i32) + (local $s' (ref $bytes)) (local $s'' (ref $bytes)) + (local.set $s' (call $bytes_of_jsstring (local.get $s))) + (local.set $l (array.len (local.get $s'))) + (local.set $i (i32.const 0)) + (local.set $n (i32.const 0)) + (loop $count + (if (i32.lt_u (local.get $i) (local.get $l)) + (then + (if (i32.ge_u (array.get_u $bytes (local.get $s') (local.get $i)) + (i32.const 0xC0)) + (then (local.set $n (i32.add (local.get $n) (i32.const 1))))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br $count)))) + (if (i32.eqz (local.get $n)) (then (return (local.get $s')))) + (local.set $s'' + (array.new $bytes (i32.const 0) + (i32.sub (local.get $i) (local.get $n)))) + (local.set $i (i32.const 0)) + (local.set $n (i32.const 0)) + (loop $fill + (if (i32.lt_u (local.get $i) (local.get $l)) + (then + (local.set $c + (array.get_u $bytes (local.get $s') (local.get $i))) + (if (i32.lt_u (local.get $c) (i32.const 0xC0)) + (then + (array.set $bytes + (local.get $s'') (local.get $n) (local.get $c)) + (local.set $i (i32.add (local.get $i) (i32.const 1)))) + (else + (array.set $bytes (local.get $s'') + (local.get $n) + (i32.sub + (i32.add + (i32.shl (local.get $c) (i32.const 6)) + (array.get_u $bytes (local.get $s') + (i32.add (local.get $i) (i32.const 1)))) + (i32.const 0x3080))) + (local.set $i (i32.add (local.get $i) (i32.const 2))))) + (local.set $n (i32.add (local.get $n) (i32.const 1))) + (br $fill)))) + (local.get $s'')) ;; Fallback implementation of string conversion functions @@ -151,19 +306,19 @@ (global $buffer_size i32 (i32.const 65536)) (func $write_to_buffer - (param $s (ref $string)) (param $pos i32) (param $len i32) + (param $s (ref $bytes)) (param $pos i32) (param $len i32) (local $i i32) (loop $loop (if (i32.lt_u (local.get $i) (local.get $len)) (then (i32.store8 (local.get $i) - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $pos) (local.get $i)))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br $loop))))) - (func $jsstring_of_substring_fallback - (param $s (ref $string)) (param $pos i32) (param $len i32) + (func $jsstring_of_subbytes_fallback + (param $s (ref $bytes)) (param $pos i32) (param $len i32) (result anyref) (local $s' anyref) (local $continued i32) @@ -195,30 +350,30 @@ (local.get $s')) (func $read_from_buffer - (param $s (ref $string)) (param $pos i32) (param $len i32) + (param $s (ref $bytes)) (param $pos i32) (param $len i32) (local $i i32) (loop $loop (if (i32.lt_u (local.get $i) (local.get $len)) (then - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $pos) (local.get $i)) (i32.load8_u (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br $loop))))) (type $stack - (struct (field $s (ref $string)) (field $next (ref null $stack)))) + (struct (field $s (ref $bytes)) (field $next (ref null $stack)))) (global $stack (mut (ref null $stack)) (ref.null $stack)) - (func $string_of_jsstring_fallback (param $s anyref) (result (ref $string)) + (func $bytes_of_jsstring_fallback (param $s anyref) (result (ref $bytes)) (local $ofs i32) (local $len i32) - (local $s' (ref $string)) (local $s'' (ref $string)) + (local $s' (ref $bytes)) (local $s'' (ref $bytes)) (local $item (ref $stack)) (local.set $len (call $write_string (local.get $s))) (if (ref.is_null (global.get $stack)) (then (local.set $s' - (array.new $string (i32.const 0) (local.get $len))) + (array.new $bytes (i32.const 0) (local.get $len))) (call $read_from_buffer (local.get $s') (i32.const 0) (local.get $len)) (return (local.get $s')))) @@ -232,7 +387,7 @@ (br_on_null $done (struct.get $stack $next (local.get $item)))) (br $loop))) (local.set $s' - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.add (local.get $len) (local.get $ofs)))) (call $read_from_buffer (local.get $s') (local.get $ofs) (local.get $len)) @@ -243,7 +398,7 @@ (local.set $s'' (struct.get $stack $s (local.get $item))) (local.set $len (array.len (local.get $s''))) (local.set $ofs (i32.sub (local.get $ofs) (local.get $len))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $s') (local.get $ofs) (local.get $s'') (i32.const 0) (local.get $len)) @@ -253,8 +408,110 @@ (local.get $s')) (func (export "caml_extract_string") (param $len i32) - (local $s (ref $string)) - (local.set $s (array.new $string (i32.const 0) (local.get $len))) + (local $s (ref $bytes)) + (local.set $s (array.new $bytes (i32.const 0) (local.get $len))) (call $read_from_buffer (local.get $s) (i32.const 0) (local.get $len)) (global.set $stack (struct.new $stack (local.get $s) (global.get $stack)))) + + (func $utf16_to_utf8 + (param $s externref) (param $l i32) (param $b (ref $wstring)) (result i32) + (local $i i32) (local $j i32) (local $c i32) (local $d i32) + (loop $loop + (if (i32.lt_u (local.get $i) (local.get $l)) + (then + (local.set $c (call $string_get (local.get $s) (local.get $i))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (if (i32.lt_u (local.get $c) (i32.const 0x80)) + (then + (array.set $wstring + (local.get $b) (local.get $j) (local.get $c)) + (local.set $j (i32.add (local.get $j) (i32.const 1))) + (br $loop))) + (if (i32.lt_u (local.get $c) (i32.const 0x800)) + (then + (array.set $wstring + (local.get $b) (local.get $j) + (i32.or (i32.const 0xC0) + (i32.shr_u (local.get $c) (i32.const 6)))) + (array.set $wstring + (local.get $b) + (i32.add (local.get $j) (i32.const 1)) + (i32.or (i32.const 0x80) + (i32.and (local.get $c) (i32.const 0x3F)))) + (local.set $j (i32.add (local.get $j) (i32.const 2))) + (br $loop))) + (if (i32.and + (i32.ge_u (local.get $c) (i32.const 0xD800)) + (i32.lt_u (local.get $c) (i32.const 0xE000))) + (then + (if (i32.and + (i32.lt_u (local.get $c) (i32.const 0xDC00)) + (i32.lt_u (local.get $i) (local.get $l))) + (then + (local.set $d + (call $string_get (local.get $s) (local.get $i))) + (if (i32.and + (i32.ge_u (local.get $c) (i32.const 0xDC00)) + (i32.lt_u (local.get $c) (i32.const 0xE000))) + (then + (local.set $i + (i32.add (local.get $i) (i32.const 1))) + (local.set $c + (i32.sub + (i32.add + (i32.shl + (local.get $c) + (i32.const 10)) + (local.get $d)) + (i32.const 0x35fdc00))) + (array.set $wstring + (local.get $b) (local.get $j) + (i32.or (i32.const 0xE0) + (i32.shr_u (local.get $c) + (i32.const 18)))) + (array.set $wstring + (local.get $b) + (i32.add (local.get $j) (i32.const 1)) + (i32.or (i32.const 0x80) + (i32.and + (i32.shr_u (local.get $c) + (i32.const 12)) + (i32.const 0x3F)))) + (array.set $wstring + (local.get $b) + (i32.add (local.get $j) (i32.const 2)) + (i32.or (i32.const 0x80) + (i32.and + (i32.shr_u (local.get $c) + (i32.const 6)) + (i32.const 0x3F)))) + (array.set $wstring + (local.get $b) + (i32.add (local.get $j) (i32.const 3)) + (i32.or (i32.const 0x80) + (i32.and (local.get $c) + (i32.const 0x3F)))) + (local.set $j + (i32.add (local.get $j) (i32.const 4))) + (br $loop))))) + ;; replacement character + (local.set $c (i32.const 0xFFFD)))) + (array.set $wstring + (local.get $b) (local.get $j) + (i32.or (i32.const 0xE0) + (i32.shr_u (local.get $c) (i32.const 12)))) + (array.set $wstring + (local.get $b) + (i32.add (local.get $j) (i32.const 1)) + (i32.or (i32.const 0x80) + (i32.and (i32.shr_u (local.get $c) (i32.const 6)) + (i32.const 0x3F)))) + (array.set $wstring + (local.get $b) + (i32.add (local.get $j) (i32.const 2)) + (i32.or (i32.const 0x80) + (i32.and (local.get $c) (i32.const 0x3F)))) + (local.set $j (i32.add (local.get $j) (i32.const 3))) + (br $loop)))) + (local.get $j)) ) diff --git a/runtime/wasm/lexing.wat b/runtime/wasm/lexing.wat index eb9b94b1ad..8fc76703a4 100644 --- a/runtime/wasm/lexing.wat +++ b/runtime/wasm/lexing.wat @@ -19,16 +19,39 @@ (import "fail" "caml_failwith" (func $caml_failwith (param (ref eq)))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) - (func $get (param $a (ref eq)) (param $i i32) (result i32) - (local $s (ref $string)) - (local.set $s (ref.cast (ref $string) (local.get $a))) +(#if use-js-string +(#then + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) + + (func $get +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (result i32) (local.set $i (i32.add (local.get $i) (local.get $i))) (i32.extend16_s - (i32.or (array.get_u $string (local.get $s) (local.get $i)) + (i32.or (call $string_get (local.get $s) (local.get $i)) (i32.shl - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.add (local.get $i) (i32.const 1))) (i32.const 8))))) @@ -52,7 +75,7 @@ (global $lex_check_code i32 (i32.const 10)) (global $lex_code i32 (i32.const 11)) - (data $lexing_empty_token "lexing: empty token") + (#string $lexing_empty_token "lexing: empty token") (func (export "caml_lex_engine") (param $vtbl (ref eq)) (param $start_state (ref eq)) @@ -62,21 +85,32 @@ (local $lexbuf (ref $block)) (local $c i32) (local $state i32) - (local $buffer (ref $string)) + (local $buffer (ref $bytes)) (local $vpos (ref eq)) (local $action (ref eq)) (local $pos i32) (local $base i32) (local $backtrk i32) - (local $lex_base (ref $string)) - (local $lex_backtrk (ref $string)) - (local $lex_check (ref $string)) - (local $lex_check_code (ref $string)) - (local $lex_trans (ref $string)) - (local $lex_default (ref $string)) +(#if use-js-string +(#then + (local $lex_base externref) + (local $lex_backtrk externref) + (local $lex_check externref) + (local $lex_check_code externref) + (local $lex_trans externref) + (local $lex_default externref) +) +(#else + (local $lex_base (ref $bytes)) + (local $lex_backtrk (ref $bytes)) + (local $lex_check (ref $bytes)) + (local $lex_check_code (ref $bytes)) + (local $lex_trans (ref $bytes)) + (local $lex_default (ref $bytes)) +)) (local.set $tbl (ref.cast (ref $block) (local.get $vtbl))) (local.set $lexbuf (ref.cast (ref $block) (local.get $vlexbuf))) (local.set $state (i31.get_s (ref.cast (ref i31) (local.get $start_state)))) (local.set $buffer - (ref.cast (ref $string) + (ref.cast (ref $bytes) (array.get $block (local.get $lexbuf) (global.get $lex_buffer)))) (if (i32.ge_s (local.get $state) (i32.const 0)) (then @@ -91,22 +125,22 @@ (else (local.set $state (i32.sub (i32.const -1) (local.get $state))))) (local.set $lex_base - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_base)))) (local.set $lex_backtrk - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_backtrk)))) (local.set $lex_check - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_check)))) (local.set $lex_check_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_check_code)))) (local.set $lex_trans - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_trans)))) (local.set $lex_default - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_default)))) (loop $loop (local.set $base (call $get (local.get $lex_base) (local.get $state))) @@ -149,7 +183,7 @@ (array.get $block (local.get $lexbuf) (global.get $lex_curr_pos))))) (local.set $c - (array.get_u $string (local.get $buffer) (local.get $pos))) + (array.get_u $bytes (local.get $buffer) (local.get $pos))) (array.set $block (local.get $lexbuf) (global.get $lex_curr_pos) (ref.i31 (i32.add (local.get $pos) (i32.const 1)))))) (if (i32.eq @@ -172,10 +206,7 @@ (array.get $block (local.get $lexbuf) (global.get $lex_last_action))) (if (ref.eq (local.get $action) (ref.i31 (i32.const -1))) - (then - (call $caml_failwith - (array.new_data $string $lexing_empty_token - (i32.const 0) (i32.const 19))))) + (then (call $caml_failwith (global.get $lexing_empty_token)))) (return (local.get $action)))) (if (i32.eq (local.get $c) (i32.const 256)) (then @@ -185,7 +216,14 @@ (br $loop))) (func $run_mem - (param $s (ref $string)) (param $i i32) (param $lexbuf (ref $block)) +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (param $lexbuf (ref $block)) (param $curr_pos (ref eq)) (local $dst i32) (local $src i32) (local $mem (ref $block)) @@ -193,11 +231,11 @@ (ref.cast (ref $block) (array.get $block (local.get $lexbuf) (global.get $lex_mem)))) (loop $loop - (local.set $dst (array.get_u $string (local.get $s) (local.get $i))) + (local.set $dst (call $string_get (local.get $s) (local.get $i))) (if (i32.eq (local.get $dst) (i32.const 0xff)) (then (return))) (local.set $src - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.add (local.get $i) (i32.const 1)))) (local.set $i (i32.add (local.get $i) (i32.const 2))) (array.set $block (local.get $mem) @@ -211,7 +249,14 @@ (br $loop))) (func $run_tag - (param $s (ref $string)) (param $i i32) (param $lexbuf (ref $block)) +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (param $lexbuf (ref $block)) (return_call $run_mem (local.get $s) (local.get $i) (local.get $lexbuf) (ref.i31 (i32.const -1)))) @@ -223,27 +268,43 @@ (local $lexbuf (ref $block)) (local $c i32) (local $state i32) (local $pstate i32) - (local $buffer (ref $string)) + (local $buffer (ref $bytes)) (local $vpos (ref eq)) (local $action (ref eq)) (local $pos i32) (local $base i32) (local $backtrk i32) (local $pc_off i32) (local $base_code i32) - (local $lex_code (ref $string)) - (local $lex_base (ref $string)) - (local $lex_base_code (ref $string)) - (local $lex_backtrk (ref $string)) - (local $lex_backtrk_code (ref $string)) - (local $lex_check (ref $string)) - (local $lex_check_code (ref $string)) - (local $lex_trans (ref $string)) - (local $lex_trans_code (ref $string)) - (local $lex_default (ref $string)) - (local $lex_default_code (ref $string)) +(#if use-js-string +(#then + (local $lex_code externref) + (local $lex_base externref) + (local $lex_base_code externref) + (local $lex_backtrk externref) + (local $lex_backtrk_code externref) + (local $lex_check externref) + (local $lex_check_code externref) + (local $lex_trans externref) + (local $lex_trans_code externref) + (local $lex_default externref) + (local $lex_default_code externref) +) +(#else + (local $lex_code (ref $bytes)) + (local $lex_base (ref $bytes)) + (local $lex_base_code (ref $bytes)) + (local $lex_backtrk (ref $bytes)) + (local $lex_backtrk_code (ref $bytes)) + (local $lex_check (ref $bytes)) + (local $lex_check_code (ref $bytes)) + (local $lex_trans (ref $bytes)) + (local $lex_trans_code (ref $bytes)) + (local $lex_default (ref $bytes)) + (local $lex_default_code (ref $bytes)) +)) (local.set $tbl (ref.cast (ref $block) (local.get $vtbl))) (local.set $lexbuf (ref.cast (ref $block) (local.get $vlexbuf))) (local.set $state (i31.get_s (ref.cast (ref i31) (local.get $start_state)))) (local.set $buffer - (ref.cast (ref $string) + (ref.cast (ref $bytes) (array.get $block (local.get $lexbuf) (global.get $lex_buffer)))) (if (i32.ge_s (local.get $state) (i32.const 0)) (then @@ -258,37 +319,37 @@ (else (local.set $state (i32.sub (i32.const -1) (local.get $state))))) (local.set $lex_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_code)))) (local.set $lex_base - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_base)))) (local.set $lex_base_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_base_code)))) (local.set $lex_backtrk - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_backtrk)))) (local.set $lex_backtrk_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_backtrk_code)))) (local.set $lex_check - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_check)))) (local.set $lex_check_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_check_code)))) (local.set $lex_trans - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_trans)))) (local.set $lex_trans_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_trans_code)))) (local.set $lex_default - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_default)))) (local.set $lex_default_code - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tbl) (global.get $lex_default_code)))) (loop $loop (local.set $base (call $get (local.get $lex_base) (local.get $state))) @@ -339,7 +400,7 @@ (array.get $block (local.get $lexbuf) (global.get $lex_curr_pos))))) (local.set $c - (array.get_u $string (local.get $buffer) (local.get $pos))) + (array.get_u $bytes (local.get $buffer) (local.get $pos))) (array.set $block (local.get $lexbuf) (global.get $lex_curr_pos) (ref.i31 (i32.add (local.get $pos) (i32.const 1)))))) (local.set $pstate (local.get $state)) @@ -363,10 +424,7 @@ (array.get $block (local.get $lexbuf) (global.get $lex_last_action))) (if (ref.eq (local.get $action) (ref.i31 (i32.const -1))) - (then - (call $caml_failwith - (array.new_data $string $lexing_empty_token - (i32.const 0) (i32.const 19))))) + (then (call $caml_failwith (global.get $lexing_empty_token)))) (return (local.get $action)))) (local.set $base_code (call $get (local.get $lex_base_code) (local.get $pstate))) diff --git a/runtime/wasm/marshal.wat b/runtime/wasm/marshal.wat index 46373b2bf7..526f606df3 100644 --- a/runtime/wasm/marshal.wat +++ b/runtime/wasm/marshal.wat @@ -20,7 +20,6 @@ (import "fail" "caml_invalid_argument" (func $caml_invalid_argument (param (ref eq)))) (import "fail" "caml_raise_end_of_file" (func $caml_raise_end_of_file)) - (import "obj" "double_array_tag" (global $double_array_tag i32)) (import "string" "caml_string_concat" (func $caml_string_concat (param (ref eq)) (param (ref eq)) (result (ref eq)))) @@ -35,10 +34,10 @@ (func $map_set (param (ref any)) (param (ref eq)) (param (ref i31)))) (import "io" "caml_really_putblock" (func $caml_really_putblock - (param (ref eq)) (param (ref $string)) (param i32) (param i32))) + (param (ref eq)) (param (ref $bytes)) (param i32) (param i32))) (import "io" "caml_really_getblock" (func $caml_really_getblock - (param (ref eq)) (param (ref $string)) (param i32) (param i32) + (param (ref eq)) (param (ref $bytes)) (param i32) (param i32) (result i32))) (import "io" "caml_flush_if_unbuffered" (func $caml_flush_if_unbuffered (param (ref eq)))) @@ -46,28 +45,44 @@ (func $caml_init_custom_operations)) (import "custom" "caml_find_custom_operations" (func $caml_find_custom_operations - (param (ref $string)) (result (ref null $custom_operations)))) + (param (ref $bytes)) (result (ref null $custom_operations)))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) + (import "string" "caml_bytes_of_string" + (func $caml_bytes_of_string (param (ref eq)) (result (ref eq)))) + (import "jsstring" "jsstring_test" + (func $jsstring_test (param anyref) (result i32))) + (import "jsstring" "jsstring_length" + (func $jsstring_length (param anyref) (result i32))) + (import "string" "caml_blit_string" + (func $caml_blit_string + (param (ref eq) (ref eq) (ref eq) (ref eq) (ref eq)) + (result (ref eq)))) (import "version-dependent" "caml_marshal_header_size" (global $caml_marshal_header_size i32)) - (global $input_val_from_string (ref $string) - (array.new_fixed $string 21 - (i32.const 105) (i32.const 110) (i32.const 112) (i32.const 117) - (i32.const 116) (i32.const 95) (i32.const 118) (i32.const 97) - (i32.const 108) (i32.const 95) (i32.const 102) (i32.const 114) - (i32.const 111) (i32.const 109) (i32.const 95) (i32.const 115) - (i32.const 116) (i32.const 114) (i32.const 105) (i32.const 110) - (i32.const 103))) + (#string $input_val_from_string "input_val_from_string") +(#if use-js-string +(#then + (func (export "caml_input_value_from_string") + (param $vstr (ref eq)) (param $vofs (ref eq)) (result (ref eq)) + ;; It would be better to parse the header and extract just the + ;; relevant substring + (return_call $caml_input_value_from_bytes + (call $caml_bytes_of_string (local.get $vstr)) (local.get $vofs))) +) +(#else (export "caml_input_value_from_string" (func $caml_input_value_from_bytes)) +)) (func $caml_input_value_from_bytes (export "caml_input_value_from_bytes") (param $vstr (ref eq)) (param $vofs (ref eq)) (result (ref eq)) - (local $str (ref $string)) + (local $str (ref $bytes)) (local $ofs i32) (local $s (ref $intern_state)) (local $h (ref $marshal_header)) - (local.set $str (ref.cast (ref $string) (local.get $vstr))) + (local.set $str (ref.cast (ref $bytes) (local.get $vstr))) (local.set $ofs (i31.get_u (ref.cast (ref i31) (local.get $vofs)))) (local.set $s (call $get_intern_state (local.get $str) (local.get $ofs))) @@ -82,49 +97,39 @@ (call $bad_length (global.get $input_val_from_string)))) (return_call $intern_rec (local.get $s) (local.get $h))) - (data $truncated_obj "input_value: truncated object") - - (global $input_value (ref $string) - (array.new_fixed $string 11 - (i32.const 105) (i32.const 110) (i32.const 112) (i32.const 117) - (i32.const 116) (i32.const 95) (i32.const 118) (i32.const 97) - (i32.const 108) (i32.const 117) (i32.const 101))) + (#string $truncated_obj "input_value: truncated object") + (#string $input_value "input_value") (func (export "caml_input_value") (param $ch (ref eq)) (result (ref eq)) ;; ZZZ check binary channel? (local $r i32) (local $len i32) - (local $header (ref $string)) (local $buf (ref $string)) + (local $header (ref $bytes)) (local $buf (ref $bytes)) (local $s (ref $intern_state)) (local $h (ref $marshal_header)) - (local.set $header (array.new $string (i32.const 0) (i32.const 20))) + (local.set $header (array.new $bytes (i32.const 0) (i32.const 20))) (local.set $r (call $caml_really_getblock (local.get $ch) (local.get $header) (i32.const 0) (i32.const 20))) (if (i32.eqz (local.get $r)) (then (call $caml_raise_end_of_file))) (if (i32.lt_u (local.get $r) (i32.const 20)) - (then - (call $caml_failwith - (array.new_data $string $truncated_obj - (i32.const 0) (i32.const 29))))) + (then (call $caml_failwith (global.get $truncated_obj)))) (local.set $s (call $get_intern_state (local.get $header) (i32.const 0))) (local.set $h (call $parse_header (local.get $s) (global.get $input_value))) (local.set $len (struct.get $marshal_header $data_len (local.get $h))) - (local.set $buf (array.new $string (i32.const 0) (local.get $len))) + (local.set $buf (array.new $bytes (i32.const 0) (local.get $len))) (if (i32.lt_u (call $caml_really_getblock (local.get $ch) (local.get $buf) (i32.const 0) (local.get $len)) (local.get $len)) - (then - (call $caml_failwith - (array.new_data $string $truncated_obj - (i32.const 0) (i32.const 29))))) + (then (call $caml_failwith (global.get $truncated_obj)))) (local.set $s (call $get_intern_state (local.get $buf) (i32.const 0))) (return_call $intern_rec (local.get $s) (local.get $h))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $float (struct (field f64))) (type $float_array (array (mut f64))) (type $js (struct (field anyref))) @@ -140,7 +145,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -181,13 +186,13 @@ (type $intern_state (struct - (field $src (ref $string)) + (field $src (ref $bytes)) (field $pos (mut i32)) (field $obj_table (mut (ref null $block))) (field $obj_counter (mut i32)))) (func $get_intern_state - (param $src (ref $string)) (param $pos i32) (result (ref $intern_state)) + (param $src (ref $bytes)) (param $pos i32) (result (ref $intern_state)) (struct.new $intern_state (local.get $src) (local.get $pos) (ref.null $block) (i32.const 0))) @@ -195,7 +200,7 @@ (local $pos i32) (local $res i32) (local.set $pos (struct.get $intern_state $pos (local.get $s))) (local.set $res - (array.get_u $string + (array.get_u $bytes (struct.get $intern_state $src (local.get $s)) (local.get $pos))) (struct.set $intern_state $pos (local.get $s) @@ -206,7 +211,7 @@ (local $pos i32) (local $res i32) (local.set $pos (struct.get $intern_state $pos (local.get $s))) (local.set $res - (array.get_s $string + (array.get_s $bytes (struct.get $intern_state $src (local.get $s)) (local.get $pos))) (struct.set $intern_state $pos (local.get $s) @@ -214,84 +219,84 @@ (local.get $res)) (func $read16u (param $s (ref $intern_state)) (result i32) - (local $src (ref $string)) (local $pos i32) (local $res i32) + (local $src (ref $bytes)) (local $pos i32) (local $res i32) (local.set $src (struct.get $intern_state $src (local.get $s))) (local.set $pos (struct.get $intern_state $pos (local.get $s))) (local.set $res (i32.or (i32.shl - (array.get_u $string (local.get $src) (local.get $pos)) + (array.get_u $bytes (local.get $src) (local.get $pos)) (i32.const 8)) - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (i32.const 1))))) (struct.set $intern_state $pos (local.get $s) (i32.add (local.get $pos) (i32.const 2))) (local.get $res)) (func $read16s (param $s (ref $intern_state)) (result i32) - (local $src (ref $string)) (local $pos i32) (local $res i32) + (local $src (ref $bytes)) (local $pos i32) (local $res i32) (local.set $src (struct.get $intern_state $src (local.get $s))) (local.set $pos (struct.get $intern_state $pos (local.get $s))) (local.set $res (i32.or (i32.shl - (array.get_s $string (local.get $src) (local.get $pos)) + (array.get_s $bytes (local.get $src) (local.get $pos)) (i32.const 8)) - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (i32.const 1))))) (struct.set $intern_state $pos (local.get $s) (i32.add (local.get $pos) (i32.const 2))) (local.get $res)) (func $read32 (param $s (ref $intern_state)) (result i32) - (local $src (ref $string)) (local $pos i32) (local $res i32) + (local $src (ref $bytes)) (local $pos i32) (local $res i32) (local.set $src (struct.get $intern_state $src (local.get $s))) (local.set $pos (struct.get $intern_state $pos (local.get $s))) (local.set $res (i32.or (i32.or (i32.shl - (array.get_u $string (local.get $src) (local.get $pos)) + (array.get_u $bytes (local.get $src) (local.get $pos)) (i32.const 24)) (i32.shl - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (i32.const 1))) (i32.const 16))) (i32.or (i32.shl - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (i32.const 2))) (i32.const 8)) - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (i32.const 3)))))) (struct.set $intern_state $pos (local.get $s) (i32.add (local.get $pos) (i32.const 4))) (local.get $res)) - (func $readblock (param $s (ref $intern_state)) (param $str (ref $string)) + (func $readblock (param $s (ref $intern_state)) (param $str (ref $bytes)) (local $len i32) (local $pos i32) (local.set $len (array.len (local.get $str))) (local.set $pos (struct.get $intern_state $pos (local.get $s))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $str) (i32.const 0) (struct.get $intern_state $src (local.get $s)) (local.get $pos) (local.get $len)) (struct.set $intern_state $pos (local.get $s) (i32.add (local.get $pos) (local.get $len)))) - (func $readstr (param $s (ref $intern_state)) (result (ref $string)) - (local $len i32) (local $pos i32) (local $res (ref $string)) - (local $src (ref $string)) + (func $readstr (param $s (ref $intern_state)) (result (ref $bytes)) + (local $len i32) (local $pos i32) (local $res (ref $bytes)) + (local $src (ref $bytes)) (local.set $src (struct.get $intern_state $src (local.get $s))) (local.set $pos (struct.get $intern_state $pos (local.get $s))) (loop $loop - (if (array.get_u $string (local.get $src) + (if (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (local.get $len))) (then (local.set $len (i32.add (local.get $len) (i32.const 1))) (br $loop)))) - (local.set $res (array.new $string (i32.const 0) (local.get $len))) - (array.copy $string $string + (local.set $res (array.new $bytes (i32.const 0) (local.get $len))) + (array.copy $bytes $bytes (local.get $res) (i32.const 0) (local.get $src) (local.get $pos) (local.get $len)) @@ -301,7 +306,7 @@ (func $readfloat (param $s (ref $intern_state)) (param $code i32) (result f64) - (local $src (ref $string)) (local $pos i32) (local $res i32) + (local $src (ref $bytes)) (local $pos i32) (local $res i32) (local $d i64) (local $i i32) (local $v (ref eq)) @@ -316,7 +321,7 @@ (i64.or (i64.shl (local.get $d) (i64.const 8)) (i64.extend_i32_u - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (local.get $i)))))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $loop (i32.lt_u (local.get $i) (i32.const 8))))) @@ -326,7 +331,7 @@ (i64.rotr (i64.or (local.get $d) (i64.extend_i32_u - (array.get_u $string (local.get $src) + (array.get_u $bytes (local.get $src) (i32.add (local.get $pos) (local.get $i))))) (i64.const 8))) (local.set $i (i32.add (local.get $i) (i32.const 1))) @@ -394,13 +399,13 @@ (field $pos (mut i32)) (field $next (ref null $stack_item)))) - (data $integer_too_large "input_value: integer too large") - (data $code_pointer "input_value: code pointer") - (data $ill_formed "input_value: ill-formed message") + (#string $integer_too_large "input_value: integer too large") + (#string $code_pointer "input_value: code pointer") + (#string $ill_formed "input_value: ill-formed message") - (data $unknown_custom "input_value: unknown custom block identifier") - (data $expected_size "input_value: expected a fixed-size custom block") - (data $incorrect_size + (#string $unknown_custom "input_value: unknown custom block identifier") + (#string $expected_size "input_value: expected a fixed-size custom block") + (#string $incorrect_size "input_value: incorrect length of serialized custom block") (func $intern_custom @@ -437,17 +442,10 @@ (i32.ne (tuple.extract 2 1 (local.get $r)) (local.get $expected_size)) (i32.ne (local.get $code) (global.get $CODE_CUSTOM))) - (then - (call $caml_failwith - (array.new_data $string $incorrect_size - (i32.const 0) (i32.const 56))))) + (then (call $caml_failwith (global.get $incorrect_size)))) (return (tuple.extract 2 0 (local.get $r)))) - (call $caml_failwith - (array.new_data $string $expected_size - (i32.const 0) (i32.const 47)))) - (call $caml_failwith - (array.new_data $string $unknown_custom - (i32.const 0) (i32.const 44))) + (call $caml_failwith (global.get $expected_size))) + (call $caml_failwith (global.get $unknown_custom)) (ref.i31 (i32.const 0))) (func $intern_rec @@ -460,7 +458,7 @@ (local $header i32) (local $tag i32) (local $size i32) (local $len i32) (local $pos i32) (local $pos' i32) (local $ofs i32) (local $b (ref $block)) - (local $str (ref $string)) + (local $str (ref $bytes)) (local $v (ref eq)) (call $caml_init_custom_operations) (local.set $res (array.new_fixed $block 1 (ref.i31 (i32.const 0)))) @@ -543,8 +541,7 @@ (local.get $code))) ;; default (call $caml_failwith - (array.new_data $string $ill_formed - (i32.const 0) (i32.const 31))) + (global.get $ill_formed)) (br $done)) ;; CUSTOM (local.set $v @@ -555,8 +552,7 @@ (br $done)) ;; CODEPOINTER (call $caml_failwith - (array.new_data $string $code_pointer - (i32.const 0) (i32.const 25))) + (global.get $code_pointer)) (br $done)) ;; DOUBLE_ARRAY32 (local.set $len @@ -600,8 +596,7 @@ (br $read_shared)) ;; INT64 (call $caml_failwith - (array.new_data $string $integer_too_large - (i32.const 0) (i32.const 30))) + (global.get $integer_too_large)) (br $done)) ;; INT32 (local.set $v (ref.i31 (call $read32 (local.get $s)))) @@ -632,9 +627,9 @@ (call $register_object (local.get $s) (local.get $v)) (br $done)) ;; read_string - (local.set $str (array.new $string (i32.const 0) (local.get $len))) + (local.set $str (array.new $bytes (i32.const 0) (local.get $len))) (call $readblock (local.get $s) (local.get $str)) - (local.set $v (local.get $str)) + (local.set $v (call $caml_string_of_bytes (local.get $str))) (call $register_object (local.get $s) (local.get $v)) (br $done)) ;; read_block @@ -656,26 +651,23 @@ (br $loop))) (array.get $block (local.get $res) (i32.const 0))) - (data $too_large ": object too large to be read back on a 32-bit platform") + (#string $too_large ": object too large to be read back on a 32-bit platform") - (func $too_large (param $prim (ref $string)) + (func $too_large (param $prim (ref eq)) (call $caml_failwith - (call $caml_string_concat (local.get $prim) - (array.new_data $string $too_large (i32.const 0) (i32.const 55))))) + (call $caml_string_concat (local.get $prim) (global.get $too_large)))) - (data $bad_object ": bad object") + (#string $bad_object ": bad object") - (func $bad_object (param $prim (ref $string)) + (func $bad_object (param $prim (ref eq)) (call $caml_failwith - (call $caml_string_concat (local.get $prim) - (array.new_data $string $bad_object (i32.const 0) (i32.const 12))))) + (call $caml_string_concat (local.get $prim) (global.get $bad_object)))) - (data $bad_length ": bad length") + (#string $bad_length ": bad length") - (func $bad_length (param $prim (ref $string)) + (func $bad_length (param $prim (ref eq)) (call $caml_failwith - (call $caml_string_concat (local.get $prim) - (array.new_data $string $bad_length (i32.const 0) (i32.const 12))))) + (call $caml_string_concat (local.get $prim) (global.get $bad_length)))) (type $marshal_header (struct @@ -683,17 +675,15 @@ (field $num_objects i32))) (func $parse_header - (param $s (ref $intern_state)) (param $prim (ref $string)) + (param $s (ref $intern_state)) (param $prim (ref eq)) (result (ref $marshal_header)) (local $magic i32) (local $data_len i32) (local $num_objects i32) (local $whsize i32) (local.set $magic (call $read32 (local.get $s))) (if (i32.eq (local.get $magic) (global.get $Intext_magic_number_big)) - (then - (call $too_large (local.get $prim)))) + (then (call $too_large (local.get $prim)))) (if (i32.ne (local.get $magic) (global.get $Intext_magic_number_small)) - (then - (call $bad_object (local.get $prim)))) + (then (call $bad_object (local.get $prim)))) (local.set $data_len (call $read32 (local.get $s))) (local.set $num_objects (call $read32 (local.get $s))) (drop (call $read32 (local.get $s))) @@ -702,7 +692,7 @@ (local.get $data_len) (local.get $num_objects))) - (data $marshal_data_size "Marshal.data_size") + (#string $marshal_data_size "Marshal.data_size") (func (export "caml_marshal_data_size") (param $buf (ref eq)) (param $ofs (ref eq)) (result (ref eq)) @@ -710,19 +700,13 @@ (local $magic i32) (local.set $s (call $get_intern_state - (ref.cast (ref $string) (local.get $buf)) + (ref.cast (ref $bytes) (local.get $buf)) (i31.get_u (ref.cast (ref i31) (local.get $ofs))))) (local.set $magic (call $read32 (local.get $s))) (if (i32.eq (local.get $magic) (global.get $Intext_magic_number_big)) - (then - (call $too_large - (array.new_data $string $marshal_data_size - (i32.const 0) (i32.const 17))))) + (then (call $too_large (global.get $marshal_data_size)))) (if (i32.ne (local.get $magic) (global.get $Intext_magic_number_small)) - (then - (call $bad_object - (array.new_data $string $marshal_data_size - (i32.const 0) (i32.const 17))))) + (then (call $bad_object (global.get $marshal_data_size)))) (ref.i31 (i32.add (i32.sub (i32.const 20) @@ -733,7 +717,7 @@ (struct (field $next (mut (ref null $output_block))) (field $end (mut i32)) - (field $data (ref $string)))) + (field $data (ref $bytes)))) (type $extern_state (struct @@ -747,7 +731,7 @@ ;; Position of already marshalled objects (field $pos_table (ref any)) ;; Buffers - (field $buf (mut (ref $string))) + (field $buf (mut (ref $bytes))) (field $pos (mut i32)) (field $limit (mut i32)) (field $output_first (ref $output_block)) @@ -781,7 +765,7 @@ (local.get $output) (local.get $output))) - (data $buffer_overflow "Marshal.to_buffer: buffer overflow") + (#string $buffer_overflow "Marshal.to_buffer: buffer overflow") (global $SIZE_EXTERN_OUTPUT_BLOCK i32 (i32.const 8100)) @@ -789,7 +773,7 @@ (param $s (ref $extern_state)) (param $required i32) (result i32) (local $last (ref $output_block)) (local $blk (ref $output_block)) (local $pos i32) (local $extra i32) - (local $buf (ref $string)) + (local $buf (ref $bytes)) (local.set $pos (struct.get $extern_state $pos (local.get $s))) (if (i32.le_u (i32.add (local.get $pos) (local.get $required)) (struct.get $extern_state $limit (local.get $s))) @@ -798,10 +782,7 @@ (i32.add (local.get $pos) (local.get $required))) (return (local.get $pos)))) (if (struct.get $extern_state $user_provided_output (local.get $s)) - (then - (call $caml_failwith - (array.new_data $string $buffer_overflow - (i32.const 0) (i32.const 34))))) + (then (call $caml_failwith (global.get $buffer_overflow)))) (local.set $last (struct.get $extern_state $output_last (local.get $s))) (struct.set $output_block $end (local.get $last) (struct.get $extern_state $pos (local.get $s))) @@ -810,7 +791,7 @@ (then (local.set $extra (local.get $required)))) (local.set $buf - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.add (global.get $SIZE_EXTERN_OUTPUT_BLOCK) (local.get $extra)))) (local.set $blk (struct.new $output_block @@ -825,25 +806,25 @@ (array.len (local.get $buf))) (i32.const 0)) - (func $store16 (param $s (ref $string)) (param $pos i32) (param $n i32) - (array.set $string (local.get $s) (local.get $pos) + (func $store16 (param $s (ref $bytes)) (param $pos i32) (param $n i32) + (array.set $bytes (local.get $s) (local.get $pos) (i32.shr_u (local.get $n) (i32.const 8))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $pos) (i32.const 1)) (local.get $n))) - (func $store32 (param $s (ref $string)) (param $pos i32) (param $n i32) - (array.set $string (local.get $s) (local.get $pos) + (func $store32 (param $s (ref $bytes)) (param $pos i32) (param $n i32) + (array.set $bytes (local.get $s) (local.get $pos) (i32.shr_u (local.get $n) (i32.const 24))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $pos) (i32.const 1)) (i32.shr_u (local.get $n) (i32.const 16))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $pos) (i32.const 2)) (i32.shr_u (local.get $n) (i32.const 8))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $pos) (i32.const 3)) (local.get $n))) - (func $store64 (param $s (ref $string)) (param $pos i32) (param $n i64) + (func $store64 (param $s (ref $bytes)) (param $pos i32) (param $n i64) (call $store32 (local.get $s) (local.get $pos) (i32.wrap_i64 (i64.shr_u (local.get $n) (i64.const 32)))) (call $store32 (local.get $s) (i32.add (local.get $pos) (i32.const 4)) @@ -853,58 +834,71 @@ (local $pos i32) (local.set $pos (call $reserve_extern_output (local.get $s) (i32.const 1))) - (array.set $string (struct.get $extern_state $buf (local.get $s)) + (array.set $bytes (struct.get $extern_state $buf (local.get $s)) (local.get $pos) (local.get $c))) (func $writecode8 (param $s (ref $extern_state)) (param $c i32) (param $v i32) - (local $pos i32) (local $buf (ref $string)) + (local $pos i32) (local $buf (ref $bytes)) (local.set $pos (call $reserve_extern_output (local.get $s) (i32.const 2))) (local.set $buf (struct.get $extern_state $buf (local.get $s))) - (array.set $string (local.get $buf) (local.get $pos) (local.get $c)) - (array.set $string (local.get $buf) + (array.set $bytes (local.get $buf) (local.get $pos) (local.get $c)) + (array.set $bytes (local.get $buf) (i32.add (local.get $pos) (i32.const 1)) (local.get $v))) (func $writecode16 (param $s (ref $extern_state)) (param $c i32) (param $v i32) - (local $pos i32) (local $buf (ref $string)) + (local $pos i32) (local $buf (ref $bytes)) (local.set $pos (call $reserve_extern_output (local.get $s) (i32.const 3))) (local.set $buf (struct.get $extern_state $buf (local.get $s))) - (array.set $string (local.get $buf) (local.get $pos) (local.get $c)) + (array.set $bytes (local.get $buf) (local.get $pos) (local.get $c)) (call $store16 (local.get $buf) (i32.add (local.get $pos) (i32.const 1)) (local.get $v))) (func $writecode32 (param $s (ref $extern_state)) (param $c i32) (param $v i32) - (local $pos i32) (local $buf (ref $string)) + (local $pos i32) (local $buf (ref $bytes)) (local.set $pos (call $reserve_extern_output (local.get $s) (i32.const 5))) (local.set $buf (struct.get $extern_state $buf (local.get $s))) - (array.set $string (local.get $buf) (local.get $pos) (local.get $c)) + (array.set $bytes (local.get $buf) (local.get $pos) (local.get $c)) (call $store32 (local.get $buf) (i32.add (local.get $pos) (i32.const 1)) (local.get $v))) (func $writeblock - (param $s (ref $extern_state)) (param $str (ref $string)) + (param $s (ref $extern_state)) (param $str (ref $bytes)) (local $len i32) (local $pos i32) (local.set $len (array.len (local.get $str))) (local.set $pos (call $reserve_extern_output (local.get $s) (local.get $len))) - (array.copy $string $string + (array.copy $bytes $bytes (struct.get $extern_state $buf (local.get $s)) (local.get $pos) (local.get $str) (i32.const 0) (local.get $len))) + (func $writestring + (param $s (ref $extern_state)) (param $str anyref) (param $len i32) + (local $pos i32) + (local.set $len (call $jsstring_length (local.get $str))) + (local.set $pos + (call $reserve_extern_output (local.get $s) (local.get $len))) + (drop + (call $caml_blit_string ;; ZZZ lower level func? + (struct.new $js (local.get $str)) (ref.i31 (i32.const 0)) + (struct.get $extern_state $buf (local.get $s)) + (ref.i31 (local.get $pos)) + (ref.i31 (local.get $len))))) + (func $writefloat (param $s (ref $extern_state)) (param $f f64) - (local $pos i32) (local $buf (ref $string)) (local $d i64) (local $i i32) + (local $pos i32) (local $buf (ref $bytes)) (local $d i64) (local $i i32) (local.set $pos (call $reserve_extern_output (local.get $s) (i32.const 8))) (local.set $buf (struct.get $extern_state $buf (local.get $s))) (local.set $d (i64.reinterpret_f64 (local.get $f))) (loop $loop - (array.set $string (local.get $buf) + (array.set $bytes (local.get $buf) (i32.add (local.get $pos) (local.get $i)) (i32.wrap_i64 (i64.shr_u (local.get $d) @@ -914,7 +908,7 @@ (func $writefloats (param $s (ref $extern_state)) (param $b (ref $float_array)) - (local $pos i32) (local $sz i32) (local $buf (ref $string)) (local $d i64) + (local $pos i32) (local $sz i32) (local $buf (ref $bytes)) (local $d i64) (local $i i32) (local $j i32) (local.set $sz (array.len (local.get $b))) (local.set $pos @@ -930,7 +924,7 @@ (array.get $float_array (local.get $b) (local.get $j)))) (local.set $i (i32.const 0)) (loop $loop - (array.set $string (local.get $buf) + (array.set $bytes (local.get $buf) (i32.add (local.get $pos) (local.get $i)) (i32.wrap_i64 (i64.shr_u (local.get $d) @@ -1022,7 +1016,7 @@ (i32.or (local.get $tag) (i32.shl (local.get $sz) (i32.const 10))))))) - (func $extern_string (param $s (ref $extern_state)) (param $v (ref $string)) + (func $extern_bytes (param $s (ref $extern_state)) (param $v (ref $bytes)) (local $len i32) (local.set $len (array.len (local.get $v))) (if (i32.lt_u (local.get $len) (i32.const 0x20)) @@ -1038,6 +1032,22 @@ (local.get $len)))))) (call $writeblock (local.get $s) (local.get $v))) + (func $extern_string (param $s (ref $extern_state)) (param $v anyref) + (local $len i32) + (local.set $len (call $jsstring_length (local.get $v))) + (if (i32.lt_u (local.get $len) (i32.const 0x20)) + (then + (call $write (local.get $s) + (i32.add (global.get $PREFIX_SMALL_STRING) (local.get $len)))) + (else (if (i32.lt_u (local.get $len) (i32.const 0x100)) + (then + (call $writecode8 (local.get $s) (global.get $CODE_STRING8) + (local.get $len))) + (else + (call $writecode32 (local.get $s) (global.get $CODE_STRING32) + (local.get $len)))))) + (call $writestring (local.get $s) (local.get $v) (local.get $len))) + (func $extern_float (param $s (ref $extern_state)) (param $v f64) (call $write (local.get $s) (global.get $CODE_DOUBLE_LITTLE)) (call $writefloat (local.get $s) (local.get $v))) @@ -1055,14 +1065,14 @@ (global.get $CODE_DOUBLE_ARRAY32_LITTLE) (local.get $nfloats)))) (call $writefloats (local.get $s) (local.get $v))) - (data $incorrect_sizes "output_value: incorrect fixed sizes specified by ") + (#string $incorrect_sizes "output_value: incorrect fixed sizes specified by ") (func $extern_custom (param $s (ref $extern_state)) (param $v (ref $custom)) (result i32 i32) (local $ops (ref $custom_operations)) (local $serialize (ref $serialize)) (local $fixed_length (ref $fixed_length)) - (local $pos i32) (local $buf (ref $string)) + (local $pos i32) (local $buf (ref $bytes)) (local $r (tuple i32 i32)) (local.set $ops (struct.get $custom 0 (local.get $v))) (block $abstract @@ -1091,8 +1101,7 @@ (then (call $caml_failwith (call $caml_string_concat - (array.new_data $string $incorrect_sizes - (i32.const 0) (i32.const 49)) + (global.get $incorrect_sizes) (struct.get $custom_operations $id (local.get $ops)))))) (return (local.get $r))) @@ -1112,24 +1121,24 @@ (call $store32 (local.get $buf) (i32.add (local.get $pos) (i32.const 8)) (tuple.extract 2 1 (local.get $r))) (return (local.get $r))) - (call $caml_invalid_argument - (array.new_data $string $cust_value (i32.const 0) (i32.const 37))) + (call $caml_invalid_argument (global.get $cust_value)) (return (tuple.make 2 (i32.const 0) (i32.const 0)))) - (data $func_value "output_value: functional value") - (data $cont_value "output_value: continuation value") - (data $js_value "output_value: abstract value (JavaScript value)") - (data $abstract_value "output_value: abstract value") - (data $cust_value "output_value: abstract value (Custom)") + (#string $func_value "output_value: functional value") + (#string $cont_value "output_value: continuation value") + (#string $js_value "output_value: abstract value (JavaScript value)") + (#string $abstract_value "output_value: abstract value") + (#string $cust_value "output_value: abstract value (Custom)") (func $extern_rec (param $s (ref $extern_state)) (param $v (ref eq)) (local $sp (ref null $stack_item)) (local $item (ref $stack_item)) - (local $b (ref $block)) (local $str (ref $string)) + (local $b (ref $block)) (local $str (ref $bytes)) (local $fa (ref $float_array)) (local $hd i32) (local $tag i32) (local $sz i32) (local $pos i32) (local $r (tuple i32 i32)) + (local $js anyref) (loop $loop (block $next_item (drop (block $not_int (result (ref eq)) @@ -1187,9 +1196,9 @@ (call $extern_record_location (local.get $s) (local.get $v)) (drop (block $not_string (result (ref eq)) (local.set $str - (br_on_cast_fail $not_string (ref eq) (ref $string) + (br_on_cast_fail $not_string (ref eq) (ref $bytes) (local.get $v))) - (call $extern_string (local.get $s) (local.get $str)) + (call $extern_bytes (local.get $s) (local.get $str)) (local.set $sz (array.len (local.get $str))) (call $extern_size (local.get $s) (i32.add (i32.const 1) @@ -1228,23 +1237,27 @@ (i32.const 3))) (br $next_item))) (if (call $caml_is_closure (local.get $v)) - (then - (call $caml_invalid_argument - (array.new_data $string $func_value - (i32.const 0) (i32.const 30))))) + (then (call $caml_invalid_argument (global.get $func_value)))) (if (call $caml_is_continuation (local.get $v)) - (then - (call $caml_invalid_argument - (array.new_data $string $cont_value - (i32.const 0) (i32.const 32))))) - (if (ref.test (ref $js) (local.get $v)) - (then - (call $caml_invalid_argument - (array.new_data $string $js_value - (i32.const 0) (i32.const 47))))) - (call $caml_invalid_argument - (array.new_data $string $abstract_value - (i32.const 0) (i32.const 28))) + (then (call $caml_invalid_argument (global.get $cont_value)))) + (drop (block $not_js (result (ref eq)) + (local.set $js + (struct.get $js 0 + (br_on_cast_fail $not_js (ref eq) (ref $js) + (local.get $v)))) + (if (call $jsstring_test (local.get $js)) + (then + (call $extern_string (local.get $s) (local.get $js)) + (local.set $sz (call $jsstring_length (local.get $js))) + (call $extern_size (local.get $s) + (i32.add (i32.const 1) + (i32.shr_u (local.get $sz) (i32.const 2))) + (i32.add (i32.const 1) + (i32.shr_u (local.get $sz) (i32.const 3)))) + (br $next_item))) + (call $caml_invalid_argument (global.get $js_value)) + (ref.i31 (i32.const 0)))) + (call $caml_invalid_argument (global.get $abstract_value)) ) ;; next_item (block $done @@ -1291,9 +1304,9 @@ (func $extern_value (param $flags (ref eq)) (param $output (ref $output_block)) (param $pos i32) (param $user_provided_output i32) (param $v (ref eq)) - (result i32 (ref $string) (ref $extern_state)) + (result i32 (ref $bytes) (ref $extern_state)) (local $s (ref $extern_state)) (local $len i32) - (local $header (ref $string)) + (local $header (ref $bytes)) (local.set $s (call $init_extern_state (local.get $flags) (local.get $output) (local.get $pos) @@ -1301,7 +1314,7 @@ (call $extern_rec (local.get $s) (local.get $v)) (local.set $len (call $extern_output_length (local.get $s) (local.get $pos))) - (local.set $header (array.new $string (i32.const 0) (i32.const 20))) + (local.set $header (array.new $bytes (i32.const 0) (i32.const 20))) (call $store32 (local.get $header) (i32.const 0) (global.get $Intext_magic_number_small)) (call $store32 (local.get $header) (i32.const 4) (local.get $len)) @@ -1313,32 +1326,43 @@ (struct.get $extern_state $size_64 (local.get $s))) (tuple.make 3 (local.get $len) (local.get $header) (local.get $s))) +(#if use-js-string +(#then (func (export "caml_output_value_to_string") (param $v (ref eq)) (param $flags (ref eq)) (result (ref eq)) - (local $r (tuple i32 (ref $string) (ref $extern_state))) + (return_call $caml_string_of_bytes + (call $caml_output_value_to_bytes (local.get $v) (local.get $flags)))) +) +(#else + (export "caml_output_value_to_string" (func $caml_output_value_to_bytes)) +)) + + (func $caml_output_value_to_bytes (export "caml_output_value_to_bytes") + (param $v (ref eq)) (param $flags (ref eq)) (result (ref eq)) + (local $r (tuple i32 (ref $bytes) (ref $extern_state))) (local $blk (ref $output_block)) (local $pos i32) (local $len i32) - (local $res (ref $string)) + (local $res (ref $bytes)) (local.set $blk (struct.new $output_block (ref.null $output_block) (global.get $SIZE_EXTERN_OUTPUT_BLOCK) - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (global.get $SIZE_EXTERN_OUTPUT_BLOCK)))) (local.set $r (call $extern_value (local.get $flags) (local.get $blk) (i32.const 0) (i32.const 0) (local.get $v))) (local.set $res - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.add (tuple.extract 3 0 (local.get $r)) (i32.const 20)))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $res) (i32.const 0) (tuple.extract 3 1 (local.get $r)) (i32.const 0) (i32.const 20)) (local.set $pos (i32.const 20)) (loop $loop (block $done (local.set $len (struct.get $output_block $end (local.get $blk))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $res) (local.get $pos) (struct.get $output_block $data (local.get $blk)) (i32.const 0) (local.get $len)) @@ -1352,10 +1376,10 @@ (func (export "caml_output_value_to_buffer") (param $vbuf (ref eq)) (param $vpos (ref eq)) (param $vlen (ref eq)) (param $v (ref eq)) (param $flags (ref eq)) (result (ref eq)) - (local $buf (ref $string)) (local $pos i32) (local $len i32) - (local $r (tuple i32 (ref $string) (ref $extern_state))) + (local $buf (ref $bytes)) (local $pos i32) (local $len i32) + (local $r (tuple i32 (ref $bytes) (ref $extern_state))) (local $blk (ref $output_block)) - (local.set $buf (ref.cast (ref $string) (local.get $vbuf))) + (local.set $buf (ref.cast (ref $bytes) (local.get $vbuf))) (local.set $pos (i31.get_u (ref.cast (ref i31) (local.get $vpos)))) (local.set $len (i31.get_u (ref.cast (ref i31) (local.get $vlen)))) (local.set $blk @@ -1370,7 +1394,7 @@ (i32.add (local.get $pos) (i32.const 20)) (i32.const 1) (local.get $v))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $buf) (local.get $pos) (tuple.extract 3 1 (local.get $r)) (i32.const 0) (i32.const 20)) (ref.i31 (i32.const 0))) @@ -1378,15 +1402,15 @@ (func (export "caml_output_value") (param $ch (ref eq)) (param $v (ref eq)) (param $flags (ref eq)) (result (ref eq)) - (local $r (tuple i32 (ref $string) (ref $extern_state))) + (local $r (tuple i32 (ref $bytes) (ref $extern_state))) (local $blk (ref $output_block)) (local $len i32) - (local $res (ref $string)) + (local $res (ref $bytes)) ;; ZZZ check if binary channel? (local.set $blk (struct.new $output_block (ref.null $output_block) (global.get $SIZE_EXTERN_OUTPUT_BLOCK) - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (global.get $SIZE_EXTERN_OUTPUT_BLOCK)))) (local.set $r (call $extern_value @@ -1414,7 +1438,7 @@ (local.set $s (ref.cast (ref $extern_state) (local.get $vs))) (local.set $pos (call $reserve_extern_output (local.get $s) (i32.const 1))) - (array.set $string (struct.get $extern_state $buf (local.get $s)) + (array.set $bytes (struct.get $extern_state $buf (local.get $s)) (local.get $pos) (local.get $i))) (func (export "caml_serialize_int_2") (param $vs (ref eq)) (param $i i32) diff --git a/runtime/wasm/md5.wat b/runtime/wasm/md5.wat index c8149eca6b..ada3645788 100644 --- a/runtime/wasm/md5.wat +++ b/runtime/wasm/md5.wat @@ -18,11 +18,15 @@ (module (import "io" "caml_getblock" (func $caml_getblock - (param (ref eq)) (param (ref $string)) (param i32) (param i32) + (param (ref eq)) (param (ref $bytes)) (param i32) (param i32) (result i32))) (import "fail" "caml_raise_end_of_file" (func $caml_raise_end_of_file)) + (import "string" "caml_bytes_of_string" + (func $caml_bytes_of_string (param (ref eq)) (result (ref eq)))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) (type $int_array (array (mut i32))) (type $context @@ -30,13 +34,25 @@ (field (ref $int_array)) ;; w (field (mut i64)) ;; len (field (ref $int_array)) ;; buffer - (field (ref $string)))) ;; intermediate buffer + (field (ref $bytes)))) ;; intermediate buffer - (func (export "caml_md5_string") (export "caml_md5_bytes") +(#if use-js-string +(#then + (func (export "caml_md5_string") + (param (ref eq)) (param (ref eq)) (param (ref eq)) (result (ref eq)) + (return_call $caml_md5_bytes + (call $caml_bytes_of_string (local.get 0)) + (local.get 1) (local.get 2))) +) +(#else + (export "caml_md5_string" (func $caml_md5_bytes)) +)) + + (func $caml_md5_bytes (export "caml_md5_bytes") (param (ref eq)) (param (ref eq)) (param (ref eq)) (result (ref eq)) (local $ctx (ref $context)) (local.set $ctx (call $MD5Init)) - (call $MD5Update (local.get $ctx) (ref.cast (ref $string) (local.get 0)) + (call $MD5Update (local.get $ctx) (ref.cast (ref $bytes) (local.get 0)) (i31.get_u (ref.cast (ref i31) (local.get 1))) (i31.get_u (ref.cast (ref i31) (local.get 2)))) (return_call $MD5Final (local.get $ctx))) @@ -44,10 +60,10 @@ (func (export "caml_md5_chan") (param $ch (ref eq)) (param $vlen (ref eq)) (result (ref eq)) (local $len i32) (local $read i32) - (local $buf (ref $string)) + (local $buf (ref $bytes)) (local $ctx (ref $context)) (local.set $len (i31.get_s (ref.cast (ref i31) (local.get $vlen)))) - (local.set $buf (array.new $string (i32.const 0) (i32.const 4096))) + (local.set $buf (array.new $bytes (i32.const 0) (i32.const 4096))) (local.set $ctx (call $MD5Init)) (if (i32.lt_s (local.get $len) (i32.const 0)) (then @@ -124,24 +140,24 @@ (local.get $a) (local.get $b) (local.get $x) (local.get $s) (local.get $t))) - (func $get_32 (param $s (ref $string)) (param $p i32) (result i32) + (func $get_32 (param $s (ref $bytes)) (param $p i32) (result i32) (i32.or (i32.or - (array.get_u $string (local.get $s) (local.get $p)) - (i32.shl (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (local.get $p)) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1))) (i32.const 8))) (i32.or - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 2))) (i32.const 16)) - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 3))) (i32.const 24))))) (func $MD5Transform (param $w (ref $int_array)) (param $buffer (ref $int_array)) - (param $buffer' (ref $string)) (param $p i32) + (param $buffer' (ref $bytes)) (param $p i32) (local $i i32) (local $a i32) (local $b i32) (local $c i32) (local $d i32) (loop $loop @@ -430,10 +446,10 @@ (i32.const 0x98BADCFE) (i32.const 0x10325476)) (i64.const 0) (array.new $int_array (i32.const 0) (i32.const 16)) - (array.new $string (i32.const 0) (i32.const 64)))) + (array.new $bytes (i32.const 0) (i32.const 64)))) (func $MD5Update - (param $ctx (ref $context)) (param $input (ref $string)) + (param $ctx (ref $context)) (param $input (ref $bytes)) (param $input_pos i32) (param $input_len i32) (local $in_buf i32) (local $len i64) (local $missing i32) @@ -447,13 +463,13 @@ (local.set $missing (i32.sub (i32.const 64) (local.get $in_buf))) (if (i32.lt_u (local.get $input_len) (local.get $missing)) (then - (array.copy $string $string + (array.copy $bytes $bytes (struct.get $context 3 (local.get $ctx)) (local.get $missing) (local.get $input) (local.get $input_pos) (local.get $input_len)) (return))) - (array.copy $string $string + (array.copy $bytes $bytes (struct.get $context 3 (local.get $ctx)) (local.get $missing) (local.get $input) (local.get $input_pos) (local.get $missing)) @@ -479,20 +495,20 @@ (br $loop)))) (if (local.get $input_len) (then - (array.copy $string $string + (array.copy $bytes $bytes (struct.get $context 3 (local.get $ctx)) (i32.const 0) (local.get $input) (local.get $input_pos) (local.get $input_len))))) - (func $MD5Final (param $ctx (ref $context)) (result (ref $string)) + (func $MD5Final (param $ctx (ref $context)) (result (ref eq)) (local $in_buf i32) (local $i i32) (local $len i64) (local $w (ref $int_array)) - (local $buffer (ref $string)) (local $res (ref $string)) + (local $buffer (ref $bytes)) (local $res (ref $bytes)) (local.set $len (struct.get $context 1 (local.get $ctx))) (local.set $in_buf (i32.and (i32.wrap_i64 (local.get $len)) (i32.const 0x3f))) (local.set $buffer (struct.get $context 3 (local.get $ctx))) - (array.set $string (local.get $buffer) (local.get $in_buf) + (array.set $bytes (local.get $buffer) (local.get $in_buf) (i32.const 0x80)) (local.set $in_buf (i32.add (local.get $in_buf) (i32.const 1))) (if (i32.gt_u (local.get $in_buf) (i32.const 56)) @@ -501,7 +517,7 @@ (loop $loop (if (i32.lt_u (local.get $i) (i32.const 64)) (then - (array.set $string + (array.set $bytes (local.get $buffer) (local.get $i) (i32.const 0)) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br $loop)))) @@ -512,40 +528,40 @@ (local.set $in_buf (i32.const 0)))) (local.set $i (local.get $in_buf)) (loop $loop - (array.set $string (local.get $buffer) (local.get $i) (i32.const 0)) + (array.set $bytes (local.get $buffer) (local.get $i) (i32.const 0)) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $loop (i32.lt_u (local.get $i) (i32.const 56)))) (local.set $len (i64.shl (local.get $len) (i64.const 3))) - (array.set $string (local.get $buffer) (i32.const 56) + (array.set $bytes (local.get $buffer) (i32.const 56) (i32.wrap_i64 (local.get $len))) - (array.set $string (local.get $buffer) (i32.const 57) + (array.set $bytes (local.get $buffer) (i32.const 57) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 8)))) - (array.set $string (local.get $buffer) (i32.const 58) + (array.set $bytes (local.get $buffer) (i32.const 58) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 16)))) - (array.set $string (local.get $buffer) (i32.const 59) + (array.set $bytes (local.get $buffer) (i32.const 59) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 24)))) - (array.set $string (local.get $buffer) (i32.const 60) + (array.set $bytes (local.get $buffer) (i32.const 60) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 32)))) - (array.set $string (local.get $buffer) (i32.const 61) + (array.set $bytes (local.get $buffer) (i32.const 61) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 40)))) - (array.set $string (local.get $buffer) (i32.const 62) + (array.set $bytes (local.get $buffer) (i32.const 62) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 48)))) - (array.set $string (local.get $buffer) (i32.const 63) + (array.set $bytes (local.get $buffer) (i32.const 63) (i32.wrap_i64 (i64.shr_u (local.get $len) (i64.const 56)))) (call $MD5Transform (struct.get $context 0 (local.get $ctx)) (struct.get $context 2 (local.get $ctx)) (local.get $buffer) (i32.const 0)) - (local.set $res (array.new $string (i32.const 0) (i32.const 16))) + (local.set $res (array.new $bytes (i32.const 0) (i32.const 16))) (local.set $i (i32.const 0)) (local.set $w (struct.get $context 0 (local.get $ctx))) (loop $loop - (array.set $string (local.get $res) (local.get $i) + (array.set $bytes (local.get $res) (local.get $i) (i32.shr_u (array.get $int_array (local.get $w) (i32.shr_u (local.get $i) (i32.const 2))) (i32.shl (local.get $i) (i32.const 3)))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br_if $loop (i32.lt_u (local.get $i) (i32.const 16)))) - (local.get $res)) + (return_call $caml_string_of_bytes (local.get $res))) ) diff --git a/runtime/wasm/obj.wat b/runtime/wasm/obj.wat index f0057eee2a..908cfcae58 100644 --- a/runtime/wasm/obj.wat +++ b/runtime/wasm/obj.wat @@ -25,9 +25,13 @@ (func $caml_is_continuation (param (ref eq)) (result i32))) (import "effect" "caml_trampoline_ref" (global $caml_trampoline_ref (mut (ref null $function_1)))) + (import "jsstring" "jsstring_test" + (func $jsstring_test (param anyref) (result i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) + (type $js (struct (field anyref))) (type $float (struct (field f64))) (type $float_array (array (mut f64))) (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq)))) @@ -177,7 +181,7 @@ (param (ref eq)) (result (ref eq)) (local $orig (ref $block)) (local $res (ref $block)) (local $forig (ref $float_array)) (local $fres (ref $float_array)) - (local $s (ref $string)) (local $s' (ref $string)) + (local $s (ref $bytes)) (local $s' (ref $bytes)) (local $len i32) (drop (block $not_block (result (ref eq)) (local.set $orig (br_on_cast_fail $not_block (ref eq) (ref $block) @@ -202,11 +206,11 @@ (local.get $len)) (return (local.get $fres)))) (drop (block $not_string (result (ref eq)) - (local.set $s (br_on_cast_fail $not_string (ref eq) (ref $string) + (local.set $s (br_on_cast_fail $not_string (ref eq) (ref $bytes) (local.get 0))) (local.set $len (array.len (local.get $s))) - (local.set $s' (array.new $string (i32.const 0) (local.get $len))) - (array.copy $string $string + (local.set $s' (array.new $bytes (i32.const 0) (local.get $len))) + (array.copy $bytes $bytes (local.get $s') (i32.const 0) (local.get $s) (i32.const 0) (local.get $len)) (return (local.get $s')))) @@ -216,6 +220,8 @@ (struct.get $float 0 (br_on_cast_fail $not_float (ref eq) (ref $float) (local.get 0))))))) + (if (ref.test (ref $js) (local.get 0)) + (then (return (local.get 0)))) (call $caml_dup_custom (local.get 0))) (func (export "caml_obj_with_tag") @@ -246,7 +252,7 @@ (array.get $block (br_on_cast_fail $not_block (ref eq) (ref $block) (local.get $v)) (i32.const 0))))) - (if (ref.test (ref $string) (local.get $v)) + (if (ref.test (ref $bytes) (local.get $v)) (then (return (ref.i31 (global.get $string_tag))))) (if (ref.test (ref $float) (local.get $v)) (then (return (ref.i31 (global.get $float_tag))))) @@ -258,6 +264,13 @@ (then (return (ref.i31 (global.get $closure_tag))))) (if (call $caml_is_continuation (local.get $v)) (then (return (ref.i31 (global.get $cont_tag))))) + (drop (block $not_string (result (ref eq)) + (if (call $jsstring_test + (struct.get $js 0 + (br_on_cast_fail $not_string (ref eq) (ref $js) + (local.get $v)))) + (then (return (ref.i31 (global.get $string_tag))))) + (ref.i31 (i32.const 0)))) (ref.i31 (global.get $abstract_tag))) (func (export "caml_obj_make_forward") @@ -340,21 +353,18 @@ (local.get $v)) (ref.i31 (i32.const 0))) - (data $not_implemented "Obj.add_offset is not supported") + (#string $not_implemented "Obj.add_offset is not supported") (func (export "caml_obj_add_offset") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (call $caml_failwith - (array.new_data $string $not_implemented (i32.const 0) (i32.const 31))) + (call $caml_failwith (global.get $not_implemented)) (ref.i31 (i32.const 0))) - (data $truncate_not_implemented "Obj.truncate is not supported") + (#string $truncate_not_implemented "Obj.truncate is not supported") (func (export "caml_obj_truncate") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (call $caml_failwith - (array.new_data $string $truncate_not_implemented - (i32.const 0) (i32.const 29))) + (call $caml_failwith (global.get $truncate_not_implemented)) (ref.i31 (i32.const 0))) (global $method_cache (mut (ref $int_array)) diff --git a/runtime/wasm/parsing.wat b/runtime/wasm/parsing.wat index 4e4a0bb29b..804ff8e196 100644 --- a/runtime/wasm/parsing.wat +++ b/runtime/wasm/parsing.wat @@ -16,16 +16,15 @@ ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. (module - (import "jslib" "wrap" (func $wrap (param anyref) (result (ref eq)))) - (import "jslib" "caml_string_of_jsstring" - (func $caml_string_of_jsstring (param (ref eq)) (result (ref eq)))) (import "io" "caml_stderr" (global $caml_stderr (mut (ref eq)))) - (import "io" "caml_ml_open_descriptor_out" - (func $caml_ml_open_descriptor_out (param (ref eq)) (result (ref eq)))) (import "io" "caml_ml_output" (func $caml_ml_output (param (ref eq)) (param (ref eq)) (param (ref eq)) (param (ref eq)) (result (ref eq)))) + (import "io" "caml_ml_output_bytes" + (func $caml_ml_output_bytes + (param (ref eq)) (param (ref eq)) (param (ref eq)) (param (ref eq)) + (result (ref eq)))) (import "io" "caml_ml_flush" (func $caml_ml_flush (param (ref eq)) (result (ref eq)))) (import "ints" "caml_format_int" @@ -34,19 +33,64 @@ (import "float" "caml_format_float" (func $caml_format_float (param (ref eq)) (param (ref eq)) (result (ref eq)))) + (import "string" "caml_string_length" + (func $caml_string_length (param (ref eq)) (result i32))) (type $float (struct (field f64))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) + +(#if use-js-string +(#then + (import "wasm:js-string" "substring" + (func $string_substring (param externref i32 i32) (result (ref extern)))) + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + + (func $string_sub + (param $s externref) (param $i i32) (param $l i32) (result (ref eq)) + (struct.new $string + (any.convert_extern + (call $string_substring + (local.get $s) + (local.get $i) + (i32.add (local.get $i) (local.get $l)))))) + + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_sub + (param $s (ref $bytes)) (param $i i32) (param $l i32) (result (ref eq)) + (local $s' (ref $bytes)) + (local.set $s' (array.new $bytes (i32.const 0) (local.get $l))) + (array.copy $bytes $bytes + (local.get $s') (i32.const 0) + (local.get $s) (local.get $i) + (local.get $l)) + (local.get $s')) + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) - (func $get (param $a (ref eq)) (param $i i32) (result i32) - (local $s (ref $string)) - (local.set $s (ref.cast (ref $string) (local.get $a))) + (func $get +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $i i32) (result i32) (local.set $i (i32.add (local.get $i) (local.get $i))) (i32.extend16_s - (i32.or (array.get_u $string (local.get $s) (local.get $i)) + (i32.or (call $string_get (local.get $s) (local.get $i)) (i32.shl - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.add (local.get $i) (i32.const 1))) (i32.const 8))))) @@ -105,29 +149,41 @@ (global $tbl_names_const i32 (i32.const 15)) (global $tbl_names_block i32 (i32.const 16)) - (func $strlen (param $s (ref $string)) (param $p i32) (result i32) + (func $strlen +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $p i32) (result i32) (local $i i32) (local.set $i (local.get $p)) (loop $loop - (if (i32.ne (array.get_u $string (local.get $s) (local.get $i)) + (if (i32.ne (call $string_get (local.get $s) (local.get $i)) (i32.const 0)) (then (local.set $i (i32.add (local.get $i) (i32.const 1))) (br $loop)))) (i32.sub (local.get $i) (local.get $p))) - (data $unknown_token "") + (#string $unknown_token "") (func $token_name (param $vnames (ref eq)) (param $number i32) (result (ref eq)) - (local $names (ref $string)) (local $i i32) (local $len i32) - (local $name (ref $string)) - (local.set $names (ref.cast (ref $string) (local.get $vnames))) +(#if use-js-string +(#then + (local $names externref) +) +(#else + (local $names (ref $bytes)) +)) + (local $i i32) (local $len i32) + (local.set $names (call $string_val (local.get $vnames))) (loop $loop - (if (i32.eqz (array.get_u $string (local.get $names) (local.get $i))) + (if (i32.eqz (call $string_get (local.get $names) (local.get $i))) (then - (return - (array.new_data $string $unknown_token - (i32.const 0) (i32.const 15))))) + (return (global.get $unknown_token)))) (if (i32.ne (local.get $number) (i32.const 0)) (then (local.set $i @@ -137,35 +193,40 @@ (local.set $number (i32.sub (local.get $number) (i32.const 1))) (br $loop)))) (local.set $len (call $strlen (local.get $names) (local.get $i))) - (local.set $name (array.new $string (i32.const 0) (local.get $len))) - (array.copy $string $string - (local.get $name) (i32.const 0) - (local.get $names) (local.get $i) (local.get $len)) - (local.get $name)) + (return_call $string_sub + (local.get $names) (local.get $i) (local.get $len))) - (func $output (param (ref eq)) - (local $s (ref $string)) - (local.set $s (ref.cast (ref $string) (local.get 0))) + (func $output (param $s (ref eq)) (drop (call $caml_ml_output (global.get $caml_stderr) + (local.get $s) (ref.i31 (i32.const 0)) + (ref.i31 (call $caml_string_length (local.get $s)))))) + + (func $output_bytes (param (ref eq)) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (drop + (call $caml_ml_output_bytes (global.get $caml_stderr) (local.get $s) (ref.i31 (i32.const 0)) (ref.i31 (array.len (local.get $s)))))) (func $output_nl (drop - (call $caml_ml_output (global.get $caml_stderr) - (array.new_fixed $string 1 (i32.const 10)) + (call $caml_ml_output_bytes (global.get $caml_stderr) + (array.new_fixed $bytes 1 (i32.const 10)) (ref.i31 (i32.const 0)) (ref.i31 (i32.const 1)))) (drop (call $caml_ml_flush (global.get $caml_stderr)))) + (#string $int_format "%d") + (func $output_int (param i32) (call $output - (call $caml_format_int - (array.new_fixed $string 2 (i32.const 37) (i32.const 100)) + (call $caml_format_int (global.get $int_format) (ref.i31 (local.get 0))))) - (data $State "State ") - (data $read_token ": read token ") + (#string $State "State ") + (#string $read_token ": read token ") + (#string $float_format "%g") (func $print_token (param $tables (ref $block)) (param $state i32) (param $tok (ref eq)) @@ -173,11 +234,9 @@ (local $v (ref eq)) (if (ref.test (ref i31) (local.get $tok)) (then - (call $output - (array.new_data $string $State (i32.const 0) (i32.const 6))) + (call $output (global.get $State)) (call $output_int (local.get $state)) - (call $output - (array.new_data $string $read_token (i32.const 0) (i32.const 13))) + (call $output (global.get $read_token)) (call $output (call $token_name (array.get $block (local.get $tables) @@ -185,11 +244,9 @@ (i31.get_u (ref.cast (ref i31) (local.get $tok))))) (call $output_nl)) (else - (call $output - (array.new_data $string $State (i32.const 0) (i32.const 6))) + (call $output (global.get $State)) (call $output_int (local.get $state)) - (call $output - (array.new_data $string $read_token (i32.const 0) (i32.const 13))) + (call $output (global.get $read_token)) (local.set $b (ref.cast (ref $block) (local.get $tok))) (call $output (call $token_name @@ -198,33 +255,31 @@ (i31.get_u (ref.cast (ref i31) (array.get $block (local.get $b) (i32.const 0)))))) - (call $output (array.new_fixed $string 1 (i32.const 40))) ;; "(" + (call $output_bytes (array.new_fixed $bytes 1 (i32.const 40))) ;; "(" (local.set $v (array.get $block (local.get $b) (i32.const 1))) (if (ref.test (ref i31) (local.get $v)) (then (call $output_int (i31.get_s (ref.cast (ref i31) (local.get $v))))) - (else (if (ref.test (ref $string) (local.get $v)) + (else (if (ref.test (ref $bytes) (local.get $v)) (then (call $output (local.get $v))) (else (if (ref.test (ref $float) (local.get $v)) (then (call $output - (call $caml_format_float - (array.new_fixed $string 2 - (i32.const 37) (i32.const 103)) + (call $caml_format_float (global.get $float_format) (local.get $v)))) (else - (call $output - (array.new_fixed $string 1 (i32.const 95))))))))) ;; '_' - (call $output (array.new_fixed $string 1 (i32.const 41))) ;; ")" + (call $output_bytes + (array.new_fixed $bytes 1 (i32.const 95))))))))) ;; '_' + (call $output_bytes (array.new_fixed $bytes 1 (i32.const 41))) ;; ")" (call $output_nl)))) - (data $recovering_in_state "Recovering in state ") - (data $discarding_state "Discarding state ") - (data $no_more_states_to_discard "No more states to discard") - (data $discarding_last_token_read "Discarding last token read") - (data $shift_to_state ": shift to state ") - (data $reduce_by_rule ": reduce by rule ") + (#string $recovering_in_state "Recovering in state ") + (#string $discarding_state "Discarding state ") + (#string $no_more_states_to_discard "No more states to discard") + (#string $discarding_last_token_read "Discarding last token read") + (#string $shift_to_state ": shift to state ") + (#string $reduce_by_rule ": reduce by rule ") (func (export "caml_parse_engine") (param $vtables (ref eq)) (param $venv (ref eq)) (param $vcmd (ref eq)) @@ -235,42 +290,56 @@ (local $errflag i32) (local $tables (ref $block)) (local $env (ref $block)) (local $cmd i32) (local $arg (ref $block)) - (local $tbl_defred (ref $string)) - (local $tbl_sindex (ref $string)) - (local $tbl_check (ref $string)) - (local $tbl_rindex (ref $string)) - (local $tbl_table (ref $string)) - (local $tbl_len (ref $string)) - (local $tbl_lhs (ref $string)) - (local $tbl_gindex (ref $string)) - (local $tbl_dgoto (ref $string)) +(#if use-js-string +(#then + (local $tbl_defred externref) + (local $tbl_sindex externref) + (local $tbl_check externref) + (local $tbl_rindex externref) + (local $tbl_table externref) + (local $tbl_len externref) + (local $tbl_lhs externref) + (local $tbl_gindex externref) + (local $tbl_dgoto externref) +) +(#else + (local $tbl_defred (ref $bytes)) + (local $tbl_sindex (ref $bytes)) + (local $tbl_check (ref $bytes)) + (local $tbl_rindex (ref $bytes)) + (local $tbl_table (ref $bytes)) + (local $tbl_len (ref $bytes)) + (local $tbl_lhs (ref $bytes)) + (local $tbl_gindex (ref $bytes)) + (local $tbl_dgoto (ref $bytes)) +)) (local.set $tables (ref.cast (ref $block) (local.get $vtables))) (local.set $tbl_defred - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_defred)))) (local.set $tbl_sindex - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_sindex)))) (local.set $tbl_check - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_check)))) (local.set $tbl_rindex - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_rindex)))) (local.set $tbl_table - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_table)))) (local.set $tbl_len - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_len)))) (local.set $tbl_lhs - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_lhs)))) (local.set $tbl_gindex - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_gindex)))) (local.set $tbl_dgoto - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $tables) (global.get $tbl_dgoto)))) (local.set $env (ref.cast (ref $block) (local.get $venv))) (local.set $cmd (i31.get_s (ref.cast (ref i31) (local.get $vcmd)))) @@ -461,10 +530,8 @@ (if (global.get $caml_parser_trace) (then (call $output - (array.new_data $string - $recovering_in_state - (i32.const 0) - (i32.const 20))) + (global.get + $recovering_in_state)) (call $output_int (local.get $state1)) (call $output_nl))) @@ -473,9 +540,7 @@ (br $next))))))) (if (global.get $caml_parser_trace) (then - (call $output - (array.new_data $string $discarding_state - (i32.const 0) (i32.const 17))) + (call $output (global.get $discarding_state)) (call $output_int (local.get $state1)) (call $output_nl))) (if (i32.le_s (local.get $sp) @@ -487,9 +552,7 @@ (if (global.get $caml_parser_trace) (then (call $output - (array.new_data $string - $no_more_states_to_discard - (i32.const 0) (i32.const 25))) + (global.get $no_more_states_to_discard)) (call $output_nl))) (return (ref.i31 (global.get $RAISE_PARSE_ERROR))))) (local.set $sp (i32.sub (local.get $sp) (i32.const 1))) @@ -504,8 +567,7 @@ (if (global.get $caml_parser_trace) (then (call $output - (array.new_data $string $discarding_last_token_read - (i32.const 0) (i32.const 26))) + (global.get $discarding_last_token_read)) (call $output_nl))) (array.set $block (local.get $env) (global.get $env_curr_char) @@ -523,13 +585,9 @@ ;; shift_recover: (if (global.get $caml_parser_trace) (then - (call $output - (array.new_data $string $State - (i32.const 0) (i32.const 6))) + (call $output (global.get $State)) (call $output_int (local.get $state)) - (call $output - (array.new_data $string $shift_to_state - (i32.const 0) (i32.const 17))) + (call $output (global.get $shift_to_state)) (call $output_int (call $get (local.get $tbl_table) (local.get $n2))) (call $output_nl))) @@ -573,12 +631,9 @@ ;; reduce: (if (global.get $caml_parser_trace) (then - (call $output - (array.new_data $string $State (i32.const 0) (i32.const 6))) + (call $output (global.get $State)) (call $output_int (local.get $state)) - (call $output - (array.new_data $string $reduce_by_rule - (i32.const 0) (i32.const 17))) + (call $output (global.get $reduce_by_rule)) (call $output_int (local.get $n)) (call $output_nl))) (local.set $m (call $get (local.get $tbl_len) (local.get $n))) diff --git a/runtime/wasm/printexc.wat b/runtime/wasm/printexc.wat index 84b616829d..e175f6d437 100644 --- a/runtime/wasm/printexc.wat +++ b/runtime/wasm/printexc.wat @@ -16,61 +16,84 @@ ;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. (module - (import "jslib" "unwrap" (func $unwrap (param (ref eq)) (result anyref))) - (import "jslib" "caml_jsstring_of_string" - (func $caml_jsstring_of_string (param (ref eq)) (result (ref eq)))) (import "fail" "caml_is_special_exception" (func $caml_is_special_exception (param (ref eq)) (result i32))) (import "ints" "caml_format_int" (func $caml_format_int (param (ref eq)) (param (ref eq)) (result (ref eq)))) + (import "string" "caml_string_length" + (func $caml_string_length (param (ref eq)) (result i32))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) + (import "string" "caml_blit_string" + (func $caml_blit_string + (param (ref eq) (ref eq) (ref eq) (ref eq) (ref eq)) + (result (ref eq)))) + (import "jsstring" "jsstring_test" + (func $jsstring_test (param anyref) (result i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $string (struct (field anyref))) + (type $bytes (array (mut i8))) (type $buffer (struct (field (mut i32)) - (field (ref $string)))) + (field (ref $bytes)))) (func $add_char (param $buf (ref $buffer)) (param $c i32) (local $pos i32) - (local $data (ref $string)) + (local $data (ref $bytes)) (local.set $pos (struct.get $buffer 0 (local.get $buf))) (local.set $data (struct.get $buffer 1 (local.get $buf))) (if (i32.lt_u (local.get $pos) (array.len (local.get $data))) (then - (array.set $string (local.get $data) (local.get $pos) (local.get $c)) + (array.set $bytes (local.get $data) (local.get $pos) (local.get $c)) (struct.set $buffer 0 (local.get $buf) (i32.add (local.get $pos) (i32.const 1)))))) - (func $add_string (param $buf (ref $buffer)) (param $v (ref eq)) + (func $add_string (param $buf (ref $buffer)) (param $s (ref eq)) (local $pos i32) (local $len i32) - (local $data (ref $string)) - (local $s (ref $string)) + (local $data (ref $bytes)) (local.set $pos (struct.get $buffer 0 (local.get $buf))) (local.set $data (struct.get $buffer 1 (local.get $buf))) - (local.set $s (ref.cast (ref $string) (local.get $v))) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $caml_string_length (local.get $s))) (if (i32.gt_u (i32.add (local.get $pos) (local.get $len)) (array.len (local.get $data))) (then (local.set $len (i32.sub (array.len (local.get $data)) (local.get $pos))))) - (array.copy $string $string - (local.get $data) (local.get $pos) - (local.get $s) (i32.const 0) - (local.get $len)) + (drop (call $caml_blit_string + (local.get $s) (ref.i31 (i32.const 0)) + (local.get $data) (ref.i31 (local.get $pos)) + (ref.i31 (local.get $len)))) (struct.set $buffer 0 (local.get $buf) (i32.add (local.get $pos) (local.get $len)))) +(#if use-js-string +(#then + (func $is_string (param $v (ref eq)) (result i32) + (drop (block $not_string (result (ref eq)) + (return_call $jsstring_test + (struct.get $string 0 + (br_on_cast_fail $not_string (ref eq) (ref $string) + (local.get $v)))))) + (i32.const 0)) +) +(#else + (func $is_string (param $v (ref eq)) (result i32) + (ref.test (ref $bytes) (local.get $v))) +)) + + (#string $int_format "%d") + (func (export "caml_format_exception") (param (ref eq)) (result (ref eq)) (local $exn (ref $block)) (local $buf (ref $buffer)) (local $v (ref eq)) (local $bucket (ref $block)) (local $i i32) (local $len i32) - (local $s (ref $string)) + (local $s (ref $bytes)) (local.set $exn (ref.cast (ref $block) (local.get 0))) (if (result (ref eq)) (ref.eq (array.get $block (local.get $exn) (i32.const 0)) @@ -79,7 +102,7 @@ (local.set $buf (struct.new $buffer (i32.const 0) - (array.new $string (i32.const 0) (i32.const 256)))) + (array.new $bytes (i32.const 0) (i32.const 256)))) (call $add_string (local.get $buf) (array.get $block @@ -120,10 +143,9 @@ (then (call $add_string (local.get $buf) (call $caml_format_int - (array.new_fixed $string 2 - (i32.const 37) (i32.const 100)) ;; %d + (global.get $int_format) (ref.cast (ref i31) (local.get $v))))) - (else (if (ref.test (ref $string) (local.get $v)) + (else (if (call $is_string (local.get $v)) (then (call $add_char (local.get $buf) (i32.const 34)) ;; '\"' @@ -143,13 +165,13 @@ (br $loop)))) (call $add_char (local.get $buf) (i32.const 41)))) ;; '\)' (local.set $s - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (struct.get $buffer 0 (local.get $buf)))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $s) (i32.const 0) (struct.get $buffer 1 (local.get $buf)) (i32.const 0) (struct.get $buffer 0 (local.get $buf))) - (local.get $s)) + (call $caml_string_of_bytes (local.get $s))) (else (array.get $block (local.get $exn) (i32.const 1))))) ) diff --git a/runtime/wasm/runtime.js b/runtime/wasm/runtime.js index 00adc8f4a6..34241c72dc 100644 --- a/runtime/wasm/runtime.js +++ b/runtime/wasm/runtime.js @@ -130,7 +130,27 @@ return (((h + (h << 2)) | 0) + (0xe6546b64 | 0)) | 0; } function hash_string(h, s) { - for (var i = 0; i < s.length; i++) h = hash_int(h, s.charCodeAt(i)); + const len = s.length; + for (var i = 0; i + 4 <= len; i += 4) { + var w = + s.charCodeAt(i) | + (s.charCodeAt(i + 1) << 8) | + (s.charCodeAt(i + 2) << 16) | + (s.charCodeAt(i + 3) << 24); + h = hash_int(h, w); + } + w = 0; + switch (len & 3) { + case 3: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: + w = s.charCodeAt(i + 2) << 16; + case 2: + // biome-ignore lint/suspicious/noFallthroughSwitchClause: + w |= s.charCodeAt(i + 1) << 8; + case 1: + w |= s.charCodeAt(i); + h = hash_int(h, w); + } return h ^ s.length; } @@ -221,12 +241,23 @@ ta_copy: (ta, t, s, n) => ta.copyWithin(t, s, n), ta_bytes: (a) => new Uint8Array(a.buffer, a.byteOffset, a.length * a.BYTES_PER_ELEMENT), - ta_blit_from_string: (s, p1, a, p2, l) => { + ta_blit_from_bytes: (s, p1, a, p2, l) => { for (let i = 0; i < l; i++) a[p2 + i] = string_get(s, p1 + i); }, - ta_blit_to_string: (a, p1, s, p2, l) => { + ta_blit_to_bytes: (a, p1, s, p2, l) => { for (let i = 0; i < l; i++) string_set(s, p2 + i, a[p1 + i]); }, + ta_blit_from_string: (s, p1, a, p2, l) => { + for (let i = 0; i < l; i++) a[p2 + i] = s.charCodeAt(p1 + i); + }, + ta_to_string: (a) => { + let len = a.length; + if (len <= 4096) return String.fromCharCode(...a); + var s = ""; + for (let i = 0; 0 < len; i += 1024, len -= 1024) + s += String.fromCharCode(...a.subarray(i, i + Math.min(len, 1024))); + return s; + }, wrap_callback: (f) => function (...args) { if (args.length === 0) { @@ -438,11 +469,16 @@ }; const string_ops = { test: (v) => +(typeof v === "string"), - compare: (s1, s2) => (s1 < s2 ? -1 : +(s1 > s2)), + compare: (s1, s2) => (s1 === s2 ? 0 : s1 < s2 ? -1 : 1), hash: hash_string, decodeStringFromUTF8Array: () => "", encodeStringToUTF8Array: () => 0, fromCharCodeArray: () => "", + length: (s) => s.length, + charCodeAt: (s, i) => s.charCodeAt(i), + concat: (s1, s2) => s1.concat(s2), + equals: (s1, s2) => +(s1 === s2), + substring: (s, i, j) => s.substring(i, j), }; const imports = Object.assign( { @@ -456,7 +492,10 @@ }, generated, ); - const options = { builtins: ["js-string", "text-decoder", "text-encoder"] }; + const options = { + builtins: ["js-string", "text-decoder", "text-encoder"], + importedStringConstants: "", + }; function loadRelative(src) { const path = require("node:path"); diff --git a/runtime/wasm/stdlib.wat b/runtime/wasm/stdlib.wat index 5176402152..63a445453b 100644 --- a/runtime/wasm/stdlib.wat +++ b/runtime/wasm/stdlib.wat @@ -22,11 +22,8 @@ (import "string" "caml_string_equal" (func $caml_string_equal (param (ref eq)) (param (ref eq)) (result (ref eq)))) - (import "jslib" "caml_string_of_jsstring" - (func $caml_string_of_jsstring (param (ref eq)) (result (ref eq)))) (import "jslib" "caml_jsstring_of_string" (func $caml_jsstring_of_string (param (ref eq)) (result (ref eq)))) - (import "jslib" "wrap" (func $wrap (param anyref) (result (ref eq)))) (import "jslib" "unwrap" (func $unwrap (param (ref eq)) (result anyref))) (import "obj" "caml_callback_1" (func $caml_callback_1 @@ -38,6 +35,8 @@ (import "string" "caml_string_concat" (func $caml_string_concat (param (ref eq)) (param (ref eq)) (result (ref eq)))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) (import "printexc" "caml_format_exception" (func $caml_format_exception (param (ref eq)) (result (ref eq)))) (import "sys" "ocaml_exit" (tag $ocaml_exit (param i32))) @@ -46,11 +45,12 @@ (import "bindings" "throw" (func $throw (param externref))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $assoc (struct - (field (ref $string)) + (field (ref eq)) (field (mut (ref eq))) (field (mut (ref null $assoc))))) @@ -117,9 +117,7 @@ (return (ref.i31 (i32.const 0)))) (array.set $assoc_array (global.get $named_value_table) (local.get $h) - (struct.new $assoc - (ref.cast (ref $string) (local.get 0)) - (local.get 1) (local.get $r))) + (struct.new $assoc (local.get 0) (local.get 1) (local.get $r))) (ref.i31 (i32.const 0))) ;; Used only for testing (tests-jsoo/bin), but inconvenient to pull out @@ -183,9 +181,9 @@ (type $func (func (result (ref eq)))) - (data $fatal_error "Fatal error: exception ") - (data $handle_uncaught_exception "Printexc.handle_uncaught_exception") - (data $do_at_exit "Pervasives.do_at_exit") + (#string $fatal_error "Fatal error: exception ") + (#string $handle_uncaught_exception "Printexc.handle_uncaught_exception") + (#string $do_at_exit "Pervasives.do_at_exit") (global $uncaught_exception (mut externref) (ref.null extern)) @@ -212,9 +210,7 @@ (call $caml_callback_2 (br_on_null $not_registered (call $caml_named_value - (array.new_data $string - $handle_uncaught_exception - (i32.const 0) (i32.const 34)))) + (global.get $handle_uncaught_exception))) (local.get $exn) (ref.i31 (i32.const 0)))) (br $exit)) @@ -222,19 +218,17 @@ (drop (call $caml_callback_1 (br_on_null $null - (call $caml_named_value - (array.new_data $string $do_at_exit - (i32.const 0) (i32.const 21)))) + (call $caml_named_value (global.get $do_at_exit))) (ref.i31 (i32.const 0))))) (call $write (i32.const 2) (call $unwrap (call $caml_jsstring_of_string (call $caml_string_concat - (array.new_data $string $fatal_error - (i32.const 0) (i32.const 23)) + (global.get $fatal_error) (call $caml_string_concat (call $caml_format_exception (local.get $exn)) - (array.new_fixed $string 1 - (i32.const 10)))))))) ;; `\n` - (call $exit (i32.const 2))))) + (call $caml_string_of_bytes + (array.new_fixed $bytes 1 + (i32.const 10))))))))) ;; `\n` + (call $exit (i32.const 2))))) ) diff --git a/runtime/wasm/str.wat b/runtime/wasm/str.wat index 4fa9409ee7..200547a4bd 100644 --- a/runtime/wasm/str.wat +++ b/runtime/wasm/str.wat @@ -19,8 +19,35 @@ (import "fail" "caml_invalid_argument" (func $caml_invalid_argument (param (ref eq)))) (import "fail" "caml_failwith" (func $caml_failwith (param (ref eq)))) + (import "string" "caml_string_of_bytes" + (func $caml_string_of_bytes (param (ref eq)) (result (ref eq)))) + (import "string" "caml_blit_string" + (func $caml_blit_string + (param (ref eq) (ref eq) (ref eq) (ref eq) (ref eq)) + (result (ref eq)))) - (type $string (array (mut i8))) +(#if use-js-string +(#then + (import "wasm:js-string" "length" + (func $string_length (param externref) (result i32))) + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + + (func $string_val (param $s (ref eq)) (result externref) + (extern.convert_any + (struct.get $string 0 (ref.cast (ref $string) (local.get $s))))) +) +(#else + (func $string_length (param $s (ref $bytes)) (result i32) + (array.len (local.get $s))) + (func $string_get (param $s (ref $bytes)) (param $i i32) (result i32) + (array.get $bytes (local.get $s) (local.get $i))) + (func $string_val (param $s (ref eq)) (result (ref $bytes)) + (ref.cast (ref $bytes) (local.get $s))) +)) + + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $block (array (mut (ref eq)))) (type $char_table (array i8)) @@ -67,24 +94,48 @@ (i32.shr_u (local.get $c) (i32.const 3))) (i32.and (local.get $c) (i32.const 7))))) - (func $in_bitset (param $s (ref $string)) (param $c i32) (result i32) + (func $in_bitset +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $c i32) (result i32) (i32.and (i32.const 1) (i32.shr_u - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.shr_u (local.get $c) (i32.const 3))) (i32.and (local.get $c) (i32.const 7))))) (func $re_match - (param $vre (ref eq)) (param $s (ref $string)) (param $pos i32) - (param $accept_partial_match i32) (result (ref eq)) + (param $vre (ref eq)) +(#if use-js-string +(#then + (param $s externref) +) +(#else + (param $s (ref $bytes)) +)) + (param $pos i32) (param $accept_partial_match i32) (result (ref eq)) (local $res (ref $block)) - (local $s' (ref $string)) (local $set (ref $string)) +(#if use-js-string +(#then + (local $s' externref) + (local $set externref) + (local $normtable externref) +) +(#else + (local $s' (ref $bytes)) + (local $set (ref $bytes)) + (local $normtable (ref $bytes)) +)) (local $len i32) (local $instr i32) (local $arg i32) (local $i i32) (local $j i32) (local $l i32) (local $re (ref $block)) (local $prog (ref $block)) (local $cpool (ref $block)) - (local $normtable (ref $string)) (local $numgroups i32) (local $numregisters i32) (local $group_start (ref $int_array)) @@ -94,7 +145,7 @@ (local $stack (ref null $stack)) (local $u (ref $undo)) (local $p (ref $pos)) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (local.set $re (ref.cast (ref $block) (local.get $vre))) (local.set $prog (ref.cast (ref $block) @@ -103,8 +154,7 @@ (ref.cast (ref $block) (array.get $block (local.get $re) (i32.const 2)))) (local.set $normtable - (ref.cast (ref $string) - (array.get $block (local.get $re) (i32.const 3)))) + (call $string_val (array.get $block (local.get $re) (i32.const 3)))) (local.set $numgroups (i31.get_s (ref.cast (ref i31) @@ -166,7 +216,7 @@ (i32.shr_u (local.get $instr) (i32.const 8))) (br_if $backtrack (i32.ne (local.get $arg) - (array.get_u $string + (call $string_get (local.get $s) (local.get $pos)))) (local.set $pos (i32.add (local.get $pos) (i32.const 1))) @@ -178,9 +228,9 @@ (i32.shr_u (local.get $instr) (i32.const 8))) (br_if $backtrack (i32.ne (local.get $arg) - (array.get_u $string + (call $string_get (local.get $normtable) - (array.get_u $string + (call $string_get (local.get $s) (local.get $pos))))) (local.set $pos (i32.add (local.get $pos) (i32.const 1))) @@ -189,11 +239,12 @@ (local.set $arg (i32.shr_u (local.get $instr) (i32.const 8))) (local.set $s' - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $cpool) - (i32.add (local.get $arg) (i32.const 1))))) + (i32.add (local.get $arg) + (i32.const 1))))) (local.set $i (i32.const 0)) - (local.set $l (array.len (local.get $s'))) + (local.set $l (call $string_length (local.get $s'))) (loop $loop (if (i32.lt_u (local.get $i) (local.get $l)) (then @@ -202,9 +253,9 @@ (local.get $pos) (local.get $len))) (br_if $backtrack (i32.ne - (array.get_u $string (local.get $s') + (call $string_get (local.get $s') (local.get $i)) - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos)))) (local.set $pos (i32.add (local.get $pos) (i32.const 1))) @@ -216,11 +267,12 @@ (local.set $arg (i32.shr_u (local.get $instr) (i32.const 8))) (local.set $s' - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $cpool) - (i32.add (local.get $arg) (i32.const 1))))) + (i32.add (local.get $arg) + (i32.const 1))))) (local.set $i (i32.const 0)) - (local.set $l (array.len (local.get $s'))) + (local.set $l (call $string_length (local.get $s'))) (loop $loop (if (i32.lt_u (local.get $i) (local.get $l)) (then @@ -229,11 +281,11 @@ (local.get $pos) (local.get $len))) (br_if $backtrack (i32.ne - (array.get_u $string (local.get $s') + (call $string_get (local.get $s') (local.get $i)) - (array.get_u $string + (call $string_get (local.get $normtable) - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos))))) (local.set $pos (i32.add (local.get $pos) (i32.const 1))) @@ -249,11 +301,11 @@ (br_if $backtrack (i32.eqz (call $in_bitset - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $cpool) (i32.add (local.get $arg) (i32.const 1)))) - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos))))) (local.set $pos (i32.add (local.get $pos) (i32.const 1))) @@ -262,7 +314,7 @@ (br_if $continue (i32.eqz (local.get $pos))) (br_if $continue (i32.eq (i32.const 10) ;; '\n' - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.sub (local.get $pos) (i32.const 1))))) (br $backtrack)) ;; EOL @@ -270,7 +322,7 @@ (i32.eq (local.get $pos) (local.get $len))) (br_if $continue (i32.eq (i32.const 10) ;; '\n' - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos)))) (br $backtrack)) ;; WORDBOUNDARY @@ -280,7 +332,7 @@ (i32.eq (local.get $pos) (local.get $len))) (br_if $continue (call $is_word_letter - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos)))) (br $backtrack)) (else @@ -288,7 +340,7 @@ (then (br_if $continue (call $is_word_letter - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.sub (local.get $pos) (i32.const 1))))) (br $backtrack)) @@ -296,11 +348,11 @@ (br_if $continue (i32.ne (call $is_word_letter - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (i32.sub (local.get $pos) (i32.const 1)))) (call $is_word_letter - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos))))) (br $backtrack)))))) ;; BEGGROUP @@ -348,9 +400,9 @@ (i32.eq (local.get $pos) (local.get $len))) (br_if $backtrack (i32.ne - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $i)) - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos)))) (local.set $pos (i32.add (local.get $pos) (i32.const 1))) @@ -363,10 +415,11 @@ (if (i32.lt_u (local.get $pos) (local.get $len)) (then (if (call $in_bitset - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $cpool) - (i32.add (local.get $arg) (i32.const 1)))) - (array.get_u $string (local.get $s) + (i32.add (local.get $arg) + (i32.const 1)))) + (call $string_get (local.get $s) (local.get $pos))) (then (local.set $pos @@ -375,14 +428,14 @@ ;; SIMPLESTAR (local.set $arg (i32.shr_u (local.get $instr) (i32.const 8))) (local.set $set - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $cpool) - (i32.add (local.get $arg) (i32.const 1))))) + (i32.add (local.get $arg) (i32.const 1))))) (loop $loop (if (i32.lt_u (local.get $pos) (local.get $len)) (then (if (call $in_bitset (local.get $set) - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos))) (then (local.set $pos @@ -393,20 +446,20 @@ (br_if $prefix_match (i32.eq (local.get $pos) (local.get $len))) (local.set $arg (i32.shr_u (local.get $instr) (i32.const 8))) (local.set $set - (ref.cast (ref $string) + (call $string_val (array.get $block (local.get $cpool) - (i32.add (local.get $arg) (i32.const 1))))) + (i32.add (local.get $arg) (i32.const 1))))) (br_if $backtrack (i32.eqz (call $in_bitset (local.get $set) - (array.get_u $string (local.get $s) (local.get $pos))))) + (call $string_get (local.get $s) (local.get $pos))))) (loop $loop (local.set $pos (i32.add (local.get $pos) (i32.const 1))) (if (i32.lt_u (local.get $pos) (local.get $len)) (then (br_if $loop (call $in_bitset (local.get $set) - (array.get_u $string (local.get $s) + (call $string_get (local.get $s) (local.get $pos))))))) (br $continue)) ;; GOTO @@ -507,23 +560,26 @@ ;; reject (ref.i31 (i32.const 0))) - (data $search_forward "Str.search_forward") + (#string $search_forward "Str.search_forward") (func (export "re_search_forward") (param $re (ref eq)) (param $vs (ref eq)) (param $vpos (ref eq)) (result (ref eq)) ;; ZZZ startchars - (local $s (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $pos i32) (local $len i32) (local $res (ref eq)) - (local.set $s (ref.cast (ref $string) (local.get $vs))) + (local.set $s (call $string_val (local.get $vs))) (local.set $pos (i31.get_s (ref.cast (ref i31) (local.get $vpos)))) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (if (i32.gt_u (local.get $pos) (local.get $len)) - (then - (call $caml_invalid_argument - (array.new_data $string $search_forward - (i32.const 0) (i32.const 18))))) + (then (call $caml_invalid_argument (global.get $search_forward)))) (loop $loop (local.set $res (call $re_match @@ -535,23 +591,26 @@ (br_if $loop (i32.le_u (local.get $pos) (local.get $len)))) (array.new_fixed $block 1 (ref.i31 (i32.const 0)))) - (data $search_backward "Str.search_backward") + (#string $search_backward "Str.search_backward") (func (export "re_search_backward") (param $re (ref eq)) (param $vs (ref eq)) (param $vpos (ref eq)) (result (ref eq)) ;; ZZZ startchars - (local $s (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $pos i32) (local $len i32) (local $res (ref eq)) - (local.set $s (ref.cast (ref $string) (local.get $vs))) + (local.set $s (call $string_val (local.get $vs))) (local.set $pos (i31.get_s (ref.cast (ref i31) (local.get $vpos)))) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (if (i32.gt_u (local.get $pos) (local.get $len)) - (then - (call $caml_invalid_argument - (array.new_data $string $search_backward - (i32.const 0) (i32.const 19))))) + (then (call $caml_invalid_argument (global.get $search_backward)))) (loop $loop (local.set $res (call $re_match @@ -563,23 +622,26 @@ (br_if $loop (i32.ge_s (local.get $pos) (i32.const 0)))) (array.new_fixed $block 1 (ref.i31 (i32.const 0)))) - (data $string_match "Str.string_match") + (#string $string_match "Str.string_match") (func (export "re_string_match") (param $re (ref eq)) (param $vs (ref eq)) (param $vpos (ref eq)) (result (ref eq)) ;; ZZZ startchars - (local $s (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $pos i32) (local $len i32) (local $res (ref eq)) - (local.set $s (ref.cast (ref $string) (local.get $vs))) + (local.set $s (call $string_val (local.get $vs))) (local.set $pos (i31.get_s (ref.cast (ref i31) (local.get $vpos)))) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (if (i32.gt_u (local.get $pos) (local.get $len)) - (then - (call $caml_invalid_argument - (array.new_data $string $string_match - (i32.const 0) (i32.const 16))))) + (then (call $caml_invalid_argument (global.get $string_match)))) (local.set $res (call $re_match (local.get $re) (local.get $s) (local.get $pos) (i32.const 0))) @@ -588,23 +650,26 @@ (return (local.get $res)))) (array.new_fixed $block 1 (ref.i31 (i32.const 0)))) - (data $string_partial_match "Str.string_partial_match") + (#string $string_partial_match "Str.string_partial_match") (func (export "re_partial_match") (param $re (ref eq)) (param $vs (ref eq)) (param $vpos (ref eq)) (result (ref eq)) ;; ZZZ startchars - (local $s (ref $string)) +(#if use-js-string +(#then + (local $s externref) +) +(#else + (local $s (ref $bytes)) +)) (local $pos i32) (local $len i32) (local $res (ref eq)) - (local.set $s (ref.cast (ref $string) (local.get $vs))) + (local.set $s (call $string_val (local.get $vs))) (local.set $pos (i31.get_s (ref.cast (ref i31) (local.get $vpos)))) - (local.set $len (array.len (local.get $s))) + (local.set $len (call $string_length (local.get $s))) (if (i32.gt_u (local.get $pos) (local.get $len)) - (then - (call $caml_invalid_argument - (array.new_data $string $string_partial_match - (i32.const 0) (i32.const 24))))) + (then (call $caml_invalid_argument (global.get $string_partial_match)))) (local.set $res (call $re_match (local.get $re) (local.get $s) (local.get $pos) (i32.const 1))) @@ -613,39 +678,40 @@ (return (local.get $res)))) (array.new_fixed $block 1 (ref.i31 (i32.const 0)))) - (data $illegal_backslash "Str.replace: illegal backslash sequence") - (data $unmatched_group "Str.replace: reference to unmatched group") + (#string $illegal_backslash "Str.replace: illegal backslash sequence") + (#string $unmatched_group "Str.replace: reference to unmatched group") (func (export "re_replacement_text") - (param $vrepl (ref eq)) (param $vgroups (ref eq)) (param $vorig (ref eq)) + (param $vrepl (ref eq)) (param $vgroups (ref eq)) (param $orig (ref eq)) (result (ref eq)) - (local $repl (ref $string)) +(#if use-js-string +(#then + (local $repl externref) +) +(#else + (local $repl (ref $bytes)) +)) (local $groups (ref $block)) - (local $orig (ref $string)) - (local $res (ref $string)) + (local $res (ref $bytes)) (local $i i32) (local $j i32) (local $l i32) (local $len i32) (local $c i32) (local $start i32) (local $end i32) - (local.set $repl (ref.cast (ref $string) (local.get $vrepl))) - (local.set $l (array.len (local.get $repl))) + (local.set $repl (call $string_val (local.get $vrepl))) + (local.set $l (call $string_length (local.get $repl))) (local.set $groups (ref.cast (ref $block) (local.get $vgroups))) - (local.set $orig (ref.cast (ref $string) (local.get $vorig))) (loop $loop (if (i32.lt_u (local.get $i) (local.get $l)) (then (local.set $c - (array.get_u $string (local.get $repl) (local.get $i))) + (call $string_get (local.get $repl) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.ne (local.get $c) (i32.const 92)) ;; '\\' (then (local.set $len (i32.add (local.get $len) (i32.const 1))) (br $loop))) (if (i32.eq (local.get $i) (local.get $l)) - (then - (call $caml_failwith - (array.new_data $string $illegal_backslash - (i32.const 0) (i32.const 39))))) + (then (call $caml_failwith (global.get $illegal_backslash)))) (local.set $c - (array.get_u $string (local.get $repl) (local.get $i))) + (call $string_get (local.get $repl) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.eq (local.get $c) (i32.const 92)) ;; '\\' (then @@ -659,10 +725,7 @@ (local.set $c (i32.shl (local.get $c) (i32.const 1))) (if (i32.gt_u (i32.add (local.get $c) (i32.const 1)) (array.len (local.get $groups))) - (then - (call $caml_failwith - (array.new_data $string $unmatched_group - (i32.const 0) (i32.const 41))))) + (then (call $caml_failwith (global.get $unmatched_group)))) (local.set $start (i31.get_s (ref.cast (ref i31) @@ -674,43 +737,40 @@ (array.get $block (local.get $groups) (i32.add (local.get $c) (i32.const 2)))))) (if (i32.eq (local.get $start) (i32.const -1)) - (then - (call $caml_failwith - (array.new_data $string $unmatched_group - (i32.const 0) (i32.const 41))))) + (then (call $caml_failwith (global.get $unmatched_group)))) (local.set $len (i32.add (local.get $len) (i32.sub (local.get $end) (local.get $start)))) (br $loop)))) - (local.set $res (array.new $string (i32.const 0) (local.get $len))) + (local.set $res (array.new $bytes (i32.const 0) (local.get $len))) (local.set $i (i32.const 0)) (loop $loop (if (i32.lt_u (local.get $i) (local.get $l)) (then (local.set $c - (array.get_u $string (local.get $repl) (local.get $i))) + (call $string_get (local.get $repl) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.ne (local.get $c) (i32.const 92)) ;; '\\' (then - (array.set $string (local.get $res) (local.get $j) + (array.set $bytes (local.get $res) (local.get $j) (local.get $c)) (local.set $j (i32.add (local.get $j) (i32.const 1))) (br $loop))) (local.set $c - (array.get_u $string (local.get $repl) (local.get $i))) + (call $string_get (local.get $repl) (local.get $i))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (if (i32.eq (local.get $c) (i32.const 92)) ;; '\\' (then - (array.set $string (local.get $res) (local.get $j) + (array.set $bytes (local.get $res) (local.get $j) (local.get $c)) (local.set $j (i32.add (local.get $j) (i32.const 1))) (br $loop))) (local.set $c (i32.sub (local.get $c) (i32.const 48))) ;; '0' (if (i32.gt_u (local.get $c) (i32.const 9)) (then - (array.set $string (local.get $res) (local.get $j) + (array.set $bytes (local.get $res) (local.get $j) (i32.const 92)) - (array.set $string (local.get $res) + (array.set $bytes (local.get $res) (i32.add (local.get $j) (i32.const 1)) (i32.add (local.get $c) (i32.const 48))) (local.set $j (i32.add (local.get $j) (i32.const 2))) @@ -718,10 +778,7 @@ (local.set $c (i32.shl (local.get $c) (i32.const 1))) (if (i32.gt_u (i32.add (local.get $c) (i32.const 1)) (array.len (local.get $groups))) - (then - (call $caml_failwith - (array.new_data $string $unmatched_group - (i32.const 0) (i32.const 41))))) + (then (call $caml_failwith (global.get $unmatched_group)))) (local.set $start (i31.get_s (ref.cast (ref i31) @@ -733,11 +790,12 @@ (array.get $block (local.get $groups) (i32.add (local.get $c) (i32.const 2)))))) (local.set $len (i32.sub (local.get $end) (local.get $start))) - (array.copy $string $string - (local.get $res) (local.get $j) - (local.get $orig) (local.get $start) - (local.get $len)) + (drop + (call $caml_blit_string + (local.get $orig) (ref.i31 (local.get $start)) + (local.get $res) (ref.i31 (local.get $j)) + (ref.i31 (local.get $len)))) (local.set $j (i32.add (local.get $j) (local.get $len))) (br $loop)))) - (local.get $res)) + (call $caml_string_of_bytes (local.get $res))) ) diff --git a/runtime/wasm/string.wat b/runtime/wasm/string.wat index bf43b2f9e4..e242c7026a 100644 --- a/runtime/wasm/string.wat +++ b/runtime/wasm/string.wat @@ -19,18 +19,122 @@ (import "fail" "caml_bound_error" (func $caml_bound_error)) (import "fail" "caml_invalid_argument" (func $caml_invalid_argument (param $arg (ref eq)))) + (import "wasm:js-string" "equals" + (func $string_equals (param externref externref) (result i32))) + (import "wasm:js-string" "compare" + (func $string_compare (param externref externref) (result i32))) + (import "wasm:js-string" "length" + (func $string_length (param externref) (result i32))) + (import "wasm:js-string" "charCodeAt" + (func $string_get (param externref i32) (result i32))) + (import "wasm:js-string" "concat" + (func $string_concat (param externref externref) (result (ref extern)))) + (import "jsstring" "jsbytes_of_bytes" + (func $jsbytes_of_bytes (param (ref $bytes)) (result anyref))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) - (export "caml_bytes_equal" (func $caml_string_equal)) +(#if use-js-string +(#then (func $caml_string_equal (export "caml_string_equal") (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) - (local $s1 (ref $string)) (local $s2 (ref $string)) + (ref.i31 + (call $string_equals + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p2))))))) + + (func (export "caml_string_notequal") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (return + (ref.i31 (i32.eqz (i31.get_u (ref.cast (ref i31) + (call $caml_string_equal (local.get $p1) (local.get $p2)))))))) + + (func (export "caml_string_compare") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (ref.i31 + (call $string_compare + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p2))))))) + + (func (export "caml_string_lessequal") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (ref.i31 + (i32.le_s + (call $string_compare + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p2))))) + (i32.const 0)))) + + (func (export "caml_string_lessthan") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (ref.i31 + (i32.lt_s + (call $string_compare + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p2))))) + (i32.const 0)))) + + (func (export "caml_string_greaterequal") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (ref.i31 + (i32.ge_s + (call $string_compare + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p2))))) + (i32.const 0)))) + + (func (export "caml_string_greaterthan") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (ref.i31 + (i32.gt_s + (call $string_compare + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $p2))))) + (i32.const 0)))) +) +(#else + (export "caml_string_equal" (func $caml_bytes_equal)) + (export "caml_string_notequal" (func $caml_bytes_notequal)) + (export "caml_string_compare" (func $caml_bytes_compare)) + (export "caml_string_lessequal" (func $caml_bytes_lessequal)) + (export "caml_string_lessthan" (func $caml_bytes_lessthan)) + (export "caml_string_greaterequal" (func $caml_bytes_greaterequal)) + (export "caml_string_greaterthan" (func $caml_bytes_greaterthan)) +)) + + (func $caml_bytes_equal (export "caml_bytes_equal") + (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) + (local $s1 (ref $bytes)) (local $s2 (ref $bytes)) (local $len i32) (local $i i32) (if (ref.eq (local.get $p1) (local.get $p2)) (then (return (ref.i31 (i32.const 1))))) - (local.set $s1 (ref.cast (ref $string) (local.get $p1))) - (local.set $s2 (ref.cast (ref $string) (local.get $p2))) + (local.set $s1 (ref.cast (ref $bytes) (local.get $p1))) + (local.set $s2 (ref.cast (ref $bytes) (local.get $p2))) (local.set $len (array.len (local.get $s1))) (if (i32.ne (local.get $len) (array.len (local.get $s2))) (then (return (ref.i31 (i32.const 0))))) @@ -38,29 +142,28 @@ (loop $loop (if (i32.lt_s (local.get $i) (local.get $len)) (then - (if (i32.ne (array.get_u $string (local.get $s1) (local.get $i)) - (array.get_u $string (local.get $s2) (local.get $i))) + (if (i32.ne (array.get_u $bytes (local.get $s1) (local.get $i)) + (array.get_u $bytes (local.get $s2) (local.get $i))) (then (return (ref.i31 (i32.const 0))))) (local.set $i (i32.add (local.get $i) (i32.const 1))) (br $loop)))) (ref.i31 (i32.const 1))) - (export "caml_bytes_notequal" (func $caml_string_notequal)) - (func $caml_string_notequal (export "caml_string_notequal") + (func $caml_bytes_notequal (export "caml_bytes_notequal") (param $p1 (ref eq)) (param $p2 (ref eq)) (result (ref eq)) (return (ref.i31 (i32.eqz (i31.get_u (ref.cast (ref i31) - (call $caml_string_equal (local.get $p1) (local.get $p2)))))))) + (call $caml_bytes_equal (local.get $p1) (local.get $p2)))))))) - (func $string_compare + (func $bytes_compare (param $p1 (ref eq)) (param $p2 (ref eq)) (result i32) - (local $s1 (ref $string)) (local $s2 (ref $string)) + (local $s1 (ref $bytes)) (local $s2 (ref $bytes)) (local $l1 i32) (local $l2 i32) (local $len i32) (local $i i32) (local $c1 i32) (local $c2 i32) (if (ref.eq (local.get $p1) (local.get $p2)) (then (return (i32.const 0)))) - (local.set $s1 (ref.cast (ref $string) (local.get $p1))) - (local.set $s2 (ref.cast (ref $string) (local.get $p2))) + (local.set $s1 (ref.cast (ref $bytes) (local.get $p1))) + (local.set $s2 (ref.cast (ref $bytes) (local.get $p2))) (local.set $l1 (array.len (local.get $s1))) (local.set $l2 (array.len (local.get $s2))) (local.set $len (select (local.get $l1) (local.get $l2) @@ -70,9 +173,9 @@ (if (i32.lt_s (local.get $i) (local.get $len)) (then (local.set $c1 - (array.get_u $string (local.get $s1) (local.get $i))) + (array.get_u $bytes (local.get $s1) (local.get $i))) (local.set $c2 - (array.get_u $string (local.get $s2) (local.get $i))) + (array.get_u $bytes (local.get $s2) (local.get $i))) (if (i32.lt_u (local.get $c1) (local.get $c2)) (then (return (i32.const -1)))) (if (i32.gt_u (local.get $c1) (local.get $c2)) @@ -85,62 +188,112 @@ (then (return (i32.const 1)))) (i32.const 0)) - (export "caml_bytes_compare" (func $caml_string_compare)) - (func $caml_string_compare (export "caml_string_compare") + (func $caml_bytes_compare (export "caml_bytes_compare") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (ref.i31 (call $string_compare (local.get 0) (local.get 1)))) + (ref.i31 (call $bytes_compare (local.get 0) (local.get 1)))) - (export "caml_bytes_lessequal" (func $caml_string_lessequal)) - (func $caml_string_lessequal (export "caml_string_lessequal") + (func $caml_bytes_lessequal (export "caml_bytes_lessequal") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (ref.i31 (i32.le_s (call $string_compare (local.get 0) (local.get 1)) + (ref.i31 (i32.le_s (call $bytes_compare (local.get 0) (local.get 1)) (i32.const 0)))) - (export "caml_bytes_lessthan" (func $caml_string_lessthan)) - (func $caml_string_lessthan (export "caml_string_lessthan") + (func $caml_bytes_lessthan (export "caml_bytes_lessthan") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (ref.i31 (i32.lt_s (call $string_compare (local.get 0) (local.get 1)) + (ref.i31 (i32.lt_s (call $bytes_compare (local.get 0) (local.get 1)) (i32.const 0)))) - (export "caml_bytes_greaterequal" (func $caml_string_greaterequal)) - (func $caml_string_greaterequal (export "caml_string_greaterequal") + (func $caml_bytes_greaterequal (export "caml_bytes_greaterequal") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (ref.i31 (i32.ge_s (call $string_compare (local.get 0) (local.get 1)) + (ref.i31 (i32.ge_s (call $bytes_compare (local.get 0) (local.get 1)) (i32.const 0)))) - (export "caml_bytes_greaterthan" (func $caml_string_greaterthan)) - (func $caml_string_greaterthan (export "caml_string_greaterthan") + (func $caml_bytes_greaterthan (export "caml_bytes_greaterthan") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (ref.i31 (i32.gt_s (call $string_compare (local.get 0) (local.get 1)) + (ref.i31 (i32.gt_s (call $bytes_compare (local.get 0) (local.get 1)) (i32.const 0)))) +(#if use-js-string +(#then + (func (export "caml_bytes_of_string") (param $v (ref eq)) (result (ref eq)) + (local $s externref) (local $b (ref $bytes)) (local $l i32) (local $i i32) + (local.set $s + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $v))))) + (local.set $l (call $string_length (local.get $s))) + (local.set $b (array.new $bytes (i32.const 0) (local.get $l))) + ;; loop from JS ? + (loop $loop + (if (i32.lt_u (local.get $i) (local.get $l)) + (then + (array.set $bytes (local.get $b) (local.get $i) + (call $string_get (local.get $s) (local.get $i))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br $loop)))) + (local.get $b)) + + (func (export "caml_string_of_bytes") (param $b (ref eq)) (result (ref eq)) + (return + (struct.new $string + (call $jsbytes_of_bytes (ref.cast (ref $bytes) (local.get $b)))))) +) +(#else (export "caml_bytes_of_string" (func $caml_string_of_bytes)) (func $caml_string_of_bytes (export "caml_string_of_bytes") (param $v (ref eq)) (result (ref eq)) (local.get $v)) +)) - (data $Bytes_create "Bytes.create") + (#string $string_create "Bytes.create") (func (export "caml_create_bytes") (param $len (ref eq)) (result (ref eq)) (local $l i32) (local.set $l (i31.get_s (ref.cast (ref i31) (local.get $len)))) (if (i32.lt_s (local.get $l) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $Bytes_create - (i32.const 0) (i32.const 12))))) - (array.new $string (i32.const 0) (local.get $l))) - - (export "caml_blit_bytes" (func $caml_blit_string)) - (func $caml_blit_string (export "caml_blit_string") + (then (call $caml_invalid_argument (global.get $string_create)))) + (array.new $bytes (i32.const 0) (local.get $l))) + +(#if use-js-string +(#then + (func (export "caml_blit_string") + (param $v1 (ref eq)) (param $vi1 (ref eq)) + (param $v2 (ref eq)) (param $vi2 (ref eq)) + (param $vn (ref eq)) (result (ref eq)) + (local $s externref) (local $b (ref $bytes)) + (local $i1 i32) (local $i2 i32) (local $n i32) (local $i i32) + (local.set $s + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $v1))))) + (local.set $i1 (i31.get_s (ref.cast (ref i31) (local.get $vi1)))) + (local.set $b (ref.cast (ref $bytes) (local.get $v2))) + (local.set $i2 (i31.get_s (ref.cast (ref i31) (local.get $vi2)))) + (local.set $n (i31.get_s (ref.cast (ref i31) (local.get $vn)))) + ;; loop from JS?? + (loop $loop + (if (i32.lt_u (local.get $i) (local.get $n)) + (then + (array.set $bytes (local.get $b) + (i32.add (local.get $i2) (local.get $i)) + (call $string_get + (local.get $s) (i32.add (local.get $i1) (local.get $i)))) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br $loop)))) + (ref.i31 (i32.const 0))) +) +(#else + (export "caml_blit_string" (func $caml_blit_bytes)) +)) + + (func $caml_blit_bytes (export "caml_blit_bytes") (param $v1 (ref eq)) (param $i1 (ref eq)) (param $v2 (ref eq)) (param $i2 (ref eq)) (param $n (ref eq)) (result (ref eq)) - (array.copy $string $string - (ref.cast (ref $string) (local.get $v2)) + (array.copy $bytes $bytes + (ref.cast (ref $bytes) (local.get $v2)) (i31.get_s (ref.cast (ref i31) (local.get $i2))) - (ref.cast (ref $string) (local.get $v1)) + (ref.cast (ref $bytes) (local.get $v1)) (i31.get_s (ref.cast (ref i31) (local.get $i1))) (i31.get_s (ref.cast (ref i31) (local.get $n)))) (ref.i31 (i32.const 0))) @@ -149,17 +302,121 @@ (param $v (ref eq)) (param $offset (ref eq)) (param $len (ref eq)) (param $init (ref eq)) (result (ref eq)) - (array.fill $string (ref.cast (ref $string) (local.get $v)) + (array.fill $bytes (ref.cast (ref $bytes) (local.get $v)) (i31.get_u (ref.cast (ref i31) (local.get $offset))) (i31.get_u (ref.cast (ref i31) (local.get $init))) (i31.get_u (ref.cast (ref i31) (local.get $len)))) (ref.i31 (i32.const 0))) +(#if use-js-string +(#then + (func (export "caml_string_get16") + (param $v (ref eq)) (param $i (ref eq)) (result (ref eq)) + (local $s externref) (local $p i32) + (local.set $s + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $v))))) + (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) + (if (i32.lt_s (local.get $p) (i32.const 0)) + (then (call $caml_bound_error))) + (if (i32.ge_u (i32.add (local.get $p) (i32.const 1)) + (call $string_length (local.get $s))) + (then (call $caml_bound_error))) + (ref.i31 (i32.or + (call $string_get (local.get $s) (local.get $p)) + (i32.shl (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 1))) + (i32.const 8))))) + + (func (export "caml_string_get32") + (param $v (ref eq)) (param $i (ref eq)) (result i32) + (local $s externref) (local $p i32) + (local.set $s + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $v))))) + (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) + (if (i32.lt_s (local.get $p) (i32.const 0)) + (then (call $caml_bound_error))) + (if (i32.ge_u (i32.add (local.get $p) (i32.const 3)) + (call $string_length (local.get $s))) + (then (call $caml_bound_error))) + (i32.or + (i32.or + (call $string_get (local.get $s) (local.get $p)) + (i32.shl (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 1))) + (i32.const 8))) + (i32.or + (i32.shl (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 2))) + (i32.const 16)) + (i32.shl (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 3))) + (i32.const 24))))) + + (func (export "caml_string_get64") + (param $v (ref eq)) (param $i (ref eq)) (result i64) + (local $s externref) (local $p i32) + (local.set $s + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $v))))) + (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) + (if (i32.lt_s (local.get $p) (i32.const 0)) + (then (call $caml_bound_error))) + (if (i32.ge_u (i32.add (local.get $p) (i32.const 7)) + (call $string_length (local.get $s))) + (then (call $caml_bound_error))) + (i64.or + (i64.or + (i64.or + (i64.extend_i32_u + (call $string_get (local.get $s) (local.get $p))) + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 1)))) + (i64.const 8))) + (i64.or + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 2)))) + (i64.const 16)) + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 3)))) + (i64.const 24)))) + (i64.or + (i64.or + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 4)))) + (i64.const 32)) + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 5)))) + (i64.const 40))) + (i64.or + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 6)))) + (i64.const 48)) + (i64.shl (i64.extend_i32_u + (call $string_get (local.get $s) + (i32.add (local.get $p) (i32.const 7)))) + (i64.const 56)))))) +) +(#else (export "caml_string_get16" (func $caml_bytes_get16)) + (export "caml_string_get32" (func $caml_bytes_get32)) + (export "caml_string_get64" (func $caml_bytes_get64)) +)) + (func $caml_bytes_get16 (export "caml_bytes_get16") (param $v (ref eq)) (param $i (ref eq)) (result (ref eq)) - (local $s (ref $string)) (local $p i32) - (local.set $s (ref.cast (ref $string) (local.get $v))) + (local $s (ref $bytes)) (local $p i32) + (local.set $s (ref.cast (ref $bytes) (local.get $v))) (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) @@ -167,16 +424,15 @@ (array.len (local.get $s))) (then (call $caml_bound_error))) (ref.i31 (i32.or - (array.get_u $string (local.get $s) (local.get $p)) - (i32.shl (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (local.get $p)) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1))) (i32.const 8))))) - (export "caml_string_get32" (func $caml_bytes_get32)) (func $caml_bytes_get32 (export "caml_bytes_get32") (param $v (ref eq)) (param $i (ref eq)) (result i32) - (local $s (ref $string)) (local $p i32) - (local.set $s (ref.cast (ref $string) (local.get $v))) + (local $s (ref $bytes)) (local $p i32) + (local.set $s (ref.cast (ref $bytes) (local.get $v))) (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) @@ -185,23 +441,22 @@ (then (call $caml_bound_error))) (i32.or (i32.or - (array.get_u $string (local.get $s) (local.get $p)) - (i32.shl (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (local.get $p)) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1))) (i32.const 8))) (i32.or - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 2))) (i32.const 16)) - (i32.shl (array.get_u $string (local.get $s) + (i32.shl (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 3))) (i32.const 24))))) - (export "caml_string_get64" (func $caml_bytes_get64)) (func $caml_bytes_get64 (export "caml_bytes_get64") (param $v (ref eq)) (param $i (ref eq)) (result i64) - (local $s (ref $string)) (local $p i32) - (local.set $s (ref.cast (ref $string) (local.get $v))) + (local $s (ref $bytes)) (local $p i32) + (local.set $s (ref.cast (ref $bytes) (local.get $v))) (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) @@ -212,44 +467,44 @@ (i64.or (i64.or (i64.extend_i32_u - (array.get_u $string (local.get $s) (local.get $p))) + (array.get_u $bytes (local.get $s) (local.get $p))) (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1)))) (i64.const 8))) (i64.or (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 2)))) (i64.const 16)) (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 3)))) (i64.const 24)))) (i64.or (i64.or (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 4)))) (i64.const 32)) (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 5)))) (i64.const 40))) (i64.or (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 6)))) (i64.const 48)) (i64.shl (i64.extend_i32_u - (array.get_u $string (local.get $s) + (array.get_u $bytes (local.get $s) (i32.add (local.get $p) (i32.const 7)))) (i64.const 56)))))) (func (export "caml_bytes_set16") (param (ref eq) (ref eq) (ref eq)) (result (ref eq)) - (local $s (ref $string)) (local $p i32) (local $v i32) - (local.set $s (ref.cast (ref $string) (local.get 0))) + (local $s (ref $bytes)) (local $p i32) (local $v i32) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) (local.set $p (i31.get_s (ref.cast (ref i31) (local.get 1)))) (local.set $v (i31.get_s (ref.cast (ref i31) (local.get 2)))) (if (i32.lt_s (local.get $p) (i32.const 0)) @@ -257,86 +512,117 @@ (if (i32.ge_u (i32.add (local.get $p) (i32.const 1)) (array.len (local.get $s))) (then (call $caml_bound_error))) - (array.set $string (local.get $s) (local.get $p) (local.get $v)) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (local.get $p) (local.get $v)) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1)) (i32.shr_u (local.get $v) (i32.const 8))) (ref.i31 (i32.const 0))) (func (export "caml_bytes_set32") (param (ref eq)) (param (ref eq)) (param $v i32) (result (ref eq)) - (local $s (ref $string)) (local $p i32) - (local.set $s (ref.cast (ref $string) (local.get 0))) + (local $s (ref $bytes)) (local $p i32) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) (local.set $p (i31.get_s (ref.cast (ref i31) (local.get 1)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 3)) (array.len (local.get $s))) (then (call $caml_bound_error))) - (array.set $string (local.get $s) (local.get $p) (local.get $v)) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (local.get $p) (local.get $v)) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1)) (i32.shr_u (local.get $v) (i32.const 8))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 2)) (i32.shr_u (local.get $v) (i32.const 16))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 3)) (i32.shr_u (local.get $v) (i32.const 24))) (ref.i31 (i32.const 0))) (func (export "caml_bytes_set64") (param (ref eq)) (param (ref eq)) (param $v i64) (result (ref eq)) - (local $s (ref $string)) (local $p i32) - (local.set $s (ref.cast (ref $string) (local.get 0))) + (local $s (ref $bytes)) (local $p i32) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) (local.set $p (i31.get_s (ref.cast (ref i31) (local.get 1)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 7)) (array.len (local.get $s))) (then (call $caml_bound_error))) - (array.set $string (local.get $s) (local.get $p) + (array.set $bytes (local.get $s) (local.get $p) (i32.wrap_i64 (local.get $v))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 1)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 8)))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 2)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 16)))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 3)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 24)))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 4)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 32)))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 5)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 40)))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 6)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 48)))) - (array.set $string (local.get $s) + (array.set $bytes (local.get $s) (i32.add (local.get $p) (i32.const 7)) (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 56)))) (ref.i31 (i32.const 0))) +(#if use-js-string +(#then + (func (export "caml_string_concat") + (param $s1 (ref eq)) (param $s2 (ref eq)) (result (ref eq)) + (return + (struct.new $string + (any.convert_extern + (call $string_concat + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s1)))) + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s2))))))))) +) +(#else (func (export "caml_string_concat") (param $vs1 (ref eq)) (param $vs2 (ref eq)) (result (ref eq)) - (local $s1 (ref $string)) (local $s2 (ref $string)) - (local $s (ref $string)) + (local $s1 (ref $bytes)) (local $s2 (ref $bytes)) + (local $s (ref $bytes)) (local $l1 i32) (local $l2 i32) - (local.set $s1 (ref.cast (ref $string) (local.get $vs1))) - (local.set $s2 (ref.cast (ref $string) (local.get $vs2))) + (local.set $s1 (ref.cast (ref $bytes) (local.get $vs1))) + (local.set $s2 (ref.cast (ref $bytes) (local.get $vs2))) (local.set $l1 (array.len (local.get $s1))) (local.set $l2 (array.len (local.get $s2))) (local.set $s - (array.new $string (i32.const 0) + (array.new $bytes (i32.const 0) (i32.add (local.get $l1) (local.get $l2)))) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $s) (i32.const 0) (local.get $s1) (i32.const 0) (local.get $l1)) - (array.copy $string $string + (array.copy $bytes $bytes (local.get $s) (local.get $l1) (local.get $s2) (i32.const 0) (local.get $l2)) (local.get $s)) +)) + +(#if use-js-string +(#then + (func (export "caml_string_length") (param $s (ref eq)) (result i32) + (return_call $string_length + (extern.convert_any + (struct.get $string 0 + (ref.cast (ref $string) (local.get $s)))))) +) +(#else + (func (export "caml_string_length") (param $s (ref eq)) (result i32) + (array.len (ref.cast (ref $bytes) (local.get $s)))) +)) + ) diff --git a/runtime/wasm/sync.wat b/runtime/wasm/sync.wat index cd14209dd1..6adc3f6aee 100644 --- a/runtime/wasm/sync.wat +++ b/runtime/wasm/sync.wat @@ -24,7 +24,8 @@ (func $custom_hash_id (param (ref eq)) (result i32))) (import "custom" "custom_next_id" (func $custom_next_id (result i64))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $compare (func (param (ref eq)) (param (ref eq)) (param i32) (result i32))) (type $hash @@ -36,7 +37,7 @@ (type $dup (func (param (ref eq)) (result (ref eq)))) (type $custom_operations (struct - (field $id (ref $string)) + (field $id (ref $bytes)) (field $compare (ref null $compare)) (field $compare_ext (ref null $compare)) (field $hash (ref null $hash)) @@ -53,7 +54,7 @@ (global $mutex_ops (ref $custom_operations) (struct.new $custom_operations - (array.new_fixed $string 6 ;; "_mutex" + (array.new_fixed $bytes 6 ;; "_mutex" (i32.const 95) (i32.const 109) (i32.const 117) (i32.const 116) (i32.const 101) (i32.const 120)) (ref.func $custom_compare_id) @@ -75,16 +76,13 @@ (struct.new $mutex (global.get $mutex_ops) (call $custom_next_id) (i32.const 0))) - (data $lock_failure "Mutex.lock: mutex already locked. Cannot wait.") + (#string $lock_failure "Mutex.lock: mutex already locked. Cannot wait.") (func (export "caml_ml_mutex_lock") (param (ref eq)) (result (ref eq)) (local $t (ref $mutex)) (local.set $t (ref.cast (ref $mutex) (local.get 0))) (if (struct.get $mutex $state (local.get $t)) - (then - (call $caml_failwith - (array.new_data $string $lock_failure - (i32.const 0) (i32.const 46))))) + (then (call $caml_failwith (global.get $lock_failure)))) (struct.set $mutex $state (local.get $t) (i32.const 1)) (ref.i31 (i32.const 0))) @@ -106,13 +104,11 @@ (func (export "caml_ml_condition_new") (param (ref eq)) (result (ref eq)) (ref.i31 (i32.const 0))) - (data $condition_failure "Condition.wait: cannot wait") + (#string $condition_failure "Condition.wait: cannot wait") (func (export "caml_ml_condition_wait") (param (ref eq)) (param (ref eq)) (result (ref eq)) - (call $caml_failwith - (array.new_data $string $condition_failure - (i32.const 0) (i32.const 27))) + (call $caml_failwith (global.get $condition_failure)) (ref.i31 (i32.const 0))) (func (export "caml_ml_condition_signal") (param (ref eq)) (result (ref eq)) diff --git a/runtime/wasm/sys.wat b/runtime/wasm/sys.wat index b397c89a82..a40de69017 100644 --- a/runtime/wasm/sys.wat +++ b/runtime/wasm/sys.wat @@ -49,7 +49,8 @@ (func $jsstring_test (param anyref) (result i32))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $float (struct (field f64))) (tag $ocaml_exit (export "ocaml_exit") (param i32)) @@ -148,14 +149,14 @@ ;; ZZZ (ref.i31 (i32.const 0))) - (data $Unix "Unix") + (#string $Unix "Unix") (func (export "caml_sys_get_config") (param (ref eq)) (result (ref eq)) ;; ZZZ ;; (call $log_js (string.const "caml_sys_get_config")) (array.new_fixed $block 4 (ref.i31 (i32.const 0)) - (array.new_data $string $Unix (i32.const 0) (i32.const 4)) + (global.get $Unix) (ref.i31 (i32.const 32)) (ref.i31 (i32.const 0)))) @@ -163,11 +164,13 @@ (param (ref eq)) (result (ref eq)) (ref.i31 (i32.const 0))) + (#string $empty_string "") + (func (export "caml_runtime_variant") (param (ref eq)) (result (ref eq)) - (array.new_fixed $string 0)) + (global.get $empty_string)) (func (export "caml_runtime_parameters") (param (ref eq)) (result (ref eq)) - (array.new_fixed $string 0)) + (global.get $empty_string)) (func (export "caml_install_signal_handler") (param (ref eq) (ref eq)) (result (ref eq)) @@ -185,7 +188,7 @@ (param (ref eq)) (result (ref eq)) (ref.i31 (global.get $caml_runtime_warnings))) - (data $toString "toString") + (#string $toString "toString") (func $caml_handle_sys_error (export "caml_handle_sys_error") (param $exn externref) @@ -193,6 +196,6 @@ (call $caml_string_of_jsstring (call $caml_js_meth_call (call $wrap (any.convert_extern (local.get $exn))) - (array.new_data $string $toString (i32.const 0) (i32.const 8)) + (global.get $toString) (array.new_fixed $block 1 (ref.i31 (i32.const 0))))))) ) diff --git a/runtime/wasm/weak.wat b/runtime/wasm/weak.wat index 5b54df26e0..4deb1b47b3 100644 --- a/runtime/wasm/weak.wat +++ b/runtime/wasm/weak.wat @@ -33,7 +33,8 @@ (import "jslib" "unwrap" (func $unwrap (param (ref eq)) (result anyref))) (import "jslib" "wrap" (func $wrap (param anyref) (result (ref eq)))) (type $block (array (mut (ref eq)))) - (type $string (array (mut i8))) + (type $bytes (array (mut i8))) + (type $string (struct (field anyref))) (type $js (struct (field anyref))) ;; A weak array is a an abstract value composed of possibly some @@ -275,7 +276,7 @@ (call $caml_ephe_set_data_opt (local.get $vx) (local.get $d)) (ref.i31 (i32.const 0))) - (data $Weak_create "Weak.create") + (#string $Weak_create "Weak.create") (export "caml_weak_create" (func $caml_ephe_create)) (func $caml_ephe_create (export "caml_ephe_create") @@ -284,10 +285,7 @@ (local $res (ref $block)) (local.set $len (i31.get_s (ref.cast (ref i31) (local.get $vlen)))) (if (i32.lt_s (local.get $len) (i32.const 0)) - (then - (call $caml_invalid_argument - (array.new_data $string $Weak_create - (i32.const 0) (i32.const 11))))) + (then (call $caml_invalid_argument (global.get $Weak_create)))) (local.set $res (array.new $block (global.get $caml_ephe_none) (i32.add (local.get $len) (global.get $caml_ephe_key_offset)))) diff --git a/tools/ci_setup.ml b/tools/ci_setup.ml index d64dfbc7fc..d33f15f591 100644 --- a/tools/ci_setup.ml +++ b/tools/ci_setup.ml @@ -32,6 +32,9 @@ let dune_workspace = (_ (env-vars (TESTING_FRAMEWORK inline-test)) (js_of_ocaml (enabled_if false)) + (wasm_of_ocaml + (flags + (:standard --enable use-js-string))) (flags :standard -warn-error -8-32-34-49-52-55 -w -67-69))) |}