Skip to content

Commit

Permalink
feat: Add support for reference types (#101)
Browse files Browse the repository at this point in the history
Co-authored-by: Blaine Bublitz <blaine.bublitz@gmail.com>
  • Loading branch information
jozanza and phated committed May 9, 2021
1 parent 3de1b28 commit 5058492
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,5 +1,6 @@
node_modules/
_esy/
_build/
.merlin
META
.vscode/
Expand Down
16 changes: 16 additions & 0 deletions js/op.ml
Expand Up @@ -687,3 +687,19 @@ let narrow_u_vec_i32x4_to_vec_i16x8 : t =
global ##. binaryen ##. Operations ##. NarrowUVecI32x4ToVecI16x8

let swizzle_vec8x16 : t = global ##. binaryen ##. Operations ##. SwizzleVec8x16

let ref_is_null : t = global ##. binaryen ##. Operations ##. RefIsNull

let ref_is_func : t = global ##. binaryen ##. Operations ##. RefIsFunc

let ref_is_data : t = global ##. binaryen ##. Operations ##. RefIsData

let ref_is_i31 : t = global ##. binaryen ##. Operations ##. RefIsI31

let ref_as_non_null : t = global ##. binaryen ##. Operations ##. RefAsNonNull

let ref_as_func : t = global ##. binaryen ##. Operations ##. RefAsFunc

let ref_as_data : t = global ##. binaryen ##. Operations ##. RefAsData

let ref_as_i31 : t = global ##. binaryen ##. Operations ##. RefAsI31
10 changes: 5 additions & 5 deletions src/binaryen_stubs_expressions.c
Expand Up @@ -626,6 +626,11 @@ caml_binaryen_expression_id_ref_is(value unit) {
CAMLreturn(Val_int(BinaryenRefIsId()));
}
CAMLprim value
caml_binaryen_expression_id_ref_as(value unit) {
CAMLparam1(unit);
CAMLreturn(Val_int(BinaryenRefAsId()));
}
CAMLprim value
caml_binaryen_expression_id_ref_func(value unit) {
CAMLparam1(unit);
CAMLreturn(Val_int(BinaryenRefFuncId()));
Expand Down Expand Up @@ -735,11 +740,6 @@ caml_binaryen_expression_id_array_len(value unit) {
CAMLparam1(unit);
CAMLreturn(Val_int(BinaryenArrayLenId()));
}
CAMLprim value
caml_binaryen_expression_id_ref_as(value unit) {
CAMLparam1(unit);
CAMLreturn(Val_int(BinaryenRefAsId()));
}

// Expression operations

Expand Down
56 changes: 56 additions & 0 deletions src/binaryen_stubs_ops.c
Expand Up @@ -2170,3 +2170,59 @@ caml_binaryen_binaryen_swizzle_vec8x16(value unit) {
BinaryenOp op = BinaryenSwizzleVec8x16();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_is_null(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefIsNull();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_is_func(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefIsFunc();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_is_data(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefIsData();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_is_i31(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefIsI31();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_as_non_null(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefAsNonNull();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_as_func(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefAsFunc();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_as_data(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefAsData();
CAMLreturn(alloc_BinaryenOp(op));
}

CAMLprim value
caml_binaryen_binaryen_ref_as_i31(value unit) {
CAMLparam1(unit);
BinaryenOp op = BinaryenRefAsI31();
CAMLreturn(alloc_BinaryenOp(op));
}
32 changes: 32 additions & 0 deletions src/op.ml
Expand Up @@ -1306,3 +1306,35 @@ let narrow_u_vec_i32x4_to_vec_i16x8 = narrow_u_vec_i32x4_to_vec_i16x8 ()
external swizzle_vec8x16 : unit -> t = "caml_binaryen_binaryen_swizzle_vec8x16"

let swizzle_vec8x16 = swizzle_vec8x16 ()

external ref_is_null : unit -> t = "caml_binaryen_binaryen_ref_is_null"

let ref_is_null = ref_is_null ()

external ref_is_func : unit -> t = "caml_binaryen_binaryen_ref_is_func"

let ref_is_func = ref_is_func ()

external ref_is_data : unit -> t = "caml_binaryen_binaryen_ref_is_data"

let ref_is_data = ref_is_data ()

external ref_is_i31 : unit -> t = "caml_binaryen_binaryen_ref_is_i31"

let ref_is_i31 = ref_is_i31 ()

external ref_as_non_null : unit -> t = "caml_binaryen_binaryen_ref_as_non_null"

let ref_as_non_null = ref_as_non_null ()

external ref_as_func : unit -> t = "caml_binaryen_binaryen_ref_as_func"

let ref_as_func = ref_as_func ()

external ref_as_data : unit -> t = "caml_binaryen_binaryen_ref_as_data"

let ref_as_data = ref_as_data ()

external ref_as_i31 : unit -> t = "caml_binaryen_binaryen_ref_as_i31"

let ref_as_i31 = ref_as_i31 ()
33 changes: 33 additions & 0 deletions test/test.expected
@@ -1,13 +1,17 @@
(module
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $none_=>_none (func))
(type $externref_=>_i32 (func (param externref) (result i32)))
(type $externref_i32_i32_=>_i32 (func (param externref i32 i32) (result i32)))
(import "future-wasi" "write" (func $write (param externref i32 i32) (result i32)))
(global $max_int64 i64 (i64.const 9223372036854775807))
(global $test_float64_bits f64 (f64.const 1.23))
(memory $0 1)
(table $table 1 1 funcref)
(elem $elem (i32.const 0) $adder)
(export "adder" (func $adder))
(export "memory" (memory $0))
(export "hello" (func $hello))
(start $start)
(func $adder (param $0 i32) (param $1 i32) (result i32)
(block $add (result i32)
Expand Down Expand Up @@ -36,15 +40,26 @@
)
)
)
(func $hello (param $0 externref) (result i32)
(call $write
(local.get $0)
(i32.const 0)
(i32.const 1)
)
)
)
(module
(type $none_=>_none (func))
(type $externref_=>_i32 (func (param externref) (result i32)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $externref_i32_i32_=>_i32 (func (param externref i32 i32) (result i32)))
(import "future-wasi" "write" (func $write (param externref i32 i32) (result i32)))
(memory $0 1)
(table $table 1 1 funcref)
(elem $elem (i32.const 0) $adder)
(export "adder" (func $adder))
(export "memory" (memory $0))
(export "hello" (func $hello))
(start $start)
(func $adder (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
(i32.add
Expand All @@ -66,15 +81,26 @@
)
)
)
(func $hello (; has Stack IR ;) (param $0 externref) (result i32)
(call $write
(local.get $0)
(i32.const 0)
(i32.const 1)
)
)
)
(module
(type $none_=>_none (func))
(type $externref_=>_i32 (func (param externref) (result i32)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $externref_i32_i32_=>_i32 (func (param externref i32 i32) (result i32)))
(import "future-wasi" "write" (func $fimport$0 (param externref i32 i32) (result i32)))
(memory $0 1)
(table $0 1 1 funcref)
(elem (i32.const 0) $0)
(export "adder" (func $0))
(export "memory" (memory $0))
(export "hello" (func $2))
(start $1)
(func $0 (param $0 i32) (param $1 i32) (result i32)
(i32.add
Expand All @@ -96,4 +122,11 @@
)
)
)
(func $2 (param $0 externref) (result i32)
(call $fimport$0
(local.get $0)
(i32.const 0)
(i32.const 1)
)
)
)
33 changes: 33 additions & 0 deletions test/test.ml
Expand Up @@ -95,20 +95,53 @@ let _ = Function.set_start wasm_mod start

let _ = Memory.set_memory wasm_mod 1 Memory.unlimited "memory" [] false

(* Create an imported "write" function i32 (externref, i32, i32) *)
(* Similar to the example here: https://bytecodealliance.org/articles/reference-types-in-wasmtime *)

let _ =
Import.add_function_import wasm_mod "write" "future-wasi" "write"
(Type.create [| Type.externref; Type.int32; Type.int32 |])
Type.int32

(* Create a function that calls the imported write function *)
let _ =
Function.add_function wasm_mod "hello" Type.externref Type.int32 [||]
(Expression.Call.make wasm_mod "write"
[
Expression.Local_get.make wasm_mod 0 Type.externref;
Expression.Const.make wasm_mod (Literal.int32 0l);
Expression.Const.make wasm_mod (Literal.int32 1l);
]
Type.int32)

let _ = Export.add_function_export wasm_mod "hello" "hello"

(* Finally, we print 3 versions of the module to be checked against test.expected *)

(* 1. Print the the module as-is *)

let _ = Module.print wasm_mod

(* 2. Optimize, then print the module *)

let _ = Module.optimize wasm_mod

let _ = Module.print wasm_mod

(* 3. Copy previous module bytes into new module, validate, and print *)

let byts, _ = Module.write wasm_mod None

let new_mod = Module.read byts

let _ = Module.set_features new_mod [ Module.Feature.all ]

let _ = Module.validate new_mod

let _ = Module.print new_mod

(* Dispose the modules 👋 *)

let _ = Module.dispose wasm_mod

let _ = Module.dispose new_mod
16 changes: 16 additions & 0 deletions virtual/op.mli
Expand Up @@ -615,3 +615,19 @@ val narrow_s_vec_i32x4_to_vec_i16x8 : t
val narrow_u_vec_i32x4_to_vec_i16x8 : t

val swizzle_vec8x16 : t

val ref_is_null : t

val ref_is_func : t

val ref_is_data : t

val ref_is_i31 : t

val ref_as_non_null : t

val ref_as_func : t

val ref_as_data : t

val ref_as_i31 : t

0 comments on commit 5058492

Please sign in to comment.