Skip to content

Commit b31a3af

Browse files
committed
Wasm_of_ocaml: implement use-js-string flag
1 parent 9ecfbe6 commit b31a3af

33 files changed

+1963
-826
lines changed

compiler/lib-wasm/gc_target.ml

Lines changed: 95 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,31 @@ module Type = struct
3535
; typ = W.Array { mut = true; typ = Value value }
3636
})
3737

38-
let string_type =
39-
register_type "string" (fun () ->
38+
let bytes_type =
39+
register_type "bytes" (fun () ->
4040
return
4141
{ supertype = None
4242
; final = true
4343
; typ = W.Array { mut = true; typ = Packed I8 }
4444
})
4545

46+
let string_type =
47+
register_type "string" (fun () ->
48+
return
49+
(if Config.Flag.use_js_string ()
50+
then
51+
{ supertype = None
52+
; final = true
53+
; typ =
54+
W.Struct
55+
[ { mut = false; typ = Value (Ref { nullable = true; typ = Any }) } ]
56+
}
57+
else
58+
{ supertype = None
59+
; final = true
60+
; typ = W.Array { mut = true; typ = Packed I8 }
61+
}))
62+
4663
let float_type =
4764
register_type "float" (fun () ->
4865
return
@@ -121,7 +138,7 @@ module Type = struct
121138

122139
let custom_operations_type =
123140
register_type "custom_operations" (fun () ->
124-
let* string = string_type in
141+
let* bytes = bytes_type in
125142
let* compare = compare_type in
126143
let* hash = hash_type in
127144
let* fixed_length = fixed_length_type in
@@ -134,7 +151,7 @@ module Type = struct
134151
; typ =
135152
W.Struct
136153
[ { mut = false
137-
; typ = Value (Ref { nullable = false; typ = Type string })
154+
; typ = Value (Ref { nullable = false; typ = Type bytes })
138155
}
139156
; { mut = false
140157
; typ = Value (Ref { nullable = true; typ = Type compare })
@@ -794,15 +811,50 @@ module Memory = struct
794811
wasm_array_set ~ty:Type.float_array_type (load a) (load i) (unbox_float (load v)))
795812

796813
let bytes_length e =
797-
let* ty = Type.string_type in
814+
let* ty = Type.bytes_type in
798815
let* e = wasm_cast ty e in
799816
return (W.ArrayLen e)
800817

801818
let bytes_get e e' =
802-
Value.val_int (wasm_array_get ~ty:Type.string_type e (Value.int_val e'))
819+
Value.val_int (wasm_array_get ~ty:Type.bytes_type e (Value.int_val e'))
803820

804821
let bytes_set e e' e'' =
805-
wasm_array_set ~ty:Type.string_type e (Value.int_val e') (Value.int_val e'')
822+
wasm_array_set ~ty:Type.bytes_type e (Value.int_val e') (Value.int_val e'')
823+
824+
let string_value e =
825+
let* string = Type.string_type in
826+
let* e = wasm_struct_get string (wasm_cast string e) 0 in
827+
return (W.ExternConvertAny e)
828+
829+
let string_length e =
830+
if Config.Flag.use_js_string ()
831+
then
832+
let* f =
833+
register_import
834+
~import_module:"wasm:js-string"
835+
~name:"length"
836+
(Fun { W.params = [ Ref { nullable = true; typ = Extern } ]; result = [ I32 ] })
837+
in
838+
let* e = string_value e in
839+
return (W.Call (f, [ e ]))
840+
else bytes_length e
841+
842+
let string_get e e' =
843+
if Config.Flag.use_js_string ()
844+
then
845+
let* f =
846+
register_import
847+
~import_module:"wasm:js-string"
848+
~name:"charCodeAt"
849+
(Fun
850+
{ W.params = [ Ref { nullable = true; typ = Extern }; I32 ]
851+
; result = [ I32 ]
852+
})
853+
in
854+
let* e = string_value e in
855+
let* e' = Value.int_val e' in
856+
Value.val_int (return (W.Call (f, [ e; e' ])))
857+
else bytes_get e e'
806858

807859
let field e idx = wasm_array_get e (Arith.const (Int32.of_int (idx + 1)))
808860

@@ -929,6 +981,21 @@ module Constant = struct
929981
| Const_named of string
930982
| Mutated
931983

984+
let translate_js_string s =
985+
let* i = register_string s in
986+
let* x =
987+
let* name = unit_name in
988+
register_import
989+
~import_module:
990+
(match name with
991+
| None -> "strings"
992+
| Some name -> name ^ ".strings")
993+
~name:(string_of_int i)
994+
(Global { mut = false; typ = Ref { nullable = false; typ = Any } })
995+
in
996+
let* ty = Type.js_type in
997+
return (Const_named ("str_" ^ s), W.StructNew (ty, [ GlobalGet x ]))
998+
932999
let rec translate_rec c =
9331000
match c with
9341001
| Code.Int i -> return (Const, W.RefI31 (Const (I32 (Targetint.to_int32 i))))
@@ -987,38 +1054,29 @@ module Constant = struct
9871054
| Utf (Utf8 s) -> str_js_utf8 s
9881055
| Byte s -> str_js_byte s
9891056
in
990-
let* i = register_string s in
991-
let* x =
992-
let* name = unit_name in
993-
register_import
994-
~import_module:
995-
(match name with
996-
| None -> "strings"
997-
| Some name -> name ^ ".strings")
998-
~name:(string_of_int i)
999-
(Global { mut = false; typ = Ref { nullable = false; typ = Any } })
1000-
in
1001-
let* ty = Type.js_type in
1002-
return (Const_named ("str_" ^ s), W.StructNew (ty, [ GlobalGet x ]))
1057+
translate_js_string s
10031058
| String s ->
1004-
let* ty = Type.string_type in
1005-
if String.length s >= string_length_threshold
1006-
then
1007-
let name = Code.Var.fresh_n "string" in
1008-
let* () = register_data_segment name s in
1009-
return
1010-
( Mutated
1011-
, W.ArrayNewData
1012-
(ty, name, Const (I32 0l), Const (I32 (Int32.of_int (String.length s))))
1013-
)
1059+
if Config.Flag.use_js_string ()
1060+
then translate_js_string (str_js_byte s)
10141061
else
1015-
let l =
1016-
String.fold_right
1017-
~f:(fun c r -> W.Const (I32 (Int32.of_int (Char.code c))) :: r)
1018-
s
1019-
~init:[]
1020-
in
1021-
return (Const_named ("str_" ^ s), W.ArrayNewFixed (ty, l))
1062+
let* ty = Type.string_type in
1063+
if String.length s >= string_length_threshold
1064+
then
1065+
let name = Code.Var.fresh_n "string" in
1066+
let* () = register_data_segment name s in
1067+
return
1068+
( Mutated
1069+
, W.ArrayNewData
1070+
(ty, name, Const (I32 0l), Const (I32 (Int32.of_int (String.length s))))
1071+
)
1072+
else
1073+
let l =
1074+
String.fold_right
1075+
~f:(fun c r -> W.Const (I32 (Int32.of_int (Char.code c))) :: r)
1076+
s
1077+
~init:[]
1078+
in
1079+
return (Const_named ("str_" ^ s), W.ArrayNewFixed (ty, l))
10221080
| Float f ->
10231081
let* ty = Type.float_type in
10241082
return (Const, W.StructNew (ty, [ Const (F64 f) ]))

compiler/lib-wasm/generate.ml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,22 +285,29 @@ module Generate (Target : Target_sig.S) = struct
285285
seq (Memory.array_set x y z) Value.unit
286286
| Extern "caml_floatarray_unsafe_set", [ x; y; z ] ->
287287
seq (Memory.float_array_set x y z) Value.unit
288-
| Extern ("caml_string_unsafe_get" | "caml_bytes_unsafe_get"), [ x; y ] ->
289-
Memory.bytes_get x y
290-
| Extern ("caml_string_unsafe_set" | "caml_bytes_unsafe_set"), [ x; y; z ] ->
288+
| Extern "caml_string_unsafe_get", [ x; y ] -> Memory.string_get x y
289+
| Extern "caml_bytes_unsafe_get", [ x; y ] -> Memory.bytes_get x y
290+
| Extern "caml_bytes_unsafe_set", [ x; y; z ] ->
291291
seq (Memory.bytes_set x y z) Value.unit
292-
| Extern ("caml_string_get" | "caml_bytes_get"), [ x; y ] ->
292+
| Extern "caml_string_get", [ x; y ] ->
293+
seq
294+
(let* cond = Arith.uge (Value.int_val y) (Memory.string_length x) in
295+
instr (W.Br_if (label_index context bound_error_pc, cond)))
296+
(Memory.string_get x y)
297+
| Extern "caml_bytes_get", [ x; y ] ->
293298
seq
294299
(let* cond = Arith.uge (Value.int_val y) (Memory.bytes_length x) in
295300
instr (W.Br_if (label_index context bound_error_pc, cond)))
296301
(Memory.bytes_get x y)
297-
| Extern ("caml_string_set" | "caml_bytes_set"), [ x; y; z ] ->
302+
| Extern "caml_bytes_set", [ x; y; z ] ->
298303
seq
299304
(let* cond = Arith.uge (Value.int_val y) (Memory.bytes_length x) in
300305
let* () = instr (W.Br_if (label_index context bound_error_pc, cond)) in
301306
Memory.bytes_set x y z)
302307
Value.unit
303-
| Extern ("caml_ml_string_length" | "caml_ml_bytes_length"), [ x ] ->
308+
| Extern "caml_ml_string_length", [ x ] ->
309+
Value.val_int (Memory.string_length x)
310+
| Extern "caml_ml_bytes_length", [ x ] ->
304311
Value.val_int (Memory.bytes_length x)
305312
| Extern "%int_add", [ x; y ] -> Value.int_add x y
306313
| Extern "%int_sub", [ x; y ] -> Value.int_sub x y
@@ -776,7 +783,6 @@ module Generate (Target : Target_sig.S) = struct
776783
( Extern
777784
( "caml_string_get"
778785
| "caml_bytes_get"
779-
| "caml_string_set"
780786
| "caml_bytes_set"
781787
| "caml_check_bound"
782788
| "caml_check_bound_gen"

compiler/lib-wasm/target_sig.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ module type S = sig
7777

7878
val bytes_set : expression -> expression -> expression -> unit Code_generation.t
7979

80+
val string_length : expression -> expression
81+
82+
val string_get : expression -> expression -> expression
83+
8084
val box_float : expression -> expression
8185

8286
val unbox_float : expression -> expression

runtime/wasm/array.wat

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121

2222
(type $block (array (mut (ref eq))))
2323
(type $bytes (array (mut i8)))
24+
(type $string (struct (field anyref)))
2425
(type $float (struct (field f64)))
2526
(type $float_array (array (mut f64)))
2627

27-
(data $Array_make "Array.make")
28+
(#string $Array_make "Array.make")
2829

2930
(global $empty_array (ref eq)
3031
(array.new_fixed $block 1 (ref.i31 (i32.const 0))))
@@ -34,10 +35,7 @@
3435
(local $sz i32) (local $b (ref $block)) (local $f f64)
3536
(local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n))))
3637
(if (i32.lt_s (local.get $sz) (i32.const 0))
37-
(then
38-
(call $caml_invalid_argument
39-
(array.new_data $bytes $Array_make
40-
(i32.const 0) (i32.const 10)))))
38+
(then (call $caml_invalid_argument (global.get $Array_make))))
4139
(if (i32.eqz (local.get $sz)) (then (return (global.get $empty_array))))
4240
(drop (block $not_float (result (ref eq))
4341
(local.set $f
@@ -56,10 +54,7 @@
5654
(local $sz i32) (local $f f64)
5755
(local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n))))
5856
(if (i32.lt_s (local.get $sz) (i32.const 0))
59-
(then
60-
(call $caml_invalid_argument
61-
(array.new_data $bytes $Array_make
62-
(i32.const 0) (i32.const 10)))))
57+
(then (call $caml_invalid_argument (global.get $Array_make))))
6358
(if (i32.eqz (local.get $sz)) (then (return (global.get $empty_array))))
6459
(local.set $f
6560
(struct.get $float 0
@@ -73,10 +68,7 @@
7368
(local $sz i32)
7469
(local.set $sz (i31.get_s (ref.cast (ref i31) (local.get $n))))
7570
(if (i32.lt_s (local.get $sz) (i32.const 0))
76-
(then
77-
(call $caml_invalid_argument
78-
(array.new_data $bytes $Array_make
79-
(i32.const 0) (i32.const 10)))))
71+
(then (call $caml_invalid_argument (global.get $Array_make))))
8072
(if (i32.eqz (local.get $sz)) (then (return (global.get $empty_array))))
8173
(array.new $float_array (f64.const 0) (local.get $sz)))
8274

runtime/wasm/backtrace.wat

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
(type $block (array (mut (ref eq))))
2323
(type $bytes (array (mut i8)))
24+
(type $string (struct (field anyref)))
2425

2526
(func (export "caml_get_exception_raw_backtrace")
2627
(param (ref eq)) (result (ref eq))
@@ -38,14 +39,12 @@
3839
(param (ref eq)) (result (ref eq))
3940
(ref.i31 (i32.const 0)))
4041

41-
(data $raw_backtrace_slot_err
42+
(#string $raw_backtrace_slot_err
4243
"Printexc.get_raw_backtrace_slot: index out of bounds")
4344

4445
(func (export "caml_raw_backtrace_slot")
4546
(param (ref eq) (ref eq)) (result (ref eq))
46-
(call $caml_invalid_argument
47-
(array.new_data $bytes $raw_backtrace_slot_err
48-
(i32.const 0) (i32.const 52)))
47+
(call $caml_invalid_argument (global.get $raw_backtrace_slot_err))
4948
(ref.i31 (i32.const 0)))
5049

5150
(func (export "caml_convert_raw_backtrace_slot")

0 commit comments

Comments
 (0)