From 4e81182c6c4cecb0920753bd0892b625014573e3 Mon Sep 17 00:00:00 2001 From: Oscar Spencer Date: Sat, 11 Jun 2022 20:57:03 -0400 Subject: [PATCH 1/2] feat!: Support passive memory segments --- src/binaryen_stubs_expressions.c | 101 ++++++++++++++++++++++++++++++ src/binaryen_stubs_expressions.js | 70 +++++++++++++++++++++ src/binaryen_stubs_memory.js | 2 +- src/expression.ml | 27 ++++++++ src/expression.mli | 18 ++++++ src/memory.ml | 27 ++++---- src/memory.mli | 8 +-- 7 files changed, 234 insertions(+), 19 deletions(-) diff --git a/src/binaryen_stubs_expressions.c b/src/binaryen_stubs_expressions.c index 791bedd1..d687d694 100644 --- a/src/binaryen_stubs_expressions.c +++ b/src/binaryen_stubs_expressions.c @@ -354,6 +354,27 @@ caml_binaryen_unreachable(value _module) { CAMLreturn(alloc_BinaryenExpressionRef(exp)); } +CAMLprim value +caml_binaryen_memory_init(value _module, value _segment, value _dest, value _offset, value _size) { + CAMLparam5(_module, _segment, _dest, _offset, _size); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + uint32_t segment = Int_val(_segment); + BinaryenExpressionRef dest = BinaryenExpressionRef_val(_dest); + BinaryenExpressionRef offset = BinaryenExpressionRef_val(_offset); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef exp = BinaryenMemoryInit(module, segment, dest, offset, size); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_data_drop(value _module, value _segment) { + CAMLparam2(_module, _segment); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + uint32_t segment = Int_val(_segment); + BinaryenExpressionRef exp = BinaryenDataDrop(module, segment); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + CAMLprim value caml_binaryen_memory_copy(value _module, value _dest, value _source, value _size) { CAMLparam4(_module, _dest, _source, _size); @@ -1551,6 +1572,86 @@ caml_binaryen_return_set_value(value _exp, value _value) { CAMLreturn(Val_unit); } +CAMLprim value +caml_binaryen_memory_init_get_segment(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(Val_int(BinaryenMemoryInitGetSegment(exp))); +} + +CAMLprim value +caml_binaryen_memory_init_set_segment(value _exp, value _value) { + CAMLparam2(_exp, _value); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + uint32_t val = Int_val(_value); + BinaryenMemoryInitSetSegment(exp, val); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_memory_init_get_dest(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(alloc_BinaryenExpressionRef(BinaryenMemoryInitGetDest(exp))); +} + +CAMLprim value +caml_binaryen_memory_init_set_dest(value _exp, value _value) { + CAMLparam2(_exp, _value); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_value); + BinaryenMemoryInitSetDest(exp, val); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_memory_init_get_offset(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(alloc_BinaryenExpressionRef(BinaryenMemoryInitGetOffset(exp))); +} + +CAMLprim value +caml_binaryen_memory_init_set_offset(value _exp, value _value) { + CAMLparam2(_exp, _value); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_value); + BinaryenMemoryInitSetOffset(exp, val); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_memory_init_get_size(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(alloc_BinaryenExpressionRef(BinaryenMemoryInitGetSize(exp))); +} + +CAMLprim value +caml_binaryen_memory_init_set_size(value _exp, value _value) { + CAMLparam2(_exp, _value); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_value); + BinaryenMemoryInitSetSize(exp, val); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_data_drop_get_segment(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(Val_int(BinaryenDataDropGetSegment(exp))); +} + +CAMLprim value +caml_binaryen_data_drop_set_segment(value _exp, value _value) { + CAMLparam2(_exp, _value); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + uint32_t val = Int_val(_value); + BinaryenDataDropSetSegment(exp, val); + CAMLreturn(Val_unit); +} + CAMLprim value caml_binaryen_memory_copy_get_dest(value _exp) { CAMLparam1(_exp); diff --git a/src/binaryen_stubs_expressions.js b/src/binaryen_stubs_expressions.js index 08537805..84c8922a 100644 --- a/src/binaryen_stubs_expressions.js +++ b/src/binaryen_stubs_expressions.js @@ -274,6 +274,16 @@ function caml_binaryen_unreachable(wasm_mod) { return wasm_mod.unreachable(); } +//Provides: caml_binaryen_memory_init +function caml_binaryen_memory_init(wasm_mod, segment, dest, offset, size) { + return wasm_mod.memory.init(segment, dest, offset, size); +} + +//Provides: caml_binaryen_data_drop +function caml_binaryen_data_drop(wasm_mod, segment) { + return wasm_mod.data.drop(segment); +} + //Provides: caml_binaryen_memory_copy function caml_binaryen_memory_copy(wasm_mod, dest, source, size) { return wasm_mod.memory.copy(dest, source, size); @@ -1284,6 +1294,66 @@ function caml_binaryen_return_set_value(exp, value) { return binaryen.Return.setValue(exp, value); } +//Provides: caml_binaryen_memory_init_get_segment +//Requires: binaryen +function caml_binaryen_memory_init_get_segment(exp) { + return binaryen.MemoryInit.getSegment(exp); +} + +//Provides: caml_binaryen_memory_init_set_segment +//Requires: binaryen +function caml_binaryen_memory_init_set_segment(exp, value) { + return binaryen.MemoryInit.setSegment(exp, value); +} + +//Provides: caml_binaryen_memory_init_get_dest +//Requires: binaryen +function caml_binaryen_memory_init_get_dest(exp) { + return binaryen.MemoryInit.getDest(exp); +} + +//Provides: caml_binaryen_memory_init_set_dest +//Requires: binaryen +function caml_binaryen_memory_init_set_dest(exp, value) { + return binaryen.MemoryInit.setDest(exp, value); +} + +//Provides: caml_binaryen_memory_init_get_offset +//Requires: binaryen +function caml_binaryen_memory_init_get_offset(exp) { + return binaryen.MemoryInit.getOffset(exp); +} + +//Provides: caml_binaryen_memory_init_set_offset +//Requires: binaryen +function caml_binaryen_memory_init_set_offset(exp, value) { + return binaryen.MemoryInit.setOffset(exp, value); +} + +//Provides: caml_binaryen_memory_init_get_size +//Requires: binaryen +function caml_binaryen_memory_init_get_size(exp) { + return binaryen.MemoryInit.getSize(exp); +} + +//Provides: caml_binaryen_memory_init_set_size +//Requires: binaryen +function caml_binaryen_memory_init_set_size(exp, value) { + return binaryen.MemoryInit.setSize(exp, value); +} + +//Provides: caml_binaryen_data_drop_get_segment +//Requires: binaryen +function caml_binaryen_data_drop_get_segment(exp) { + return binaryen.DataDrop.getSegment(exp); +} + +//Provides: caml_binaryen_data_drop_set_segment +//Requires: binaryen +function caml_binaryen_data_drop_set_segment(exp, value) { + return binaryen.DataDrop.setSegment(exp, value); +} + //Provides: caml_binaryen_memory_copy_get_dest //Requires: binaryen function caml_binaryen_memory_copy_get_dest(exp) { diff --git a/src/binaryen_stubs_memory.js b/src/binaryen_stubs_memory.js index 466995b4..5a2a546a 100644 --- a/src/binaryen_stubs_memory.js +++ b/src/binaryen_stubs_memory.js @@ -5,7 +5,7 @@ function caml_binaryen_set_memory(wasm_mod, initial, maximum, exportName, segmen var segs = caml_list_to_js_array(segments).map(function (segment, idx) { return { data: caml_convert_bytes_to_array(segment), - passive: segmentPassives[idx + 1], // OCaml Lists are offset by 1 + passive: caml_js_from_bool(segmentPassives[idx + 1]), // OCaml Lists are offset by 1 offset: segmentOffsets[idx + 1] // OCaml Lists are offset by 1 } }); diff --git a/src/expression.ml b/src/expression.ml index 339076fd..b7f167ba 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -707,6 +707,33 @@ module Memory_grow = struct external set_delta : t -> t -> unit = "caml_binaryen_memory_grow_set_delta" end +module Memory_init = struct + external make : Module.t -> int -> t -> t -> t = "caml_binaryen_memory_init" + (** Module, segment, destination, offset, size. *) + + external get_segment : t -> int = "caml_binaryen_memory_init_get_segment" + + external set_segment : t -> int -> unit + = "caml_binaryen_memory_init_set_segment" + + external get_dest : t -> t = "caml_binaryen_memory_init_get_dest" + external set_dest : t -> t -> unit = "caml_binaryen_memory_init_set_dest" + external get_offset : t -> t = "caml_binaryen_memory_init_get_offset" + external set_offset : t -> t -> unit = "caml_binaryen_memory_init_set_offset" + external get_size : t -> t = "caml_binaryen_memory_init_get_size" + external set_size : t -> t -> unit = "caml_binaryen_memory_init_set_size" +end + +module Data_drop = struct + external make : Module.t -> int -> t = "caml_binaryen_data_drop" + (** Module, segment. *) + + external get_segment : t -> int = "caml_binaryen_data_drop_get_segment" + + external set_segment : t -> int -> unit + = "caml_binaryen_data_drop_set_segment" +end + module Memory_copy = struct external make : Module.t -> t -> t -> t -> t = "caml_binaryen_memory_copy" (** Module, destination, source, size. *) diff --git a/src/expression.mli b/src/expression.mli index 1430228c..13f616de 100644 --- a/src/expression.mli +++ b/src/expression.mli @@ -255,6 +255,24 @@ module Memory_grow : sig val set_delta : t -> t -> unit end +module Memory_init : sig + val make : Module.t -> int -> t -> t -> t + val get_segment : t -> int + val set_segment : t -> int -> unit + val get_dest : t -> t + val set_dest : t -> t -> unit + val get_offset : t -> t + val set_offset : t -> t -> unit + val get_size : t -> t + val set_size : t -> t -> unit +end + +module Data_drop : sig + val make : Module.t -> int -> t + val get_segment : t -> int + val set_segment : t -> int -> unit +end + module Memory_copy : sig val make : Module.t -> t -> t -> t -> t val get_dest : t -> t diff --git a/src/memory.ml b/src/memory.ml index 9700cd78..561005bb 100644 --- a/src/memory.ml +++ b/src/memory.ml @@ -3,31 +3,34 @@ external set_memory : int -> int -> string -> - string list -> + bytes list -> bool list -> Expression.t list -> int list -> bool -> unit = "caml_binaryen_set_memory__bytecode" "caml_binaryen_set_memory" -type segment = { - data : string; - passive : bool; - offset : Expression.t; - size : int; -} +type segment = { data : bytes; kind : segment_kind; size : int } +and segment_kind = Passive | Active of { offset : Expression.t } (** Module, initial size, maximum size, export name, segments, shared. *) let set_memory wasm_mod initial maximum export_name (segments : segment list) shared = let split_segments segments = List.fold_right - (fun { data; passive; offset; size } + (fun { data; kind; size } (segment_data, segment_passive, segment_offsets, segment_sizes) -> - ( data :: segment_data, - passive :: segment_passive, - offset :: segment_offsets, - size :: segment_sizes )) + match kind with + | Active { offset } -> + ( data :: segment_data, + false :: segment_passive, + offset :: segment_offsets, + size :: segment_sizes ) + | Passive -> + ( data :: segment_data, + true :: segment_passive, + Expression.Null.make () :: segment_offsets, + size :: segment_sizes )) segments ([], [], [], []) in let segment_data, segment_passive, segment_offsets, segment_sizes = diff --git a/src/memory.mli b/src/memory.mli index c10303da..10064d09 100644 --- a/src/memory.mli +++ b/src/memory.mli @@ -1,9 +1,5 @@ -type segment = { - data : string; - passive : bool; - offset : Expression.t; - size : int; -} +type segment = { data : bytes; kind : segment_kind; size : int } +and segment_kind = Passive | Active of { offset : Expression.t } val set_memory : Module.t -> int -> int -> string -> segment list -> bool -> unit From c584c99f12d08835f8df1b63716c7c3102bcd3c3 Mon Sep 17 00:00:00 2001 From: Oscar Spencer Date: Sat, 11 Jun 2022 20:57:12 -0400 Subject: [PATCH 2/2] update tests --- test/test.expected | 1 + test/test.ml | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/test/test.expected b/test/test.expected index 96609ae2..07ed13fe 100644 --- a/test/test.expected +++ b/test/test.expected @@ -17,6 +17,7 @@ (global $test_float64_bits f64 (f64.const 1.23)) (memory $0 1) (data (i32.const 0) "hello") + (data "world") (table $table 1 1 funcref) (elem $elem (i32.const 0) $adder) (export "adder" (func $adder)) diff --git a/test/test.ml b/test/test.ml index 5e0f17e8..6c0cc0f1 100644 --- a/test/test.ml +++ b/test/test.ml @@ -123,13 +123,24 @@ let _ = let _ = Function.set_start wasm_mod start let segment : Binaryen.Memory.segment = - let data = "hello" in - let passive = false in - let offset = Expression.Const.make wasm_mod (Literal.int32 0l) in - let size = String.length data in - { data; passive; offset; size } + let data = Bytes.of_string "hello" in + let kind = + Binaryen.Memory.Active + { offset = Expression.Const.make wasm_mod (Literal.int32 0l) } + in + let size = Bytes.length data in + { data; kind; size } + +let passive_segment : Binaryen.Memory.segment = + let data = Bytes.of_string "world" in + let kind = Binaryen.Memory.Passive in + let size = Bytes.length data in + { data; kind; size } -let _ = Memory.set_memory wasm_mod 1 Memory.unlimited "memory" [ segment ] false +let _ = + Memory.set_memory wasm_mod 1 Memory.unlimited "memory" + [ segment; passive_segment ] + false (* Create an imported "write" function i32 (externref, i32, i32) *) (* Similar to the example here: https://bytecodealliance.org/articles/reference-types-in-wasmtime *)