Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
vouillon committed Dec 18, 2024
1 parent 275e36c commit 94d028a
Show file tree
Hide file tree
Showing 25 changed files with 1,505 additions and 382 deletions.
132 changes: 95 additions & 37 deletions compiler/lib-wasm/gc_target.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 })
Expand Down Expand Up @@ -794,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)))

Expand Down Expand Up @@ -929,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))))
Expand Down Expand Up @@ -987,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) ]))
Expand Down
20 changes: 13 additions & 7 deletions compiler/lib-wasm/generate.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions compiler/lib-wasm/target_sig.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 48 additions & 4 deletions runtime/wasm/bigarray.wat
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@
(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 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"
Expand Down Expand Up @@ -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 $bytes (array (mut i8)))
(type $string (struct (field anyref)))
(type $float (struct (field f64)))
(type $float_array (array (mut f64)))

Expand Down Expand Up @@ -2020,10 +2029,23 @@
(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 $bytes))
(local.set $a
Expand All @@ -2035,8 +2057,30 @@
(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 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
(local.get $len)))
(call $ta_blit_from_string
(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)
Expand Down
Loading

0 comments on commit 94d028a

Please sign in to comment.