From 50584929466b7aae5f7c9b48b8b9bab5676ed53e Mon Sep 17 00:00:00 2001 From: Josiah Savary Date: Sun, 9 May 2021 19:02:27 -0400 Subject: [PATCH] feat: Add support for reference types (#101) Co-authored-by: Blaine Bublitz --- .gitignore | 1 + js/op.ml | 16 +++++++++ src/binaryen_stubs_expressions.c | 10 +++--- src/binaryen_stubs_ops.c | 56 ++++++++++++++++++++++++++++++++ src/op.ml | 32 ++++++++++++++++++ test/test.expected | 33 +++++++++++++++++++ test/test.ml | 33 +++++++++++++++++++ virtual/op.mli | 16 +++++++++ 8 files changed, 192 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 7aefdbb..a13a0c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ _esy/ +_build/ .merlin META .vscode/ diff --git a/js/op.ml b/js/op.ml index eadaca4..3e8e07a 100644 --- a/js/op.ml +++ b/js/op.ml @@ -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 diff --git a/src/binaryen_stubs_expressions.c b/src/binaryen_stubs_expressions.c index 4e37ca4..bec9c13 100644 --- a/src/binaryen_stubs_expressions.c +++ b/src/binaryen_stubs_expressions.c @@ -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())); @@ -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 diff --git a/src/binaryen_stubs_ops.c b/src/binaryen_stubs_ops.c index 7c5b1d9..c4525bd 100644 --- a/src/binaryen_stubs_ops.c +++ b/src/binaryen_stubs_ops.c @@ -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)); +} \ No newline at end of file diff --git a/src/op.ml b/src/op.ml index 98d97ba..a0d7dc5 100644 --- a/src/op.ml +++ b/src/op.ml @@ -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 () diff --git a/test/test.expected b/test/test.expected index 8a618db..1f568b8 100644 --- a/test/test.expected +++ b/test/test.expected @@ -1,6 +1,9 @@ (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) @@ -8,6 +11,7 @@ (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) @@ -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 @@ -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 @@ -96,4 +122,11 @@ ) ) ) + (func $2 (param $0 externref) (result i32) + (call $fimport$0 + (local.get $0) + (i32.const 0) + (i32.const 1) + ) + ) ) diff --git a/test/test.ml b/test/test.ml index c5ed999..839c953 100644 --- a/test/test.ml +++ b/test/test.ml @@ -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 diff --git a/virtual/op.mli b/virtual/op.mli index 741a5e9..89df4be 100644 --- a/virtual/op.mli +++ b/virtual/op.mli @@ -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