From fb796fde1ad567564372d7119f970509555223fe Mon Sep 17 00:00:00 2001 From: Oscar Spencer Date: Sun, 16 Feb 2025 21:57:29 -0600 Subject: [PATCH 01/17] feat!: Implement GC instructions --- src/dune | 2 + src/expression.c | 268 +++++++++++++++++++++++++++++++++++++++++++ src/expression.js | 194 +++++++++++++++++++++++++++++++ src/expression.ml | 86 ++++++++++++++ src/expression.mli | 60 ++++++++++ src/ocaml_helpers.c | 9 ++ src/ocaml_helpers.h | 5 + src/type.ml | 5 +- src/type.mli | 2 +- src/type_builder.c | 176 ++++++++++++++++++++++++++++ src/type_builder.js | 116 +++++++++++++++++++ src/type_builder.ml | 65 +++++++++++ src/type_builder.mli | 27 +++++ test/test.expected | 191 +++++++++++++++++++++++++++++- test/test.ml | 88 +++++++++++++- 15 files changed, 1290 insertions(+), 4 deletions(-) create mode 100644 src/type_builder.c create mode 100644 src/type_builder.js create mode 100644 src/type_builder.ml create mode 100644 src/type_builder.mli diff --git a/src/dune b/src/dune index 1249f71d..b4109357 100644 --- a/src/dune +++ b/src/dune @@ -24,6 +24,7 @@ heap_type signature_type struct_type + type_builder ocaml_helpers) (flags :standard -O2 -Wall -Wextra)) (js_of_ocaml @@ -46,4 +47,5 @@ packed_type.js heap_type.js signature_type.js + type_builder.js struct_type.js))) diff --git a/src/expression.c b/src/expression.c index 69d9d568..2d737493 100644 --- a/src/expression.c +++ b/src/expression.c @@ -124,6 +124,23 @@ caml_binaryen_call_indirect__bytecode(value * argv) { return caml_binaryen_call_indirect(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); } +CAMLprim value +caml_binaryen_call_ref(value _module, value _target, value _params, value _ty, value _is_return) { + CAMLparam5(_module, _target, _params, _ty, _is_return); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef target = BinaryenExpressionRef_val(_target); + _params = array_of_list(_params); + int paramsLen = array_length(_params); + BinaryenExpressionRef params[paramsLen]; + for (int i = 0; i < paramsLen; i++) { + params[i] = BinaryenExpressionRef_val(Field(_params, i)); + } + BinaryenType ty = BinaryenType_val(_ty); + bool is_return = Bool_val(_is_return); + BinaryenExpressionRef exp = BinaryenCallRef(module, target, params, paramsLen, ty, is_return); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + CAMLprim value caml_binaryen_return_call(value _module, value _name, value _params, value _retty) { CAMLparam4(_module, _name, _params, _retty); @@ -459,6 +476,38 @@ caml_binaryen_i31_get(value _module, value _val, value _signed) { CAMLreturn(alloc_BinaryenExpressionRef(exp)); } +CAMLprim value +caml_binaryen_ref_test(value _module, value _ref, value _castType) { + CAMLparam3(_module, _ref, _castType); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenType castType = BinaryenType_val(_castType); + BinaryenExpressionRef exp = BinaryenRefTest(module, ref, castType); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_ref_cast(value _module, value _ref, value _castType) { + CAMLparam3(_module, _ref, _castType); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenType castType = BinaryenType_val(_castType); + BinaryenExpressionRef exp = BinaryenRefCast(module, ref, castType); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_br_on(value _module, value _op, value _name, value _ref, value _castType) { + CAMLparam5(_module, _op, _name, _ref, _castType); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenOp op = BinaryenOp_val(_op); + char* name = Safe_String_val(_name); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenType castType = BinaryenType_val(_castType); + BinaryenExpressionRef exp = BinaryenBrOn(module, op, name, ref, castType); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + CAMLprim value caml_binaryen_expression_id_invalid(value unit) { CAMLparam1(unit); @@ -1328,6 +1377,90 @@ caml_binaryen_call_indirect_set_return(value _exp, value _isReturn) { CAMLreturn(Val_unit); } +CAMLprim value +caml_binaryen_call_ref_get_target(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenExpressionRef target = BinaryenCallRefGetTarget(exp); + CAMLreturn(alloc_BinaryenExpressionRef(target)); +} + +CAMLprim value +caml_binaryen_call_ref_set_target(value _exp, value _target) { + CAMLparam2(_exp, _target); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenExpressionRef target = BinaryenExpressionRef_val(_target); + BinaryenCallRefSetTarget(exp, target); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_call_ref_get_num_operands(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(Val_int(BinaryenCallRefGetNumOperands(exp))); +} + +CAMLprim value +caml_binaryen_call_ref_get_operand_at(value _exp, value _index) { + CAMLparam2(_exp, _index); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenIndex index = Int_val(_index); + CAMLreturn(alloc_BinaryenExpressionRef(BinaryenCallRefGetOperandAt(exp, index))); +} + +CAMLprim value +caml_binaryen_call_ref_set_operand_at(value _exp, value _index, value _operand) { + CAMLparam3(_exp, _index, _operand); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenIndex index = Int_val(_index); + BinaryenExpressionRef operand = BinaryenExpressionRef_val(_operand); + BinaryenCallRefSetOperandAt(exp, index, operand); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_call_ref_append_operand(value _exp, value _operand) { + CAMLparam2(_exp, _operand); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenExpressionRef operand = BinaryenExpressionRef_val(_operand); + CAMLreturn(Val_int(BinaryenCallRefAppendOperand(exp, operand))); +} + +CAMLprim value +caml_binaryen_call_ref_insert_operand_at(value _exp, value _index, value _operand) { + CAMLparam3(_exp, _index, _operand); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenIndex index = Int_val(_index); + BinaryenExpressionRef operand = BinaryenExpressionRef_val(_operand); + BinaryenCallRefInsertOperandAt(exp, index, operand); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_binaryen_call_ref_remove_operand_at(value _exp, value _index) { + CAMLparam2(_exp, _index); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + BinaryenIndex index = Int_val(_index); + CAMLreturn(alloc_BinaryenExpressionRef(BinaryenCallRefRemoveOperandAt(exp, index))); +} + +CAMLprim value +caml_binaryen_call_ref_is_return(value _exp) { + CAMLparam1(_exp); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + CAMLreturn(Val_bool(BinaryenCallRefIsReturn(exp))); +} + +CAMLprim value +caml_binaryen_call_ref_set_return(value _exp, value _isReturn) { + CAMLparam2(_exp, _isReturn); + BinaryenExpressionRef exp = BinaryenExpressionRef_val(_exp); + int isReturn = Bool_val(_isReturn); + BinaryenCallRefSetReturn(exp, isReturn); + CAMLreturn(Val_unit); +} + CAMLprim value caml_binaryen_local_set_get_value(value _exp) { CAMLparam1(_exp); @@ -1883,6 +2016,141 @@ caml_binaryen_ref_eq(value _module, value _left, value _right) { CAMLreturn(alloc_BinaryenExpressionRef(exp)); } +// Struct operations + +CAMLprim value +caml_binaryen_struct_new(value _module, value _operands, value _type) { + CAMLparam3(_module, _operands, _type); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType type = BinaryenHeapType_val(_type); + if (Is_some(_operands)) { + _operands = array_of_list(Some_val(_operands)); + int operandsLen = array_length(_operands); + BinaryenExpressionRef operands[operandsLen]; + for (int i = 0; i < operandsLen; i++) { + operands[i] = BinaryenExpressionRef_val(Field(_operands, i)); + } + BinaryenExpressionRef exp = BinaryenStructNew(module, operands, operandsLen, type); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); + } else { + BinaryenExpressionRef exp = BinaryenStructNew(module, NULL, 0, type); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); + } +} + +CAMLprim value +caml_binaryen_struct_get(value _module, value _index, value _ref, value _type, value _signed) { + CAMLparam5(_module, _index, _ref, _type, _signed); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenIndex index = Int_val(_index); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenType type = BinaryenType_val(_type); + bool signed_ = Bool_val(_signed); + BinaryenExpressionRef exp = BinaryenStructGet(module, index, ref, type, signed_); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_struct_set(value _module, value _index, value _ref, value _value) { + CAMLparam4(_module, _index, _ref, _value); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenIndex index = Int_val(_index); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef value_ = BinaryenExpressionRef_val(_value); + BinaryenExpressionRef exp = BinaryenStructSet(module, index, ref, value_); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +// Array operations + +CAMLprim value +caml_binaryen_array_new(value _module, value _type, value _size, value _init) { + CAMLparam4(_module, _type, _size, _init); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType type = BinaryenHeapType_val(_type); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef init = BinaryenExpressionRef_val(_init); + BinaryenExpressionRef exp = BinaryenArrayNew(module, type, size, init); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_new_data(value _module, value _type, value _name, value _offset, value _size) { + CAMLparam5(_module, _type, _name, _offset, _size); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType type = BinaryenHeapType_val(_type); + char* name = Safe_String_val(_name); + BinaryenExpressionRef offset = BinaryenExpressionRef_val(_offset); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef exp = BinaryenArrayNewData(module, type, name, offset, size); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_new_fixed(value _module, value _type, value _values) { + CAMLparam3(_module, _type, _values); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType type = BinaryenHeapType_val(_type); + _values = array_of_list(_values); + int valuesLen = array_length(_values); + BinaryenExpressionRef values[valuesLen]; + for (int i = 0; i < valuesLen; i++) { + values[i] = BinaryenExpressionRef_val(Field(_values, i)); + } + BinaryenExpressionRef exp = BinaryenArrayNewFixed(module, type, values, valuesLen); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_get(value _module, value _ref, value _index, value _type, value _signed) { + CAMLparam5(_module, _ref, _index, _type, _signed); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef index = BinaryenExpressionRef_val(_index); + BinaryenType type = BinaryenType_val(_type); + bool signed_ = Bool_val(_signed); + BinaryenExpressionRef exp = BinaryenArrayGet(module, ref, index, type, signed_); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_set(value _module, value _ref, value _index, value _value) { + CAMLparam4(_module, _ref, _index, _value); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef index = BinaryenExpressionRef_val(_index); + BinaryenExpressionRef value_ = BinaryenExpressionRef_val(_value); + BinaryenExpressionRef exp = BinaryenArraySet(module, ref, index, value_); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_len(value _module, value _ref) { + CAMLparam2(_module, _ref); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef exp = BinaryenArrayLen(module, ref); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_copy(value _module, value _destRef, value _destIndex, value _srcRef, value _srcIndex, value _length) { + CAMLparam5(_module, _destRef, _destIndex, _srcRef, _srcIndex); + CAMLxparam1(_length); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef destRef = BinaryenExpressionRef_val(_destRef); + BinaryenExpressionRef destIndex = BinaryenExpressionRef_val(_destIndex); + BinaryenExpressionRef srcRef = BinaryenExpressionRef_val(_srcRef); + BinaryenExpressionRef srcIndex = BinaryenExpressionRef_val(_srcIndex); + BinaryenExpressionRef length = BinaryenExpressionRef_val(_length); + BinaryenExpressionRef exp = BinaryenArrayCopy(module, destRef, destIndex, srcRef, srcIndex, length); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} +CAMLprim value +caml_binaryen_array_copy__bytecode(value * argv) { + return caml_binaryen_array_copy(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + // Exception handling operations CAMLprim value caml_binaryen_try(value _module, value _name, value _body, value _catchTags, value _catchBodies, value _delegateTarget) { diff --git a/src/expression.js b/src/expression.js index 2fd5f650..f6ab3685 100644 --- a/src/expression.js +++ b/src/expression.js @@ -101,6 +101,18 @@ function caml_binaryen_call_indirect__bytecode() { ); } +//Provides: caml_binaryen_call_ref +//Requires: caml_jsstring_of_string +//Requires: caml_list_to_js_array, caml_js_from_bool +function caml_binaryen_call_ref(wasm_mod, target, params, typ, is_return) { + return wasm_mod.call_ref( + target, + caml_list_to_js_array(params), + typ, + caml_js_from_bool(is_return) + ); +} + //Provides: caml_binaryen_return_call //Requires: caml_jsstring_of_string //Requires: caml_list_to_js_array @@ -547,6 +559,32 @@ function caml_binaryen_ref_i31(wasm_mod, typ) { return wasm_mod.ref.i31(typ); } +//Provides: caml_binaryen_ref_test +function caml_binaryen_ref_test(wasm_mod, ref, typ) { + return wasm_mod.ref.test(ref, typ); +} + +//Provides: caml_binaryen_ref_cast +function caml_binaryen_ref_cast(wasm_mod, ref, typ) { + return wasm_mod.ref.cast(ref, typ); +} + +//Provides: caml_binaryen_br_on +//Requires: caml_jsstring_of_string +//Requires: Binaryen +function caml_binaryen_br_on(wasm_mod, op, name, ref, typ) { + switch (op) { + case Binaryen.BrOnNull: + return wasm_mod.br_on.null(caml_jsstring_of_string(name), ref, typ); + case Binaryen.BrOnNonNull: + return wasm_mod.br_on.non_null(caml_jsstring_of_string(name), ref, typ); + case Binaryen.BrOnCast: + return wasm_mod.br_on.cast(caml_jsstring_of_string(name), ref, typ); + case Binaryen.BrOnCastFail: + return wasm_mod.br_on.cast_fail(caml_jsstring_of_string(name), ref, typ); + } +} + //Provides: caml_binaryen_i31_get function caml_binaryen_i31_get(wasm_mod, typ, signed) { if (signed) { @@ -1296,6 +1334,68 @@ function caml_binaryen_call_indirect_set_return(exp, isReturn) { return Binaryen.CallIndirect.setReturn(exp, caml_js_from_bool(isReturn)); } +//Provides: caml_binaryen_call_ref_get_target +//Requires: Binaryen +function caml_binaryen_call_ref_get_target(exp) { + return Binaryen.CallRef.getTarget(exp); +} + +//Provides: caml_binaryen_call_ref_set_target +//Requires: Binaryen +function caml_binaryen_call_ref_set_target(exp, target) { + return Binaryen.CallRef.setTarget(exp, target); +} + +//Provides: caml_binaryen_call_ref_get_num_operands +//Requires: Binaryen +function caml_binaryen_call_ref_get_num_operands(exp) { + return Binaryen.CallRef.getNumOperands(exp); +} + +//Provides: caml_binaryen_call_ref_get_operand_at +//Requires: Binaryen +function caml_binaryen_call_ref_get_operand_at(exp, index) { + return Binaryen.CallRef.getOperandAt(exp, index); +} + +//Provides: caml_binaryen_call_ref_set_operand_at +//Requires: Binaryen +function caml_binaryen_call_ref_set_operand_at(exp, index, operand) { + return Binaryen.CallRef.setOperandAt(exp, index, operand); +} + +//Provides: caml_binaryen_call_ref_append_operand +//Requires: Binaryen +function caml_binaryen_call_ref_append_operand(exp, operand) { + return Binaryen.CallRef.appendOperand(exp, operand); +} + +//Provides: caml_binaryen_call_ref_insert_operand_at +//Requires: Binaryen +function caml_binaryen_call_ref_insert_operand_at(exp, index, operand) { + return Binaryen.CallRef.insertOperandAt(exp, index, operand); +} + +//Provides: caml_binaryen_call_ref_remove_operand_at +//Requires: Binaryen +function caml_binaryen_call_ref_remove_operand_at(exp, index) { + return Binaryen.CallRef.removeOperandAt(exp, index); +} + +//Provides: caml_binaryen_call_ref_is_return +//Requires: Binaryen +//Requires: caml_js_to_bool +function caml_binaryen_call_ref_is_return(exp) { + return caml_js_to_bool(Binaryen.CallRef.isReturn(exp)); +} + +//Provides: caml_binaryen_call_ref_set_return +//Requires: Binaryen +//Requires: caml_js_from_bool +function caml_binaryen_call_ref_set_return(exp, isReturn) { + return Binaryen.CallRef.setReturn(exp, caml_js_from_bool(isReturn)); +} + //Provides: caml_binaryen_local_set_get_value //Requires: Binaryen function caml_binaryen_local_set_get_value(exp) { @@ -1707,6 +1807,100 @@ function caml_binaryen_ref_eq(wasm_mod, left, right) { return wasm_mod.ref.func(left, right); } +// Struct operations + +//Provides: caml_binaryen_struct_new +//Requires: caml_list_to_js_array +function caml_binaryen_struct_new(wasm_mod, operands, type) { + return wasm_mod.struct.new( + operands ? caml_list_to_js_array(operands[1]) : null, + type + ); +} + +//Provides: caml_binaryen_struct_get +//Requires: caml_js_from_bool +function caml_binaryen_struct_get(wasm_mod, index, ref, type, signed) { + if (caml_js_from_bool(signed)) { + return wasm_mod.struct.get_s(index, ref, type); + } else { + return wasm_mod.struct.get_u(index, ref, type); + } +} + +//Provides: caml_binaryen_struct_set +function caml_binaryen_struct_set(wasm_mod, index, ref, value) { + return wasm_mod.struct.set(index, ref, value); +} + +// Array operations + +//Provides: caml_binaryen_array_new +function caml_binaryen_array_new(wasm_mod, type, size, init) { + return wasm_mod.array.new(type, size, init); +} + +//Provides: caml_binaryen_array_new_data +//Requires: caml_jsstring_of_string +function caml_binaryen_array_new_data(wasm_mod, type, name, offset, size) { + return wasm_mod.array.new_data( + type, + caml_jsstring_of_string(name), + offset, + size + ); +} + +//Provides: caml_binaryen_array_new_fixed +//Requires: caml_list_to_js_array +function caml_binaryen_array_new_fixed(wasm_mod, type, values) { + return wasm_mod.array.new_fixed(type, caml_list_to_js_array(values)); +} + +//Provides: caml_binaryen_array_get +//Requires: caml_js_from_bool +function caml_binaryen_array_get(wasm_mod, ref, index, type, signed) { + if (caml_js_from_bool(signed)) { + return wasm_mod.array.get_s(ref, index, type); + } else { + return wasm_mod.array.get_u(ref, index, type); + } +} + +//Provides: caml_binaryen_array_set +function caml_binaryen_array_set(wasm_mod, ref, index, value) { + return wasm_mod.array.set(ref, index, value); +} + +//Provides: caml_binaryen_array_len +function caml_binaryen_array_len(wasm_mod, ref) { + return wasm_mod.array.len(ref); +} + +//Provides: caml_binaryen_array_copy +function caml_binaryen_array_copy( + wasm_mod, + destRef, + destIndex, + srcRef, + srcIndex, + length +) { + return wasm_mod.array.copy(destRef, destIndex, srcRef, srcIndex, length); +} +//Provides: caml_binaryen_array_copy__bytecode +//Requires: caml_binaryen_array_copy +function caml_binaryen_array_copy__bytecode() { + return caml_binaryen_array_copy( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5] + ); +} + // Exception handling operations //Provides: caml_binaryen_try diff --git a/src/expression.ml b/src/expression.ml index 9328e31a..2eb57841 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -583,6 +583,39 @@ module Call_indirect = struct = "caml_binaryen_call_indirect_set_return" end +module Call_ref = struct + external make : Module.t -> t -> t list -> Type.t -> bool -> t + = "caml_binaryen_call_ref" + (** Module, function value, params, type, is return. *) + + let make_return mod_ target params typ = make mod_ target params typ true + let make mod_ target params typ = make mod_ target params typ false + + external get_target : t -> t = "caml_binaryen_call_ref_get_target" + external set_target : t -> t -> unit = "caml_binaryen_call_ref_set_target" + + external get_num_operands : t -> int + = "caml_binaryen_call_ref_get_num_operands" + + external get_operand_at : t -> int -> t + = "caml_binaryen_call_ref_get_operand_at" + + external set_operand_at : t -> int -> t -> unit + = "caml_binaryen_call_ref_set_operand_at" + + external append_operand : t -> t -> int + = "caml_binaryen_call_ref_append_operand" + + external insert_operand_at : t -> int -> t -> unit + = "caml_binaryen_call_ref_insert_operand_at" + + external remove_operand_at : t -> int -> t + = "caml_binaryen_call_ref_remove_operand_at" + + external is_return : t -> bool = "caml_binaryen_call_ref_is_return" + external set_return : t -> bool -> unit = "caml_binaryen_call_ref_set_return" +end + module Local_get = struct external make : Module.t -> int -> Type.t -> t = "caml_binaryen_local_get" (** Module, slot, type. *) @@ -830,6 +863,59 @@ module Ref = struct external eq : Module.t -> t -> t -> t = "caml_binaryen_ref_eq" (** Module, left, right *) + + external test : Module.t -> t -> Type.t -> t = "caml_binaryen_ref_test" + (** Module, value, type *) + + external cast : Module.t -> t -> Type.t -> t = "caml_binaryen_ref_cast" + (** Module, value, type *) +end + +module BrOn = struct + external make : Module.t -> Op.t -> string -> t -> Type.t -> t + = "caml_binaryen_br_on" + (** Module, op, label, value, type *) +end + +module Struct = struct + external new_ : Module.t -> t list option -> Heap_type.t -> t + = "caml_binaryen_struct_new" + (** Mdoule, operands, type *) + + external get : Module.t -> int -> t -> Type.t -> bool -> t + = "caml_binaryen_struct_get" + (** Module, index, struct, type, signed *) + + external set : Module.t -> int -> t -> t -> t = "caml_binaryen_struct_set" + (** Module, index, struct, value *) +end + +module Array = struct + external new_ : Module.t -> Heap_type.t -> t -> t -> t + = "caml_binaryen_array_new" + (** Module, type, size, init *) + + external new_data : Module.t -> Heap_type.t -> string -> t -> t -> t + = "caml_binaryen_array_new_data" + (** Module, type, data name, offset, size *) + + external new_fixed : Module.t -> Heap_type.t -> t list -> t + = "caml_binaryen_array_new_fixed" + (** Module, type, values *) + + external get : Module.t -> t -> t -> Type.t -> bool -> t + = "caml_binaryen_array_get" + (** Module, array, index, type, signed *) + + external set : Module.t -> t -> t -> t -> t = "caml_binaryen_array_set" + (** Module, array, index, value *) + + external len : Module.t -> t -> t = "caml_binaryen_array_len" + (** Module, array *) + + external copy : Module.t -> t -> t -> t -> t -> t -> t + = "caml_binaryen_array_copy__bytecode" "caml_binaryen_array_copy" + (** Module, dest, dest index, src, src index, length *) end (** Bindings for `try_table` instruction. *) diff --git a/src/expression.mli b/src/expression.mli index 3b70645a..9fe75788 100644 --- a/src/expression.mli +++ b/src/expression.mli @@ -161,6 +161,21 @@ module Call_indirect : sig val set_return : t -> bool -> unit end +module Call_ref : sig + val make : Module.t -> t -> t list -> Type.t -> t + val make_return : Module.t -> t -> t list -> Type.t -> t + val get_target : t -> t + val set_target : t -> t -> unit + val get_num_operands : t -> int + val get_operand_at : t -> int -> t + val set_operand_at : t -> int -> t -> unit + val append_operand : t -> t -> int + val insert_operand_at : t -> int -> t -> unit + val remove_operand_at : t -> int -> t + val is_return : t -> bool + val set_return : t -> bool -> unit +end + module Local_get : sig val make : Module.t -> int -> Type.t -> t end @@ -348,6 +363,51 @@ module Ref : sig val eq : Module.t -> t -> t -> t (** Module, left, right *) + + val test : Module.t -> t -> Type.t -> t + (** Module, value, type *) + + val cast : Module.t -> t -> Type.t -> t + (** Module, value, type *) +end + +module BrOn : sig + val make : Module.t -> Op.t -> string -> t -> Type.t -> t + (** Module, op, label, value, type *) +end + +module Struct : sig + val new_ : Module.t -> t list option -> Heap_type.t -> t + (** Mdoule, operands, type *) + + val get : Module.t -> int -> t -> Type.t -> bool -> t + (** Module, index, struct, type, signed *) + + val set : Module.t -> int -> t -> t -> t + (** Module, index, struct, value *) +end + +module Array : sig + val new_ : Module.t -> Heap_type.t -> t -> t -> t + (** Module, type, size, init *) + + val new_data : Module.t -> Heap_type.t -> string -> t -> t -> t + (** Module, type, data name, offset, size *) + + val new_fixed : Module.t -> Heap_type.t -> t list -> t + (** Module, type, values *) + + val get : Module.t -> t -> t -> Type.t -> bool -> t + (** Module, array, index, type, signed *) + + val set : Module.t -> t -> t -> t -> t + (** Module, array, index, value *) + + val len : Module.t -> t -> t + (** Module, array *) + + val copy : Module.t -> t -> t -> t -> t -> t -> t + (** Module, dest, dest index, src, src index, length *) end (** Bindings for `try` instruction. *) diff --git a/src/ocaml_helpers.c b/src/ocaml_helpers.c index d8af8bb6..be2568dc 100644 --- a/src/ocaml_helpers.c +++ b/src/ocaml_helpers.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "ocaml_helpers.h" @@ -102,6 +103,14 @@ value alloc_BinaryenElementSegmentRef(BinaryenElementSegmentRef elem) return v; } +/* Allocating an OCaml custom block to hold the given TypeBuilderRef */ +value alloc_TypeBuilderRef(TypeBuilderRef builder) +{ + value v = caml_alloc_custom(&binaryen_ops, sizeof(TypeBuilderRef), 0, 1); + TypeBuilderRef_val(v) = builder; + return v; +} + CAMLprim value array_of_list(value list) { CAMLparam1(list); diff --git a/src/ocaml_helpers.h b/src/ocaml_helpers.h index 939ba09e..5c32738c 100644 --- a/src/ocaml_helpers.h +++ b/src/ocaml_helpers.h @@ -23,6 +23,7 @@ static struct custom_operations binaryen_ops = { #define BinaryenModuleRef_val(v) (*((BinaryenModuleRef*) Data_custom_val(v))) #define BinaryenType_val(v) (*((BinaryenType*) Data_custom_val(v))) +#define BinaryenPackedType_val(v) Int_val(v) #define BinaryenHeapType_val(v) (*((BinaryenHeapType*) Data_custom_val(v))) #define BinaryenExpressionRef_val(v) (*((BinaryenExpressionRef*) Data_custom_val(v))) #define BinaryenOp_val(v) (*((BinaryenOp*) Data_custom_val(v))) @@ -33,6 +34,7 @@ static struct custom_operations binaryen_ops = { #define BinaryenExportRef_val(v) (*((BinaryenExportRef*) Data_custom_val(v))) #define BinaryenTableRef_val(v) (*((BinaryenTableRef*) Data_custom_val(v))) #define BinaryenElementSegmentRef_val(v) (*((BinaryenElementSegmentRef*) Data_custom_val(v))) +#define TypeBuilderRef_val(v) (*((TypeBuilderRef*) Data_custom_val(v))) #define Val_none Val_int(0) #define Some_val(v) Field(v, 0) @@ -78,6 +80,9 @@ value alloc_BinaryenTableRef(BinaryenTableRef table); /* Allocating an OCaml custom block to hold the given BinaryenElementSegmentRef */ value alloc_BinaryenElementSegmentRef(BinaryenElementSegmentRef elem); +/* Allocating an OCaml custom block to hold the given TypeBuilderRef */ +value alloc_TypeBuilderRef(TypeBuilderRef builder); + CAMLprim value array_of_list(value list); diff --git a/src/type.ml b/src/type.ml index 119be8cc..8090acb6 100644 --- a/src/type.ml +++ b/src/type.ml @@ -75,5 +75,8 @@ let auto = auto () external create : t array -> t = "caml_binaryen_type_create" external expand : t -> t array = "caml_binaryen_type_expand" external is_nullable : t -> bool = "caml_binaryen_type_is_nullable" -external from_heap_type : Heap_type.t -> t = "caml_binaryen_type_from_heap_type" + +external from_heap_type : Heap_type.t -> bool -> t + = "caml_binaryen_type_from_heap_type" + external get_heap_type : t -> Heap_type.t = "caml_binaryen_type_get_heap_type" diff --git a/src/type.mli b/src/type.mli index 874ddb37..868ac579 100644 --- a/src/type.mli +++ b/src/type.mli @@ -21,5 +21,5 @@ val auto : t val create : t array -> t val expand : t -> t array val is_nullable : t -> bool -val from_heap_type : Heap_type.t -> t +val from_heap_type : Heap_type.t -> bool -> t val get_heap_type : t -> Heap_type.t diff --git a/src/type_builder.c b/src/type_builder.c new file mode 100644 index 00000000..c1680ba6 --- /dev/null +++ b/src/type_builder.c @@ -0,0 +1,176 @@ +#define CAML_NAME_SPACE +#include +#include +#include +#include + +#include "binaryen-c.h" +#include "ocaml_helpers.h" + +CAMLprim value +caml_type_builder_create(value _size) { + CAMLparam1(_size); + BinaryenIndex size = Int_val(_size); + CAMLreturn(alloc_TypeBuilderRef(TypeBuilderCreate(size))); +} + +CAMLprim value +caml_type_builder_grow(value _builder, value _count) { + CAMLparam2(_builder, _count); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex count = Int_val(_count); + TypeBuilderGrow(builder, count); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_type_builder_get_size(value _builder) { + CAMLparam1(_builder); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + CAMLreturn(Val_int(TypeBuilderGetSize(builder))); +} + +CAMLprim value +caml_type_builder_set_signature_type(value _builder, value _index, value _paramTypes, value _resultTypes) { + CAMLparam4(_builder, _index, _paramTypes, _resultTypes); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + BinaryenType paramTypes = BinaryenType_val(_paramTypes); + BinaryenType resultTypes = BinaryenType_val(_resultTypes); + TypeBuilderSetSignatureType(builder, index, paramTypes, resultTypes); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_type_builder_set_struct_type(value _builder, value _index, value _fieldTypes, value _fieldPackedTypes, value _fieldMutables, value _numFields) { + CAMLparam5(_builder, _index, _fieldTypes, _fieldPackedTypes, _fieldMutables); + CAMLxparam1(_numFields); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + _fieldTypes = array_of_list(_fieldTypes); + int fieldTypesLen = array_length(_fieldTypes); + BinaryenType fieldTypes[fieldTypesLen]; + for (int i = 0; i < fieldTypesLen; i++) { + fieldTypes[i] = BinaryenType_val(Field(_fieldTypes, i)); + } + _fieldPackedTypes = array_of_list(_fieldPackedTypes); + int fieldPackedTypesLen = array_length(_fieldPackedTypes); + BinaryenPackedType fieldPackedTypes[fieldPackedTypesLen]; + for (int i = 0; i < fieldPackedTypesLen; i++) { + fieldPackedTypes[i] = BinaryenPackedType_val(Field(_fieldPackedTypes, i)); + } + _fieldMutables = array_of_list(_fieldMutables); + int fieldMutablesLen = array_length(_fieldMutables); + bool fieldMutables[fieldMutablesLen]; + for (int i = 0; i < fieldMutablesLen; i++) { + fieldMutables[i] = Bool_val(Field(_fieldMutables, i)); + } + int numFields = Int_val(_numFields); + TypeBuilderSetStructType(builder, index, fieldTypes, fieldPackedTypes, fieldMutables, numFields); + CAMLreturn(Val_unit); +} +CAMLprim value +caml_type_builder_set_struct_type__bytecode(value * argv) { + return caml_type_builder_set_struct_type(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +CAMLprim value +caml_type_builder_set_array_type(value _builder, value _index, value _elementType, value _elementPackedType, value _elementMutable) { + CAMLparam5(_builder, _index, _elementType, _elementPackedType, _elementMutable); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + BinaryenType elementType = BinaryenType_val(_elementType); + BinaryenPackedType elementPackedType = BinaryenPackedType_val(_elementPackedType); + bool elementMutable = Bool_val(_elementMutable); + TypeBuilderSetArrayType(builder, index, elementType, elementPackedType, elementMutable); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_type_builder_get_temp_heap_type(value _builder, value _index) { + CAMLparam2(_builder, _index); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + CAMLreturn(alloc_BinaryenHeapType(TypeBuilderGetTempHeapType(builder, index))); +} + +CAMLprim value +caml_type_builder_get_temp_tuple_type(value _builder, value _types, value _numTypes) { + CAMLparam3(_builder, _types, _numTypes); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + _types = array_of_list(_types); + int typesLen = array_length(_types); + BinaryenType types[typesLen]; + for (int i = 0; i < typesLen; i++) { + types[i] = BinaryenType_val(Field(_types, i)); + } + int numTypes = Int_val(_numTypes); + CAMLreturn(alloc_BinaryenType(TypeBuilderGetTempTupleType(builder, types, numTypes))); +} + +CAMLprim value +caml_type_builder_get_temp_ref_type(value _builder, value _heapType, value _nullable) { + CAMLparam3(_builder, _heapType, _nullable); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenHeapType heapType = BinaryenHeapType_val(_heapType); + bool nullable = Bool_val(_nullable); + CAMLreturn(alloc_BinaryenType(TypeBuilderGetTempRefType(builder, heapType, nullable))); +} + +CAMLprim value +caml_type_builder_set_sub_type(value _builder, value _index, value _superType) { + CAMLparam3(_builder, _index, _superType); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + BinaryenHeapType superType = BinaryenHeapType_val(_superType); + TypeBuilderSetSubType(builder, index, superType); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_type_builder_set_open(value _builder, value _index) { + CAMLparam2(_builder, _index); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + TypeBuilderSetOpen(builder, index); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_type_builder_create_rec_group(value _builder, value _index, value _length) { + CAMLparam3(_builder, _index, _length); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex index = Int_val(_index); + BinaryenIndex length = Int_val(_length); + TypeBuilderCreateRecGroup(builder, index, length); + CAMLreturn(Val_unit); +} + +CAMLprim value +caml_conv_heap_type(BinaryenHeapType heapType) { + return alloc_BinaryenHeapType(heapType); +} + +CAMLprim value +caml_type_builder_build_and_dispose(value _builder) { + CAMLparam1(_builder); + TypeBuilderRef builder = TypeBuilderRef_val(_builder); + BinaryenIndex size = TypeBuilderGetSize(builder); + BinaryenHeapType heapTypes[size + 1]; + heapTypes[size] = (BinaryenHeapType) NULL; + BinaryenIndex errorIndex; + TypeBuilderErrorReason errorReason; + bool success = TypeBuilderBuildAndDispose(builder, heapTypes, &errorIndex, &errorReason); + if (success) { + value ok = caml_alloc_small(1, 0); + Field(ok, 0) = caml_alloc_array((void*)caml_conv_heap_type, (char const **)heapTypes); + CAMLreturn(ok); + } else { + value error = caml_alloc_small(1, 1); + value tuple = caml_alloc_small(2, 0); + Field(tuple, 0) = Val_int(errorIndex); + Field(tuple, 1) = Val_int(errorReason); + Field(error, 0) = tuple; + CAMLreturn(error); + } +} diff --git a/src/type_builder.js b/src/type_builder.js new file mode 100644 index 00000000..b8082e32 --- /dev/null +++ b/src/type_builder.js @@ -0,0 +1,116 @@ +//Provides: caml_type_builder_create +//Requires: Binaryen +function caml_type_builder_create(size) { + return new Binaryen.TypeBuilder(size); +} + +//Provides: caml_type_builder_grow +function caml_type_builder_grow(builder, count) { + builder.grow(count); +} + +//Provides: caml_type_builder_get_size +function caml_type_builder_get_size(builder) { + return builder.getSize(); +} + +//Provides: caml_type_builder_set_signature_type +function caml_type_builder_set_signature_type( + builder, + index, + paramTypes, + resultTypes +) { + builder.setSignatureType(index, paramTypes, resultTypes); +} + +//Provides: caml_type_builder_set_struct_type +//Requires: caml_list_to_js_array +//Requires: caml_js_from_bool +function caml_type_builder_set_struct_type( + builder, + index, + fieldTypes, + fieldPackedTypes, + fieldMutables, + numFields +) { + var types = caml_list_to_js_array(fieldTypes); + var packedTypes = caml_list_to_js_array(fieldPackedTypes); + var mutables = caml_list_to_js_array(fieldMutables); + var fields = types.map(function (type, idx) { + return { + type, + packedType: packedTypes[idx], + mutable: caml_js_from_bool(mutables[idx]), + }; + }); + builder.setStructType(index, fields); +} +//Provides: caml_type_builder_set_struct_type__bytecode +//Requires: caml_type_builder_set_struct_type +function caml_type_builder_set_struct_type__bytecode() { + return caml_type_builder_set_struct_type( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5] + ); +} + +//Provides: caml_type_builder_set_array_type +function caml_type_builder_set_array_type( + builder, + index, + elementType, + elementPackedType, + elementMutable +) { + builder.setArrayType(index, elementType, elementPackedType, elementMutable); +} + +//Provides: caml_type_builder_get_temp_heap_type +function caml_type_builder_get_temp_heap_type(builder, index) { + return builder.getTempHeapType(index); +} + +//Provides: caml_type_builder_get_temp_tuple_type +//Requires: caml_list_to_js_array +function caml_type_builder_get_temp_tuple_type(builder, types, numTypes) { + var tupleTypes = caml_list_to_js_array(types); + return builder.getTempTupleType(tupleTypes); +} + +//Provides: caml_type_builder_get_temp_ref_type +//Requires: caml_js_from_bool +function caml_type_builder_get_temp_ref_type(builder, heapType, nullable) { + return builder.getTempRefType(heapType, caml_js_from_bool(nullable)); +} + +//Provides: caml_type_builder_set_sub_type +function caml_type_builder_set_sub_type(builder, index, superType) { + builder.setSubType(index, superType); +} + +//Provides: caml_type_builder_set_open +function caml_type_builder_set_open(builder, index) { + builder.setOpen(index); +} + +//Provides: caml_type_builder_create_rec_group +function caml_type_builder_create_rec_group(builder, index, length) { + builder.createRecGroup(index, length); +} + +//Provides: caml_type_builder_build_and_dispose +//Requires: caml_js_to_array +function caml_type_builder_build_and_dispose(builder) { + try { + var types = builder.buildAndDispose(); + return [0, caml_js_to_array(types)]; + } catch (e) { + return [1, [0, e.index, e.reason]]; + } +} diff --git a/src/type_builder.ml b/src/type_builder.ml new file mode 100644 index 00000000..0d72d937 --- /dev/null +++ b/src/type_builder.ml @@ -0,0 +1,65 @@ +type t + +type struct_field = { + type_ : Type.t; + packed_type : Packed_type.t; + mutable_ : bool; +} + +type error = + | SelfSupertype of int + | InvalidSupertype of int + | ForwardSupertypeReference of int + | ForwardChildReference of int + +external make : int -> t = "caml_type_builder_create" +external grow : t -> int -> unit = "caml_type_builder_grow" +external size : t -> int = "caml_type_builder_grow" + +external set_signature_type : t -> int -> Type.t -> Type.t -> unit + = "caml_type_builder_set_signature_type" + +external set_struct_type : + t -> int -> Type.t list -> Packed_type.t list -> bool list -> int -> unit + = "caml_type_builder_set_struct_type__bytecode" "caml_type_builder_set_struct_type" + +let set_struct_type builder index fields = + let split_fields fields = + List.fold_right + (fun { type_; packed_type; mutable_ } (types, packed_types, mutables) -> + (type_ :: types, packed_type :: packed_types, mutable_ :: mutables)) + fields ([], [], []) + in + let types, packed_types, mutables = split_fields fields in + set_struct_type builder index types packed_types mutables (List.length types) + +external set_array_type : t -> int -> Type.t -> Packed_type.t -> bool -> unit + = "caml_type_builder_set_array_type" + +external get_temp_heap_type : t -> int -> Heap_type.t + = "caml_type_builder_get_temp_heap_type" + +external get_temp_tuple_type : t -> Type.t list -> Type.t + = "caml_type_builder_get_temp_tuple_type" + +external get_temp_ref_type : t -> Heap_type.t -> bool -> Type.t + = "caml_type_builder_get_temp_ref_type" + +external set_sub_type : t -> int -> Type.t -> unit + = "caml_type_builder_set_sub_type" + +external set_open : t -> int -> unit = "caml_type_builder_set_open" + +external create_rec_group : t -> int -> int -> unit + = "caml_type_builder_create_rec_group" + +external build_and_dispose : t -> (Type.t array, int * int) result + = "caml_type_builder_build_and_dispose" + +let build_and_dispose builder = + match build_and_dispose builder with + | Ok types -> Ok (Array.to_list types) + | Error (idx, 0) -> Error (SelfSupertype idx) + | Error (idx, 1) -> Error (InvalidSupertype idx) + | Error (idx, 2) -> Error (ForwardSupertypeReference idx) + | Error (idx, _) -> Error (ForwardChildReference idx) diff --git a/src/type_builder.mli b/src/type_builder.mli new file mode 100644 index 00000000..260458db --- /dev/null +++ b/src/type_builder.mli @@ -0,0 +1,27 @@ +type t + +type struct_field = { + type_ : Type.t; + packed_type : Packed_type.t; + mutable_ : bool; +} + +type error = + | SelfSupertype of int + | InvalidSupertype of int + | ForwardSupertypeReference of int + | ForwardChildReference of int + +val make : int -> t +val grow : t -> int -> unit +val size : t -> int +val set_signature_type : t -> int -> Type.t -> Type.t -> unit +val set_struct_type : t -> int -> struct_field list -> unit +val set_array_type : t -> int -> Type.t -> Packed_type.t -> bool -> unit +val get_temp_heap_type : t -> int -> Heap_type.t +val get_temp_tuple_type : t -> Type.t list -> Type.t +val get_temp_ref_type : t -> Heap_type.t -> bool -> Type.t +val set_sub_type : t -> int -> Type.t -> unit +val set_open : t -> int -> unit +val create_rec_group : t -> int -> int -> unit +val build_and_dispose : t -> (Type.t list, error) result diff --git a/test/test.expected b/test/test.expected index 0a35f066..364fd155 100644 --- a/test/test.expected +++ b/test/test.expected @@ -7,6 +7,15 @@ (i32.const 0) ) (module + (type $0 (struct (field i31ref) (field (ref null $0)))) + (type $1 (array (mut i8))) + (type $2 (func (param i32 i32) (result i32))) + (type $3 (func (result (ref $1) (ref $0)))) + (type $4 (func)) + (type $5 (func (param anyref i32 i32) (result i32))) + (type $6 (func (param anyref) (result i32))) + (type $7 (func (param anyref) (result anyref anyref))) + (import "future-wasi" "write" (func $write (type $5) (param anyref i32 i32) (result i32))) (type $0 (func (param i32))) (type $1 (func (param i32 i32) (result i32))) (type $2 (func)) @@ -26,8 +35,10 @@ (export "adder" (func $adder)) (export "memory" (memory $0)) (export "hello" (func $hello)) + (export "gc" (func $gc)) (export "try" (func $try)) (start $start) + (func $adder (type $2) (param $0 i32) (param $1 i32) (result i32) (func $adder (type $1) (param $0 i32) (param $1 i32) (result i32) (block $add (result i32) (if @@ -48,6 +59,7 @@ ) ) ) + (func $start (type $4) (func $start (type $2) (block $start (memory.init $world @@ -56,6 +68,7 @@ (i32.const 5) ) (drop + (call_indirect $table (type $2) (call_indirect $table (type $1) (i32.const 3) (i32.const 5) @@ -64,6 +77,7 @@ ) ) ) + (func $hello (type $6) (param $0 anyref) (result i32) (func $hello (type $4) (param $0 anyref) (result i32) (call $write (local.get $0) @@ -71,6 +85,50 @@ (i32.const 1) ) ) + (func $gc (type $7) (param $0 anyref) (result anyref anyref) + (local $1 (ref $1)) + (local $2 (ref $0)) + (block $gc_block (type $3) (result (ref $1) (ref $0)) + (local.set $1 + (array.new_fixed $1 2 + (i32.const 0) + (i32.const 255) + ) + ) + (array.set $1 + (local.get $1) + (i32.const 1) + (i32.const 42) + ) + (local.set $2 + (struct.new $0 + (ref.cast i31ref + (local.get $0) + ) + (struct.new $0 + (ref.i31 + (i32.const 1) + ) + (struct.new $0 + (ref.i31 + (i32.const 2) + ) + (struct.new $0 + (ref.i31 + (i32.const 3) + ) + (ref.null none) + ) + ) + ) + ) + ) + (tuple.make 2 + (local.get $1) + (local.get $2) + ) + ) + ) (func $try (type $2) (block $blk (drop @@ -141,6 +199,15 @@ ) ) (module + (type $0 (struct (field i31ref) (field (ref null $0)))) + (type $1 (array (mut i8))) + (type $2 (func (result (ref $1) (ref $0)))) + (type $3 (func (param i32 i32) (result i32))) + (type $4 (func)) + (type $5 (func (param anyref i32 i32) (result i32))) + (type $6 (func (param anyref) (result i32))) + (type $7 (func (param anyref) (result anyref anyref))) + (import "future-wasi" "write" (func $write (type $5) (param anyref i32 i32) (result i32))) (type $0 (func (param i32))) (type $1 (func)) (type $2 (func (param i32 i32) (result i32))) @@ -157,8 +224,10 @@ (export "adder" (func $adder)) (export "memory" (memory $0)) (export "hello" (func $hello)) + (export "gc" (func $gc)) (export "try" (func $try)) (start $start) + (func $adder (type $3) (param $0 i32) (param $1 i32) (result i32) (func $adder (type $2) (param $0 i32) (param $1 i32) (result i32) (i32.add (select @@ -171,7 +240,7 @@ (local.get $1) ) ) - (func $start (type $1) + (func $start (type $4) (memory.init $world (i32.const 2048) (i32.const 0) @@ -184,6 +253,7 @@ ) ) ) + (func $hello (type $6) (param $0 anyref) (result i32) (func $hello (type $4) (param $0 anyref) (result i32) (call $write (local.get $0) @@ -191,6 +261,43 @@ (i32.const 1) ) ) + (func $gc (type $7) (param $0 anyref) (result anyref anyref) + (local $1 (ref $1)) + (array.set $1 + (local.tee $1 + (array.new_fixed $1 2 + (i32.const 0) + (i32.const 255) + ) + ) + (i32.const 1) + (i32.const 42) + ) + (tuple.make 2 + (local.get $1) + (struct.new $0 + (ref.cast i31ref + (local.get $0) + ) + (struct.new $0 + (ref.i31 + (i32.const 1) + ) + (struct.new $0 + (ref.i31 + (i32.const 2) + ) + (struct.new $0 + (ref.i31 + (i32.const 3) + ) + (ref.null none) + ) + ) + ) + ) + ) + ) (func $try (type $1) (drop (try (result i32) @@ -233,6 +340,15 @@ ) ) (module + (type $type_6 (struct (field i31ref) (field (ref null $type_6)))) + (type $type_5 (array (mut i8))) + (type $type_7 (func (result anyref anyref))) + (type $type (func (param anyref i32 i32) (result i32))) + (type $type_1 (func (param i32 i32) (result i32))) + (type $type_2 (func)) + (type $type_3 (func (param anyref) (result i32))) + (type $type_4 (func (param anyref) (result anyref anyref))) + (import "future-wasi" "write" (func $fimport$0 (type $type) (param anyref i32 i32) (result i32))) (type $type_3 (func)) (type $type_1 (func (param anyref i32 i32) (result i32))) (type $type_2 (func (param i32 i32) (result i32))) @@ -246,6 +362,7 @@ (export "adder" (func $0)) (export "memory" (memory $0)) (export "hello" (func $2)) + (export "gc" (func $3)) (export "try" (func $3)) (start $1) (func $0 (type $type_2) (param $0 i32) (param $1 i32) (result i32) @@ -280,6 +397,43 @@ (i32.const 1) ) ) + (func $3 (type $type_4) (param $0 anyref) (result anyref anyref) + (local $1 (ref $type_5)) + (array.set $type_5 + (local.tee $1 + (array.new_fixed $type_5 2 + (i32.const 0) + (i32.const 255) + ) + ) + (i32.const 1) + (i32.const 42) + ) + (tuple.make 2 + (local.get $1) + (struct.new $type_6 + (ref.cast i31ref + (local.get $0) + ) + (struct.new $type_6 + (ref.i31 + (i32.const 1) + ) + (struct.new $type_6 + (ref.i31 + (i32.const 2) + ) + (struct.new $type_6 + (ref.i31 + (i32.const 3) + ) + (ref.null none) + ) + ) + ) + ) + ) + ) (func $3 (type $type_3) (drop (unreachable) @@ -288,6 +442,15 @@ ) ) (module + (type $type_6 (struct (field i31ref) (field (ref null $type_6)))) + (type $type_5 (array (mut i8))) + (type $type_7 (func (result anyref anyref))) + (type $type (func (param anyref i32 i32) (result i32))) + (type $type_1 (func (param i32 i32) (result i32))) + (type $type_2 (func)) + (type $type_3 (func (param anyref) (result i32))) + (type $type_4 (func (param anyref) (result anyref anyref))) + (import "future-wasi" "write" (func $fimport$0 (type $type) (param anyref i32 i32) (result i32))) (type $type_3 (func)) (type $type_1 (func (param anyref i32 i32) (result i32))) (type $type_2 (func (param i32 i32) (result i32))) @@ -301,6 +464,7 @@ (export "adder" (func $0)) (export "memory" (memory $0)) (export "hello" (func $2)) + (export "gc" (func $3)) (export "try" (func $3)) (start $1) (func $0 (type $type_2) (param $0 i32) (param $1 i32) (result i32) @@ -328,6 +492,31 @@ i32.const 1 call $fimport$0 ) + (func $3 (type $type_4) (param $0 anyref) (result anyref anyref) + (local $1 (ref $type_5)) + i32.const 0 + i32.const 255 + array.new_fixed $type_5 2 + local.tee $1 + i32.const 1 + i32.const 42 + array.set $type_5 + local.get $1 + local.get $0 + ref.cast i31ref + i32.const 1 + ref.i31 + i32.const 2 + ref.i31 + i32.const 3 + ref.i31 + ref.null none + struct.new $type_6 + struct.new $type_6 + struct.new $type_6 + struct.new $type_6 + tuple.make 2 + ) (func $3 (type $type_3) unreachable ) diff --git a/test/test.ml b/test/test.ml index 95634257..137e61b7 100644 --- a/test/test.ml +++ b/test/test.ml @@ -257,6 +257,19 @@ let _ = (Memory.get_segment_data wasm_mod "world") (Bytes.of_string "world")) +(* Call_ref *) +let thunk_type = + let builder = Type_builder.make 1 in + Type_builder.set_signature_type builder 0 Type.none Type.none; + match Type_builder.build_and_dispose builder with + | Ok [ ty ] -> ty + | _ -> failwith "failed to build type" + +let _ = + Expression.Call_ref.make wasm_mod + (Expression.Ref.func wasm_mod "start" thunk_type) + [] Type.none + let _ = Tag.add_tag wasm_mod "foo" Type.int32 Type.none let _ = Tag.add_tag wasm_mod "bar" Type.int32 Type.none @@ -368,6 +381,79 @@ let _ = Export.add_function_export wasm_mod "hello" "hello" let _ = Export.add_function_export wasm_mod "try" "try" let _ = Module.validate wasm_mod +(* Create a function that does gc *) +let _ = + let array_u8_type = + let builder = Type_builder.make 1 in + Type_builder.set_array_type builder 0 Type.int32 Packed_type.int8 true; + match Type_builder.build_and_dispose builder with + | Ok [ ty ] -> ty + | _ -> failwith "failed to make array type" + in + let list_type = + let builder = Type_builder.make 1 in + let temp_heap_type = Type_builder.get_temp_heap_type builder 0 in + let temp_ref_type = + Type_builder.get_temp_ref_type builder temp_heap_type true + in + Type_builder.set_struct_type builder 0 + [ + Type_builder. + { + type_ = Type.i31ref; + packed_type = Packed_type.not_packed; + mutable_ = false; + }; + Type_builder. + { + type_ = temp_ref_type; + packed_type = Packed_type.not_packed; + mutable_ = false; + }; + ]; + match Type_builder.build_and_dispose builder with + | Ok [ ty ] -> ty + | _ -> failwith "failed to make list type" + in + let i32 v = Expression.Const.make wasm_mod (Literal.int32 v) in + let i31 v = Expression.I31.make wasm_mod (i32 v) in + let cons first rest = + Expression.Struct.new_ wasm_mod + (Some [ first; rest ]) + (Type.get_heap_type list_type) + in + let empty () = + Expression.Ref.null wasm_mod + (Type.from_heap_type (Type.get_heap_type list_type) true) + in + Function.add_function wasm_mod "gc" Type.anyref + (Type.create [| Type.anyref; Type.anyref |]) + [| array_u8_type; list_type |] + (Expression.Block.make wasm_mod "gc_block" + [ + Expression.Local_set.make wasm_mod 1 + (Expression.Array.new_fixed wasm_mod + (Type.get_heap_type array_u8_type) + [ i32 0l; i32 255l ]); + Expression.Array.set wasm_mod + (Expression.Local_get.make wasm_mod 1 array_u8_type) + (i32 1l) (i32 42l); + Expression.Local_set.make wasm_mod 2 + (cons + (Expression.Ref.cast wasm_mod + (Expression.Local_get.make wasm_mod 0 Type.anyref) + Type.i31ref) + (cons (i31 1l) (cons (i31 2l) (cons (i31 3l) (empty ()))))); + Expression.Tuple_make.make wasm_mod + [ + Expression.Local_get.make wasm_mod 1 array_u8_type; + Expression.Local_get.make wasm_mod 2 list_type; + ]; + ]) + +let _ = Export.add_function_export wasm_mod "gc" "gc" +let _ = assert (Module.validate wasm_mod == 1) + (* Shouldn't actually do anything since we aren't doing function renames *) let _ = Module.update_maps wasm_mod @@ -440,7 +526,7 @@ let _ = Module.Feature.all; ] -let _ = Module.validate new_mod +let _ = assert (Module.validate new_mod == 1) let _ = Module.print new_mod let _ = Module.print_stack_ir new_mod From 66da14bd9ca588e8c4646b8c414e5ef9b0b7116b Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Fri, 5 Dec 2025 10:49:06 -0500 Subject: [PATCH 02/17] feat: Implement additional gc instructions --- src/expression.c | 24 ++++++++++++++++++++++++ src/expression.js | 36 ++++++++++++++++++++++-------------- src/expression.ml | 8 ++++++++ src/expression.mli | 6 ++++++ src/type_builder.ml | 8 +++++--- src/type_builder.mli | 5 +++-- test/test.expected | 8 ++++---- test/test.ml | 24 +++++++++++++----------- 8 files changed, 85 insertions(+), 34 deletions(-) diff --git a/src/expression.c b/src/expression.c index 2d737493..34a34d3b 100644 --- a/src/expression.c +++ b/src/expression.c @@ -2086,6 +2086,18 @@ caml_binaryen_array_new_data(value _module, value _type, value _name, value _off CAMLreturn(alloc_BinaryenExpressionRef(exp)); } +CAMLprim value +caml_binaryen_array_new_elem(value _module, value _type, value _seg, value _offset, value _size) { + CAMLparam5(_module, _type, _seg, _offset, _size); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType type = BinaryenHeapType_val(_type); + char* seg = Safe_String_val(_seg); + BinaryenExpressionRef offset = BinaryenExpressionRef_val(_offset); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef exp = BinaryenArrayNewElem(module, type, seg, offset, size); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + CAMLprim value caml_binaryen_array_new_fixed(value _module, value _type, value _values) { CAMLparam3(_module, _type, _values); @@ -2151,6 +2163,18 @@ caml_binaryen_array_copy__bytecode(value * argv) { return caml_binaryen_array_copy(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); } +CAMLprim value +caml_binaryen_array_fill(value _module, value _ref, value _index, value _value, value _size) { + CAMLparam5(_module, _ref, _index, _value, _size); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef index = BinaryenExpressionRef_val(_index); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_value); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef exp = BinaryenArrayFill(module, ref, index, val, size); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + // Exception handling operations CAMLprim value caml_binaryen_try(value _module, value _name, value _body, value _catchTags, value _catchBodies, value _delegateTarget) { diff --git a/src/expression.js b/src/expression.js index f6ab3685..cface125 100644 --- a/src/expression.js +++ b/src/expression.js @@ -575,13 +575,13 @@ function caml_binaryen_ref_cast(wasm_mod, ref, typ) { function caml_binaryen_br_on(wasm_mod, op, name, ref, typ) { switch (op) { case Binaryen.BrOnNull: - return wasm_mod.br_on.null(caml_jsstring_of_string(name), ref, typ); + return wasm_mod.br_on_null(caml_jsstring_of_string(name), ref); case Binaryen.BrOnNonNull: - return wasm_mod.br_on.non_null(caml_jsstring_of_string(name), ref, typ); + return wasm_mod.br_on_non_null(caml_jsstring_of_string(name), ref); case Binaryen.BrOnCast: - return wasm_mod.br_on.cast(caml_jsstring_of_string(name), ref, typ); + return wasm_mod.br_on_cast(caml_jsstring_of_string(name), ref, typ); case Binaryen.BrOnCastFail: - return wasm_mod.br_on.cast_fail(caml_jsstring_of_string(name), ref, typ); + return wasm_mod.br_on_cast_fail(caml_jsstring_of_string(name), ref, typ); } } @@ -1821,11 +1821,7 @@ function caml_binaryen_struct_new(wasm_mod, operands, type) { //Provides: caml_binaryen_struct_get //Requires: caml_js_from_bool function caml_binaryen_struct_get(wasm_mod, index, ref, type, signed) { - if (caml_js_from_bool(signed)) { - return wasm_mod.struct.get_s(index, ref, type); - } else { - return wasm_mod.struct.get_u(index, ref, type); - } + return wasm_mod.struct.get(index, ref, type, caml_js_from_bool(signed)); } //Provides: caml_binaryen_struct_set @@ -1851,6 +1847,17 @@ function caml_binaryen_array_new_data(wasm_mod, type, name, offset, size) { ); } +//Provides: caml_binaryen_array_new_elem +//Requires: caml_jsstring_of_string +function caml_binaryen_array_new_elem(wasm_mod, type, name, offset, size) { + return wasm_mod.array.new_elem( + type, + caml_jsstring_of_string(name), + offset, + size + ); +} + //Provides: caml_binaryen_array_new_fixed //Requires: caml_list_to_js_array function caml_binaryen_array_new_fixed(wasm_mod, type, values) { @@ -1860,11 +1867,7 @@ function caml_binaryen_array_new_fixed(wasm_mod, type, values) { //Provides: caml_binaryen_array_get //Requires: caml_js_from_bool function caml_binaryen_array_get(wasm_mod, ref, index, type, signed) { - if (caml_js_from_bool(signed)) { - return wasm_mod.array.get_s(ref, index, type); - } else { - return wasm_mod.array.get_u(ref, index, type); - } + return wasm_mod.array.get(ref, index, type, caml_js_from_bool(signed)); } //Provides: caml_binaryen_array_set @@ -1877,6 +1880,11 @@ function caml_binaryen_array_len(wasm_mod, ref) { return wasm_mod.array.len(ref); } +//Provides: caml_binaryen_array_fill +function caml_binaryen_array_fill(wasm_mod, ref, index, value, size) { + return wasm_mod.array.fill(ref, index, value, size); +} + //Provides: caml_binaryen_array_copy function caml_binaryen_array_copy( wasm_mod, diff --git a/src/expression.ml b/src/expression.ml index 2eb57841..86add2ee 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -899,6 +899,10 @@ module Array = struct = "caml_binaryen_array_new_data" (** Module, type, data name, offset, size *) + external new_elem : Module.t -> Heap_type.t -> string -> t -> t -> t + = "caml_binaryen_array_new_elem" + (** Module, type, seg, offset, size *) + external new_fixed : Module.t -> Heap_type.t -> t list -> t = "caml_binaryen_array_new_fixed" (** Module, type, values *) @@ -913,6 +917,10 @@ module Array = struct external len : Module.t -> t -> t = "caml_binaryen_array_len" (** Module, array *) + external fill : Module.t -> Heap_type.t -> t -> t -> t -> t + = "caml_binaryen_array_fill" + (** Module, type, seg, offset, size *) + external copy : Module.t -> t -> t -> t -> t -> t -> t = "caml_binaryen_array_copy__bytecode" "caml_binaryen_array_copy" (** Module, dest, dest index, src, src index, length *) diff --git a/src/expression.mli b/src/expression.mli index 9fe75788..20e954ad 100644 --- a/src/expression.mli +++ b/src/expression.mli @@ -394,6 +394,9 @@ module Array : sig val new_data : Module.t -> Heap_type.t -> string -> t -> t -> t (** Module, type, data name, offset, size *) + val new_elem : Module.t -> Heap_type.t -> string -> t -> t -> t + (** Module, type, seg, offset, size *) + val new_fixed : Module.t -> Heap_type.t -> t list -> t (** Module, type, values *) @@ -406,6 +409,9 @@ module Array : sig val len : Module.t -> t -> t (** Module, array *) + val fill : Module.t -> Heap_type.t -> t -> t -> t -> t + (** Module, type, seg, offset, size *) + val copy : Module.t -> t -> t -> t -> t -> t -> t (** Module, dest, dest index, src, src index, length *) end diff --git a/src/type_builder.ml b/src/type_builder.ml index 0d72d937..28f33b03 100644 --- a/src/type_builder.ml +++ b/src/type_builder.ml @@ -6,6 +6,7 @@ type struct_field = { mutable_ : bool; } +(* Source: https://github.com/WebAssembly/binaryen/blob/64ba23996a10e229d46e41eb37736a55af87f79a/src/binaryen-c.h#L3618 *) type error = | SelfSupertype of int | InvalidSupertype of int @@ -21,7 +22,8 @@ external set_signature_type : t -> int -> Type.t -> Type.t -> unit external set_struct_type : t -> int -> Type.t list -> Packed_type.t list -> bool list -> int -> unit - = "caml_type_builder_set_struct_type__bytecode" "caml_type_builder_set_struct_type" + = "caml_type_builder_set_struct_type__bytecode" + "caml_type_builder_set_struct_type" let set_struct_type builder index fields = let split_fields fields = @@ -45,7 +47,7 @@ external get_temp_tuple_type : t -> Type.t list -> Type.t external get_temp_ref_type : t -> Heap_type.t -> bool -> Type.t = "caml_type_builder_get_temp_ref_type" -external set_sub_type : t -> int -> Type.t -> unit +external set_sub_type : t -> int -> Heap_type.t -> unit = "caml_type_builder_set_sub_type" external set_open : t -> int -> unit = "caml_type_builder_set_open" @@ -53,7 +55,7 @@ external set_open : t -> int -> unit = "caml_type_builder_set_open" external create_rec_group : t -> int -> int -> unit = "caml_type_builder_create_rec_group" -external build_and_dispose : t -> (Type.t array, int * int) result +external build_and_dispose : t -> (Heap_type.t array, int * int) result = "caml_type_builder_build_and_dispose" let build_and_dispose builder = diff --git a/src/type_builder.mli b/src/type_builder.mli index 260458db..f76dfbb1 100644 --- a/src/type_builder.mli +++ b/src/type_builder.mli @@ -6,6 +6,7 @@ type struct_field = { mutable_ : bool; } +(* Source: https://github.com/WebAssembly/binaryen/blob/64ba23996a10e229d46e41eb37736a55af87f79a/src/binaryen-c.h#L3618 *) type error = | SelfSupertype of int | InvalidSupertype of int @@ -21,7 +22,7 @@ val set_array_type : t -> int -> Type.t -> Packed_type.t -> bool -> unit val get_temp_heap_type : t -> int -> Heap_type.t val get_temp_tuple_type : t -> Type.t list -> Type.t val get_temp_ref_type : t -> Heap_type.t -> bool -> Type.t -val set_sub_type : t -> int -> Type.t -> unit +val set_sub_type : t -> int -> Heap_type.t -> unit val set_open : t -> int -> unit val create_rec_group : t -> int -> int -> unit -val build_and_dispose : t -> (Type.t list, error) result +val build_and_dispose : t -> (Heap_type.t list, error) result diff --git a/test/test.expected b/test/test.expected index 364fd155..0e730bba 100644 --- a/test/test.expected +++ b/test/test.expected @@ -201,7 +201,7 @@ (module (type $0 (struct (field i31ref) (field (ref null $0)))) (type $1 (array (mut i8))) - (type $2 (func (result (ref $1) (ref $0)))) + (type $2 (func (result (ref (exact $1)) (ref (exact $0))))) (type $3 (func (param i32 i32) (result i32))) (type $4 (func)) (type $5 (func (param anyref i32 i32) (result i32))) @@ -262,7 +262,7 @@ ) ) (func $gc (type $7) (param $0 anyref) (result anyref anyref) - (local $1 (ref $1)) + (local $1 (ref (exact $1))) (array.set $1 (local.tee $1 (array.new_fixed $1 2 @@ -398,7 +398,7 @@ ) ) (func $3 (type $type_4) (param $0 anyref) (result anyref anyref) - (local $1 (ref $type_5)) + (local $1 (ref (exact $type_5))) (array.set $type_5 (local.tee $1 (array.new_fixed $type_5 2 @@ -493,7 +493,7 @@ call $fimport$0 ) (func $3 (type $type_4) (param $0 anyref) (result anyref anyref) - (local $1 (ref $type_5)) + (local $1 (ref (exact $type_5))) i32.const 0 i32.const 255 array.new_fixed $type_5 2 diff --git a/test/test.ml b/test/test.ml index 137e61b7..a30d31da 100644 --- a/test/test.ml +++ b/test/test.ml @@ -418,25 +418,25 @@ let _ = let i32 v = Expression.Const.make wasm_mod (Literal.int32 v) in let i31 v = Expression.I31.make wasm_mod (i32 v) in let cons first rest = - Expression.Struct.new_ wasm_mod - (Some [ first; rest ]) - (Type.get_heap_type list_type) + Expression.Struct.new_ wasm_mod (Some [ first; rest ]) list_type in let empty () = - Expression.Ref.null wasm_mod - (Type.from_heap_type (Type.get_heap_type list_type) true) + Expression.Ref.null wasm_mod (Type.from_heap_type list_type true) in Function.add_function wasm_mod "gc" Type.anyref (Type.create [| Type.anyref; Type.anyref |]) - [| array_u8_type; list_type |] + [| + Type.from_heap_type array_u8_type false; + Type.from_heap_type list_type false; + |] (Expression.Block.make wasm_mod "gc_block" [ Expression.Local_set.make wasm_mod 1 - (Expression.Array.new_fixed wasm_mod - (Type.get_heap_type array_u8_type) + (Expression.Array.new_fixed wasm_mod array_u8_type [ i32 0l; i32 255l ]); Expression.Array.set wasm_mod - (Expression.Local_get.make wasm_mod 1 array_u8_type) + (Expression.Local_get.make wasm_mod 1 + (Type.from_heap_type array_u8_type false)) (i32 1l) (i32 42l); Expression.Local_set.make wasm_mod 2 (cons @@ -446,8 +446,10 @@ let _ = (cons (i31 1l) (cons (i31 2l) (cons (i31 3l) (empty ()))))); Expression.Tuple_make.make wasm_mod [ - Expression.Local_get.make wasm_mod 1 array_u8_type; - Expression.Local_get.make wasm_mod 2 list_type; + Expression.Local_get.make wasm_mod 1 + (Type.from_heap_type array_u8_type false); + Expression.Local_get.make wasm_mod 2 + (Type.from_heap_type list_type false); ]; ]) From 635dc112a957d29cc68698820290e1dd19d1766f Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Fri, 5 Dec 2025 16:00:57 -0500 Subject: [PATCH 03/17] chore: Re-enable funcref test --- test/test.ml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/test.ml b/test/test.ml index a30d31da..48a79f7b 100644 --- a/test/test.ml +++ b/test/test.ml @@ -171,13 +171,19 @@ let start = let _ = Export.add_function_export wasm_mod "adder" "adder" let _ = Table.add_table wasm_mod "table" 1 1 Type.funcref -(* TODO(#240): Re-enable after type-builder api is merged *) -(* let funcref_expr1 = Expression.Ref.func wasm_mod "adder" (Heap_type.func ()) +let adder_type = + let builder = Type_builder.make 1 in + Type_builder.set_signature_type builder 0 Type.none Type.none; + match Type_builder.build_and_dispose builder with + | Ok [ ty ] -> ty + | _ -> failwith "failed to build type" + +let funcref_expr1 = Expression.Ref.func wasm_mod "adder" adder_type let _ = Expression.Table.set wasm_mod "table" (Expression.Const.make wasm_mod (Literal.int32 0l)) - funcref_expr1 *) + funcref_expr1 let funcref_expr2 = Expression.Table.get wasm_mod "table" From 1021b7e59e3fab5f001ad58ce4f20741f7c1ab46 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Fri, 5 Dec 2025 16:16:41 -0500 Subject: [PATCH 04/17] feat: Implement `Array.init_data` and `Array.init_elem` --- src/expression.c | 38 ++++++++++++++++++++++++++++++++++++++ src/expression.js | 13 +++++++++++++ src/expression.ml | 8 ++++++++ src/expression.mli | 6 ++++++ 4 files changed, 65 insertions(+) diff --git a/src/expression.c b/src/expression.c index 34a34d3b..92a3f4a6 100644 --- a/src/expression.c +++ b/src/expression.c @@ -2175,6 +2175,44 @@ caml_binaryen_array_fill(value _module, value _ref, value _index, value _value, CAMLreturn(alloc_BinaryenExpressionRef(exp)); } +CAMLprim value +caml_binaryen_array_init_data(value _module, value _name, value _ref, value _index, value _offset, value _size) { + CAMLparam5(_module, _name, _ref, _index, _offset); + CAMLxparam1(_size); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + char* name = Safe_String_val(_name); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef index = BinaryenExpressionRef_val(_index); + BinaryenExpressionRef offset = BinaryenExpressionRef_val(_offset); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef exp = BinaryenArrayInitData(module, name, ref, index, offset, size); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_init_data__bytecode(value * argv) { + return caml_binaryen_array_init_data(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +CAMLprim value +caml_binaryen_array_init_elem(value _module, value _seg, value _ref, value _index, value _offset, value _size) { + CAMLparam5(_module, _seg, _ref, _index, _offset); + CAMLxparam1(_size); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + char* seg = Safe_String_val(_seg); + BinaryenExpressionRef ref = BinaryenExpressionRef_val(_ref); + BinaryenExpressionRef index = BinaryenExpressionRef_val(_index); + BinaryenExpressionRef offset = BinaryenExpressionRef_val(_offset); + BinaryenExpressionRef size = BinaryenExpressionRef_val(_size); + BinaryenExpressionRef exp = BinaryenArrayInitElem(module, seg, ref, index, offset, size); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_array_init_elem__bytecode(value * argv) { + return caml_binaryen_array_init_elem(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + // Exception handling operations CAMLprim value caml_binaryen_try(value _module, value _name, value _body, value _catchTags, value _catchBodies, value _delegateTarget) { diff --git a/src/expression.js b/src/expression.js index cface125..ab8bc535 100644 --- a/src/expression.js +++ b/src/expression.js @@ -1896,6 +1896,19 @@ function caml_binaryen_array_copy( ) { return wasm_mod.array.copy(destRef, destIndex, srcRef, srcIndex, length); } + +//Provides: caml_binaryen_array_init_data +//Requires: caml_jsstring_of_string +function caml_binaryen_array_init_data(name, ref, index, offset, size) { + return wasm_mod.array.init_data(caml_jsstring_of_string(name), ref, index, offset, size); +} + +//Provides: caml_binaryen_array_init_elem +//Requires: caml_jsstring_of_string +function caml_binaryen_array_init_elem(name, ref, index, offset, size) { + return wasm_mod.array.init_elem(caml_jsstring_of_string(name), ref, index, offset, size); +} + //Provides: caml_binaryen_array_copy__bytecode //Requires: caml_binaryen_array_copy function caml_binaryen_array_copy__bytecode() { diff --git a/src/expression.ml b/src/expression.ml index 86add2ee..33565785 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -924,6 +924,14 @@ module Array = struct external copy : Module.t -> t -> t -> t -> t -> t -> t = "caml_binaryen_array_copy__bytecode" "caml_binaryen_array_copy" (** Module, dest, dest index, src, src index, length *) + + external init_data : Module.t -> string -> t -> t -> t -> t -> t + = "caml_binaryen_array_init_data__bytecode" "caml_binaryen_array_init_data" + (** Module, name, ref, index, offset, size *) + + external init_elem : Module.t -> string -> t -> t -> t -> t -> t + = "caml_binaryen_array_init_elem__bytecode" "caml_binaryen_array_init_elem" + (** Module, seg, ref, index, offset, size *) end (** Bindings for `try_table` instruction. *) diff --git a/src/expression.mli b/src/expression.mli index 20e954ad..b02d73df 100644 --- a/src/expression.mli +++ b/src/expression.mli @@ -414,6 +414,12 @@ module Array : sig val copy : Module.t -> t -> t -> t -> t -> t -> t (** Module, dest, dest index, src, src index, length *) + + val init_data : Module.t -> string -> t -> t -> t -> t -> t + (** Module, name, ref, index, offset, size *) + + val init_elem : Module.t -> string -> t -> t -> t -> t -> t + (** Module, seg, ref, index, offset, size *) end (** Bindings for `try` instruction. *) From f72ada9fc317bc12715485e95018faaec9e54fba Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 13 Dec 2025 12:19:22 -0500 Subject: [PATCH 05/17] feat: Update `CallRef` bindings for `v126` --- src/expression.js | 19 +++++++++++++------ test/test.ml | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/expression.js b/src/expression.js index ab8bc535..729bccc9 100644 --- a/src/expression.js +++ b/src/expression.js @@ -105,12 +105,19 @@ function caml_binaryen_call_indirect__bytecode() { //Requires: caml_jsstring_of_string //Requires: caml_list_to_js_array, caml_js_from_bool function caml_binaryen_call_ref(wasm_mod, target, params, typ, is_return) { - return wasm_mod.call_ref( - target, - caml_list_to_js_array(params), - typ, - caml_js_from_bool(is_return) - ); + if (caml_js_from_bool(is_return)) { + return wasm_mod.return_call_ref( + target, + caml_list_to_js_array(params), + typ + ); + } else { + return wasm_mod.call_ref( + target, + caml_list_to_js_array(params), + typ + ); + } } //Provides: caml_binaryen_return_call diff --git a/test/test.ml b/test/test.ml index 48a79f7b..2d74985c 100644 --- a/test/test.ml +++ b/test/test.ml @@ -173,7 +173,7 @@ let _ = Table.add_table wasm_mod "table" 1 1 Type.funcref let adder_type = let builder = Type_builder.make 1 in - Type_builder.set_signature_type builder 0 Type.none Type.none; + Type_builder.set_signature_type builder 0 (params ()) results; match Type_builder.build_and_dispose builder with | Ok [ ty ] -> ty | _ -> failwith "failed to build type" From d182ae5c18e443f9f8ec32d51b4d1ecfdf53c921 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Fri, 23 Jan 2026 14:18:24 -0500 Subject: [PATCH 06/17] chore: Update tests after rebase --- test/test.expected | 316 +++++++++++++++++++++------------------------ 1 file changed, 145 insertions(+), 171 deletions(-) diff --git a/test/test.expected b/test/test.expected index 0e730bba..de38b05c 100644 --- a/test/test.expected +++ b/test/test.expected @@ -9,19 +9,14 @@ (module (type $0 (struct (field i31ref) (field (ref null $0)))) (type $1 (array (mut i8))) - (type $2 (func (param i32 i32) (result i32))) - (type $3 (func (result (ref $1) (ref $0)))) + (type $2 (func (param i32))) + (type $3 (func (param i32 i32) (result i32))) (type $4 (func)) - (type $5 (func (param anyref i32 i32) (result i32))) - (type $6 (func (param anyref) (result i32))) - (type $7 (func (param anyref) (result anyref anyref))) - (import "future-wasi" "write" (func $write (type $5) (param anyref i32 i32) (result i32))) - (type $0 (func (param i32))) - (type $1 (func (param i32 i32) (result i32))) - (type $2 (func)) - (type $3 (func (param anyref i32 i32) (result i32))) - (type $4 (func (param anyref) (result i32))) - (import "future-wasi" "write" (func $write (type $3) (param anyref i32 i32) (result i32))) + (type $5 (func (result (ref $1) (ref $0)))) + (type $6 (func (param anyref i32 i32) (result i32))) + (type $7 (func (param anyref) (result i32))) + (type $8 (func (param anyref) (result anyref anyref))) + (import "future-wasi" "write" (func $write (type $6) (param anyref i32 i32) (result i32))) (global $max_int64 i64 (i64.const 9223372036854775807)) (global $max_int64_mut (mut i64) (i64.const 9223372036854775807)) (global $test_float64_bits f64 (f64.const 1.23)) @@ -30,16 +25,15 @@ (data $world "world") (table $table 1 1 funcref) (elem $elem (i32.const 0) $adder) - (tag $foo (type $0) (param i32)) - (tag $bar (type $0) (param i32)) + (tag $foo (type $2) (param i32)) + (tag $bar (type $2) (param i32)) (export "adder" (func $adder)) (export "memory" (memory $0)) (export "hello" (func $hello)) - (export "gc" (func $gc)) (export "try" (func $try)) + (export "gc" (func $gc)) (start $start) - (func $adder (type $2) (param $0 i32) (param $1 i32) (result i32) - (func $adder (type $1) (param $0 i32) (param $1 i32) (result i32) + (func $adder (type $3) (param $0 i32) (param $1 i32) (result i32) (block $add (result i32) (if (i32.const 0) @@ -60,7 +54,6 @@ ) ) (func $start (type $4) - (func $start (type $2) (block $start (memory.init $world (i32.const 2048) @@ -68,8 +61,7 @@ (i32.const 5) ) (drop - (call_indirect $table (type $2) - (call_indirect $table (type $1) + (call_indirect $table (type $3) (i32.const 3) (i32.const 5) (i32.const 0) @@ -77,59 +69,14 @@ ) ) ) - (func $hello (type $6) (param $0 anyref) (result i32) - (func $hello (type $4) (param $0 anyref) (result i32) + (func $hello (type $7) (param $0 anyref) (result i32) (call $write (local.get $0) (i32.const 0) (i32.const 1) ) ) - (func $gc (type $7) (param $0 anyref) (result anyref anyref) - (local $1 (ref $1)) - (local $2 (ref $0)) - (block $gc_block (type $3) (result (ref $1) (ref $0)) - (local.set $1 - (array.new_fixed $1 2 - (i32.const 0) - (i32.const 255) - ) - ) - (array.set $1 - (local.get $1) - (i32.const 1) - (i32.const 42) - ) - (local.set $2 - (struct.new $0 - (ref.cast i31ref - (local.get $0) - ) - (struct.new $0 - (ref.i31 - (i32.const 1) - ) - (struct.new $0 - (ref.i31 - (i32.const 2) - ) - (struct.new $0 - (ref.i31 - (i32.const 3) - ) - (ref.null none) - ) - ) - ) - ) - ) - (tuple.make 2 - (local.get $1) - (local.get $2) - ) - ) - ) - (func $try (type $2) + (func $try (type $4) (block $blk (drop (try $tc1 (result i32) @@ -197,38 +144,76 @@ ) ) ) + (func $gc (type $8) (param $0 anyref) (result anyref anyref) + (local $1 (ref $1)) + (local $2 (ref $0)) + (block $gc_block (type $5) (result (ref $1) (ref $0)) + (local.set $1 + (array.new_fixed $1 2 + (i32.const 0) + (i32.const 255) + ) + ) + (array.set $1 + (local.get $1) + (i32.const 1) + (i32.const 42) + ) + (local.set $2 + (struct.new $0 + (ref.cast i31ref + (local.get $0) + ) + (struct.new $0 + (ref.i31 + (i32.const 1) + ) + (struct.new $0 + (ref.i31 + (i32.const 2) + ) + (struct.new $0 + (ref.i31 + (i32.const 3) + ) + (ref.null none) + ) + ) + ) + ) + ) + (tuple.make 2 + (local.get $1) + (local.get $2) + ) + ) + ) ) (module (type $0 (struct (field i31ref) (field (ref null $0)))) (type $1 (array (mut i8))) - (type $2 (func (result (ref (exact $1)) (ref (exact $0))))) - (type $3 (func (param i32 i32) (result i32))) - (type $4 (func)) - (type $5 (func (param anyref i32 i32) (result i32))) - (type $6 (func (param anyref) (result i32))) - (type $7 (func (param anyref) (result anyref anyref))) - (import "future-wasi" "write" (func $write (type $5) (param anyref i32 i32) (result i32))) - (type $0 (func (param i32))) - (type $1 (func)) - (type $2 (func (param i32 i32) (result i32))) - (type $3 (func (param anyref i32 i32) (result i32))) - (type $4 (func (param anyref) (result i32))) - (import "future-wasi" "write" (func $write (type $3) (param anyref i32 i32) (result i32))) + (type $2 (func (param i32))) + (type $3 (func)) + (type $4 (func (result (ref (exact $1)) (ref (exact $0))))) + (type $5 (func (param i32 i32) (result i32))) + (type $6 (func (param anyref i32 i32) (result i32))) + (type $7 (func (param anyref) (result i32))) + (type $8 (func (param anyref) (result anyref anyref))) + (import "future-wasi" "write" (func $write (type $6) (param anyref i32 i32) (result i32))) (memory $0 1) (data $hello (i32.const 0) "hello") (data $world "world") (table $table 1 1 funcref) (elem $elem (i32.const 0) $adder) - (tag $foo (type $0) (param i32)) - (tag $bar (type $0) (param i32)) + (tag $foo (type $2) (param i32)) + (tag $bar (type $2) (param i32)) (export "adder" (func $adder)) (export "memory" (memory $0)) (export "hello" (func $hello)) - (export "gc" (func $gc)) (export "try" (func $try)) + (export "gc" (func $gc)) (start $start) - (func $adder (type $3) (param $0 i32) (param $1 i32) (result i32) - (func $adder (type $2) (param $0 i32) (param $1 i32) (result i32) + (func $adder (type $5) (param $0 i32) (param $1 i32) (result i32) (i32.add (select (local.get $0) @@ -240,7 +225,7 @@ (local.get $1) ) ) - (func $start (type $4) + (func $start (type $3) (memory.init $world (i32.const 2048) (i32.const 0) @@ -253,52 +238,14 @@ ) ) ) - (func $hello (type $6) (param $0 anyref) (result i32) - (func $hello (type $4) (param $0 anyref) (result i32) + (func $hello (type $7) (param $0 anyref) (result i32) (call $write (local.get $0) (i32.const 0) (i32.const 1) ) ) - (func $gc (type $7) (param $0 anyref) (result anyref anyref) - (local $1 (ref (exact $1))) - (array.set $1 - (local.tee $1 - (array.new_fixed $1 2 - (i32.const 0) - (i32.const 255) - ) - ) - (i32.const 1) - (i32.const 42) - ) - (tuple.make 2 - (local.get $1) - (struct.new $0 - (ref.cast i31ref - (local.get $0) - ) - (struct.new $0 - (ref.i31 - (i32.const 1) - ) - (struct.new $0 - (ref.i31 - (i32.const 2) - ) - (struct.new $0 - (ref.i31 - (i32.const 3) - ) - (ref.null none) - ) - ) - ) - ) - ) - ) - (func $try (type $1) + (func $try (type $3) (drop (try (result i32) (do @@ -338,21 +285,53 @@ ) ) ) + (func $gc (type $8) (param $0 anyref) (result anyref anyref) + (local $1 (ref (exact $1))) + (array.set $1 + (local.tee $1 + (array.new_fixed $1 2 + (i32.const 0) + (i32.const 255) + ) + ) + (i32.const 1) + (i32.const 42) + ) + (tuple.make 2 + (local.get $1) + (struct.new $0 + (ref.cast i31ref + (local.get $0) + ) + (struct.new $0 + (ref.i31 + (i32.const 1) + ) + (struct.new $0 + (ref.i31 + (i32.const 2) + ) + (struct.new $0 + (ref.i31 + (i32.const 3) + ) + (ref.null none) + ) + ) + ) + ) + ) + ) ) (module - (type $type_6 (struct (field i31ref) (field (ref null $type_6)))) - (type $type_5 (array (mut i8))) - (type $type_7 (func (result anyref anyref))) - (type $type (func (param anyref i32 i32) (result i32))) - (type $type_1 (func (param i32 i32) (result i32))) - (type $type_2 (func)) - (type $type_3 (func (param anyref) (result i32))) - (type $type_4 (func (param anyref) (result anyref anyref))) - (import "future-wasi" "write" (func $fimport$0 (type $type) (param anyref i32 i32) (result i32))) + (type $type_7 (struct (field i31ref) (field (ref null $type_7)))) + (type $type_6 (array (mut i8))) (type $type_3 (func)) + (type $type_8 (func (result anyref anyref))) (type $type_1 (func (param anyref i32 i32) (result i32))) (type $type_2 (func (param i32 i32) (result i32))) (type $type_4 (func (param anyref) (result i32))) + (type $type_5 (func (param anyref) (result anyref anyref))) (import "future-wasi" "write" (func $fimport$0 (type $type_1) (param anyref i32 i32) (result i32))) (memory $0 1) (data $0 (i32.const 0) "hello") @@ -362,8 +341,8 @@ (export "adder" (func $0)) (export "memory" (memory $0)) (export "hello" (func $2)) - (export "gc" (func $3)) (export "try" (func $3)) + (export "gc" (func $4)) (start $1) (func $0 (type $type_2) (param $0 i32) (param $1 i32) (result i32) (i32.add @@ -397,11 +376,17 @@ (i32.const 1) ) ) - (func $3 (type $type_4) (param $0 anyref) (result anyref anyref) - (local $1 (ref (exact $type_5))) - (array.set $type_5 + (func $3 (type $type_3) + (drop + (unreachable) + ) + (unreachable) + ) + (func $4 (type $type_5) (param $0 anyref) (result anyref anyref) + (local $1 (ref (exact $type_6))) + (array.set $type_6 (local.tee $1 - (array.new_fixed $type_5 2 + (array.new_fixed $type_6 2 (i32.const 0) (i32.const 255) ) @@ -411,19 +396,19 @@ ) (tuple.make 2 (local.get $1) - (struct.new $type_6 + (struct.new $type_7 (ref.cast i31ref (local.get $0) ) - (struct.new $type_6 + (struct.new $type_7 (ref.i31 (i32.const 1) ) - (struct.new $type_6 + (struct.new $type_7 (ref.i31 (i32.const 2) ) - (struct.new $type_6 + (struct.new $type_7 (ref.i31 (i32.const 3) ) @@ -434,27 +419,16 @@ ) ) ) - (func $3 (type $type_3) - (drop - (unreachable) - ) - (unreachable) - ) ) (module - (type $type_6 (struct (field i31ref) (field (ref null $type_6)))) - (type $type_5 (array (mut i8))) - (type $type_7 (func (result anyref anyref))) - (type $type (func (param anyref i32 i32) (result i32))) - (type $type_1 (func (param i32 i32) (result i32))) - (type $type_2 (func)) - (type $type_3 (func (param anyref) (result i32))) - (type $type_4 (func (param anyref) (result anyref anyref))) - (import "future-wasi" "write" (func $fimport$0 (type $type) (param anyref i32 i32) (result i32))) + (type $type_7 (struct (field i31ref) (field (ref null $type_7)))) + (type $type_6 (array (mut i8))) (type $type_3 (func)) + (type $type_8 (func (result anyref anyref))) (type $type_1 (func (param anyref i32 i32) (result i32))) (type $type_2 (func (param i32 i32) (result i32))) (type $type_4 (func (param anyref) (result i32))) + (type $type_5 (func (param anyref) (result anyref anyref))) (import "future-wasi" "write" (func $fimport$0 (type $type_1) (param anyref i32 i32) (result i32))) (memory $0 1) (data $0 (i32.const 0) "hello") @@ -464,8 +438,8 @@ (export "adder" (func $0)) (export "memory" (memory $0)) (export "hello" (func $2)) - (export "gc" (func $3)) (export "try" (func $3)) + (export "gc" (func $4)) (start $1) (func $0 (type $type_2) (param $0 i32) (param $1 i32) (result i32) local.get $0 @@ -492,15 +466,18 @@ i32.const 1 call $fimport$0 ) - (func $3 (type $type_4) (param $0 anyref) (result anyref anyref) - (local $1 (ref (exact $type_5))) + (func $3 (type $type_3) + unreachable + ) + (func $4 (type $type_5) (param $0 anyref) (result anyref anyref) + (local $1 (ref (exact $type_6))) i32.const 0 i32.const 255 - array.new_fixed $type_5 2 + array.new_fixed $type_6 2 local.tee $1 i32.const 1 i32.const 42 - array.set $type_5 + array.set $type_6 local.get $1 local.get $0 ref.cast i31ref @@ -511,13 +488,10 @@ i32.const 3 ref.i31 ref.null none - struct.new $type_6 - struct.new $type_6 - struct.new $type_6 - struct.new $type_6 + struct.new $type_7 + struct.new $type_7 + struct.new $type_7 + struct.new $type_7 tuple.make 2 ) - (func $3 (type $type_3) - unreachable - ) ) From 144eb37b41e5e38f9ee6dc778d6689677b1d7b82 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 7 Mar 2026 17:29:16 -0500 Subject: [PATCH 07/17] feat: Switch to release `libbinaryen` v126 This pr also implements `Heap_type.set_type_name` and `Heap_type.set_field_name` --- src/expression.c | 23 ++++++++++++++---- src/expression.js | 33 +++++++++++++------------ src/expression.ml | 13 ++++++---- src/heap_type.c | 19 +++++++++++++++ src/heap_type.js | 12 ++++++++++ src/heap_type.ml | 9 +++++++ src/heap_type.mli | 7 ++++++ src/type.c | 2 +- src/type.js | 2 +- src/type_builder.c | 2 +- test/test.expected | 60 +++++++++++++++++++++++----------------------- test/test.ml | 30 +++++++++++++++++++++++ 12 files changed, 156 insertions(+), 56 deletions(-) diff --git a/src/expression.c b/src/expression.c index 92a3f4a6..7f0f25cf 100644 --- a/src/expression.c +++ b/src/expression.c @@ -125,8 +125,8 @@ caml_binaryen_call_indirect__bytecode(value * argv) { } CAMLprim value -caml_binaryen_call_ref(value _module, value _target, value _params, value _ty, value _is_return) { - CAMLparam5(_module, _target, _params, _ty, _is_return); +caml_binaryen_call_ref(value _module, value _target, value _params, value _ty) { + CAMLparam4(_module, _target, _params, _ty); BinaryenModuleRef module = BinaryenModuleRef_val(_module); BinaryenExpressionRef target = BinaryenExpressionRef_val(_target); _params = array_of_list(_params); @@ -136,8 +136,23 @@ caml_binaryen_call_ref(value _module, value _target, value _params, value _ty, v params[i] = BinaryenExpressionRef_val(Field(_params, i)); } BinaryenType ty = BinaryenType_val(_ty); - bool is_return = Bool_val(_is_return); - BinaryenExpressionRef exp = BinaryenCallRef(module, target, params, paramsLen, ty, is_return); + BinaryenExpressionRef exp = BinaryenCallRef(module, target, params, paramsLen, ty); + CAMLreturn(alloc_BinaryenExpressionRef(exp)); +} + +CAMLprim value +caml_binaryen_return_call_ref(value _module, value _target, value _params, value _ty) { + CAMLparam4(_module, _target, _params, _ty); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef target = BinaryenExpressionRef_val(_target); + _params = array_of_list(_params); + int paramsLen = array_length(_params); + BinaryenExpressionRef params[paramsLen]; + for (int i = 0; i < paramsLen; i++) { + params[i] = BinaryenExpressionRef_val(Field(_params, i)); + } + BinaryenType ty = BinaryenType_val(_ty); + BinaryenExpressionRef exp = BinaryenReturnCallRef(module, target, params, paramsLen, ty); CAMLreturn(alloc_BinaryenExpressionRef(exp)); } diff --git a/src/expression.js b/src/expression.js index 729bccc9..aa1ef15f 100644 --- a/src/expression.js +++ b/src/expression.js @@ -103,21 +103,24 @@ function caml_binaryen_call_indirect__bytecode() { //Provides: caml_binaryen_call_ref //Requires: caml_jsstring_of_string -//Requires: caml_list_to_js_array, caml_js_from_bool -function caml_binaryen_call_ref(wasm_mod, target, params, typ, is_return) { - if (caml_js_from_bool(is_return)) { - return wasm_mod.return_call_ref( - target, - caml_list_to_js_array(params), - typ - ); - } else { - return wasm_mod.call_ref( - target, - caml_list_to_js_array(params), - typ - ); - } +//Requires: caml_list_to_js_array +function caml_binaryen_call_ref(wasm_mod, target, params, typ) { + return wasm_mod.call_ref( + target, + caml_list_to_js_array(params), + typ + ); +} + +//Provides: caml_binaryen_return_call_ref +//Requires: caml_jsstring_of_string +//Requires: caml_list_to_js_array +function caml_binaryen_return_call_ref(wasm_mod, target, params, typ) { + return wasm_mod.return_call_ref( + target, + caml_list_to_js_array(params), + typ + ); } //Provides: caml_binaryen_return_call diff --git a/src/expression.ml b/src/expression.ml index 33565785..7c774b80 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -584,12 +584,17 @@ module Call_indirect = struct end module Call_ref = struct - external make : Module.t -> t -> t list -> Type.t -> bool -> t + external make : Module.t -> t -> t list -> Type.t -> t = "caml_binaryen_call_ref" - (** Module, function value, params, type, is return. *) - let make_return mod_ target params typ = make mod_ target params typ true - let make mod_ target params typ = make mod_ target params typ false + (** Module, function value, params, type. *) + let make mod_ target params typ = make mod_ target params typ + + external make_return : Module.t -> t -> t list -> Type.t -> t + = "caml_binaryen_return_call_ref" + + (** Module, function value, params, type. *) + let make_return mod_ target params typ = make mod_ target params typ external get_target : t -> t = "caml_binaryen_call_ref_get_target" external set_target : t -> t -> unit = "caml_binaryen_call_ref_set_target" diff --git a/src/heap_type.c b/src/heap_type.c index 711e4ff8..b4a78bc6 100644 --- a/src/heap_type.c +++ b/src/heap_type.c @@ -148,3 +148,22 @@ caml_binaryen_type_get_heap_type(value _ty) { BinaryenHeapType heapTy = BinaryenTypeGetHeapType(ty); CAMLreturn(alloc_BinaryenHeapType(heapTy)); } + +CAMLprim value caml_binaryen_module_set_type_name(value _module, value _heapType, value _name) { + CAMLparam3(_module, _heapType, _name); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType heapType = BinaryenHeapType_val(_heapType); + const char* name = String_val(_name); + BinaryenModuleSetTypeName(module, heapType, name); + CAMLreturn(Val_unit); +} + +CAMLprim value caml_binaryen_module_set_field_name(value _module, value _heapType, value _index, value _name) { + CAMLparam4(_module, _heapType, _index, _name); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenHeapType heapType = BinaryenHeapType_val(_heapType); + BinaryenIndex index = Int_val(_index); + const char* name = String_val(_name); + BinaryenModuleSetFieldName(module, heapType, index, name); + CAMLreturn(Val_unit); +} \ No newline at end of file diff --git a/src/heap_type.js b/src/heap_type.js index b14ac2c7..034d3215 100644 --- a/src/heap_type.js +++ b/src/heap_type.js @@ -111,3 +111,15 @@ function caml_binaryen_heap_type_is_sub_type(left, right) { function caml_binaryen_type_get_heap_type(typ) { return Binaryen._BinaryenTypeGetHeapType(typ); } + +//Provides: caml_binaryen_module_set_type_name +//Requires: caml_jsstring_of_string +function caml_binaryen_module_set_type_name(wasm_mod, heapType, name) { + wasm_mod.setTypeName(heapType, caml_jsstring_of_string(name)); +} + +//Provides: caml_binaryen_module_set_field_name +//Requires: caml_jsstring_of_string +function caml_binaryen_module_set_field_name(heapType, index, name) { + wasm_mod.setFieldName(heapType, index, caml_jsstring_of_string(name)); +} \ No newline at end of file diff --git a/src/heap_type.ml b/src/heap_type.ml index 44271e44..d90aa16b 100644 --- a/src/heap_type.ml +++ b/src/heap_type.ml @@ -18,3 +18,12 @@ external is_array : t -> bool = "caml_binaryen_heap_type_is_array" external is_bottom : t -> bool = "caml_binaryen_heap_type_is_bottom" external get_bottom : t -> t = "caml_binaryen_heap_type_get_bottom" external is_sub_type : t -> bool = "caml_binaryen_heap_type_is_sub_type" + +external set_type_name : Module.t -> t -> string -> unit + = "caml_binaryen_module_set_type_name" +(** Sets the textual name of a compound `heapType`. Has no effect if the type + already has a canonical name. *) + +external set_field_name : Module.t -> t -> int -> string -> unit + = "caml_binaryen_module_set_field_name" +(** Sets the field name of a struct `heapType` at index `index`. *) diff --git a/src/heap_type.mli b/src/heap_type.mli index ff28fa8f..a4ea1341 100644 --- a/src/heap_type.mli +++ b/src/heap_type.mli @@ -18,3 +18,10 @@ val is_array : t -> bool val is_bottom : t -> bool val get_bottom : t -> t val is_sub_type : t -> bool + +val set_type_name : Module.t -> t -> string -> unit +(** Sets the textual name of a compound `heapType`. Has no effect if the type + already has a canonical name. *) + +val set_field_name : Module.t -> t -> int -> string -> unit +(** Sets the field name of a struct `heapType` at index `index`. *) diff --git a/src/type.c b/src/type.c index 43855ec5..d5749a23 100644 --- a/src/type.c +++ b/src/type.c @@ -176,4 +176,4 @@ caml_binaryen_type_from_heap_type(value _ty, value _nullable) { bool nullable = Bool_val(_nullable); BinaryenType ty = BinaryenTypeFromHeapType(heapTy, nullable); CAMLreturn(alloc_BinaryenType(ty)); -} +} \ No newline at end of file diff --git a/src/type.js b/src/type.js index ffbbcab5..9100766b 100644 --- a/src/type.js +++ b/src/type.js @@ -130,4 +130,4 @@ function caml_binaryen_type_is_nullable(typ) { //Requires: Binaryen function caml_binaryen_type_from_heap_type(typ, nullable) { return Binaryen._BinaryenTypeFromHeapType(typ, nullable); -} +} \ No newline at end of file diff --git a/src/type_builder.c b/src/type_builder.c index c1680ba6..b9e5658f 100644 --- a/src/type_builder.c +++ b/src/type_builder.c @@ -173,4 +173,4 @@ caml_type_builder_build_and_dispose(value _builder) { Field(error, 0) = tuple; CAMLreturn(error); } -} +} \ No newline at end of file diff --git a/test/test.expected b/test/test.expected index de38b05c..642a51c0 100644 --- a/test/test.expected +++ b/test/test.expected @@ -7,16 +7,16 @@ (i32.const 0) ) (module - (type $0 (struct (field i31ref) (field (ref null $0)))) + (type $List (struct (field $head i31ref) (field $tail (ref null $List)))) (type $1 (array (mut i8))) (type $2 (func (param i32))) (type $3 (func (param i32 i32) (result i32))) (type $4 (func)) - (type $5 (func (result (ref $1) (ref $0)))) - (type $6 (func (param anyref i32 i32) (result i32))) - (type $7 (func (param anyref) (result i32))) - (type $8 (func (param anyref) (result anyref anyref))) - (import "future-wasi" "write" (func $write (type $6) (param anyref i32 i32) (result i32))) + (type $5 (func (param anyref i32 i32) (result i32))) + (type $6 (func (param anyref) (result i32))) + (type $7 (func (param anyref) (result anyref anyref))) + (type $8 (func (result (ref $1) (ref $List)))) + (import "future-wasi" "write" (func $write (type $5) (param anyref i32 i32) (result i32))) (global $max_int64 i64 (i64.const 9223372036854775807)) (global $max_int64_mut (mut i64) (i64.const 9223372036854775807)) (global $test_float64_bits f64 (f64.const 1.23)) @@ -69,7 +69,7 @@ ) ) ) - (func $hello (type $7) (param $0 anyref) (result i32) + (func $hello (type $6) (param $0 anyref) (result i32) (call $write (local.get $0) (i32.const 0) @@ -144,10 +144,10 @@ ) ) ) - (func $gc (type $8) (param $0 anyref) (result anyref anyref) + (func $gc (type $7) (param $0 anyref) (result anyref anyref) (local $1 (ref $1)) - (local $2 (ref $0)) - (block $gc_block (type $5) (result (ref $1) (ref $0)) + (local $2 (ref $List)) + (block $gc_block (type $8) (result (ref $1) (ref $List)) (local.set $1 (array.new_fixed $1 2 (i32.const 0) @@ -160,19 +160,19 @@ (i32.const 42) ) (local.set $2 - (struct.new $0 + (struct.new $List (ref.cast i31ref (local.get $0) ) - (struct.new $0 + (struct.new $List (ref.i31 (i32.const 1) ) - (struct.new $0 + (struct.new $List (ref.i31 (i32.const 2) ) - (struct.new $0 + (struct.new $List (ref.i31 (i32.const 3) ) @@ -190,16 +190,16 @@ ) ) (module - (type $0 (struct (field i31ref) (field (ref null $0)))) + (type $List (struct (field $head i31ref) (field $tail (ref null $List)))) (type $1 (array (mut i8))) (type $2 (func (param i32))) (type $3 (func)) - (type $4 (func (result (ref (exact $1)) (ref (exact $0))))) - (type $5 (func (param i32 i32) (result i32))) - (type $6 (func (param anyref i32 i32) (result i32))) - (type $7 (func (param anyref) (result i32))) - (type $8 (func (param anyref) (result anyref anyref))) - (import "future-wasi" "write" (func $write (type $6) (param anyref i32 i32) (result i32))) + (type $4 (func (param i32 i32) (result i32))) + (type $5 (func (param anyref i32 i32) (result i32))) + (type $6 (func (param anyref) (result i32))) + (type $7 (func (param anyref) (result anyref anyref))) + (type $8 (func (result (ref (exact $1)) (ref (exact $List))))) + (import "future-wasi" "write" (func $write (type $5) (param anyref i32 i32) (result i32))) (memory $0 1) (data $hello (i32.const 0) "hello") (data $world "world") @@ -213,7 +213,7 @@ (export "try" (func $try)) (export "gc" (func $gc)) (start $start) - (func $adder (type $5) (param $0 i32) (param $1 i32) (result i32) + (func $adder (type $4) (param $0 i32) (param $1 i32) (result i32) (i32.add (select (local.get $0) @@ -238,7 +238,7 @@ ) ) ) - (func $hello (type $7) (param $0 anyref) (result i32) + (func $hello (type $6) (param $0 anyref) (result i32) (call $write (local.get $0) (i32.const 0) @@ -285,7 +285,7 @@ ) ) ) - (func $gc (type $8) (param $0 anyref) (result anyref anyref) + (func $gc (type $7) (param $0 anyref) (result anyref anyref) (local $1 (ref (exact $1))) (array.set $1 (local.tee $1 @@ -299,19 +299,19 @@ ) (tuple.make 2 (local.get $1) - (struct.new $0 + (struct.new $List (ref.cast i31ref (local.get $0) ) - (struct.new $0 + (struct.new $List (ref.i31 (i32.const 1) ) - (struct.new $0 + (struct.new $List (ref.i31 (i32.const 2) ) - (struct.new $0 + (struct.new $List (ref.i31 (i32.const 3) ) @@ -327,11 +327,11 @@ (type $type_7 (struct (field i31ref) (field (ref null $type_7)))) (type $type_6 (array (mut i8))) (type $type_3 (func)) - (type $type_8 (func (result anyref anyref))) (type $type_1 (func (param anyref i32 i32) (result i32))) (type $type_2 (func (param i32 i32) (result i32))) (type $type_4 (func (param anyref) (result i32))) (type $type_5 (func (param anyref) (result anyref anyref))) + (type $type_8 (func (result anyref anyref))) (import "future-wasi" "write" (func $fimport$0 (type $type_1) (param anyref i32 i32) (result i32))) (memory $0 1) (data $0 (i32.const 0) "hello") @@ -424,11 +424,11 @@ (type $type_7 (struct (field i31ref) (field (ref null $type_7)))) (type $type_6 (array (mut i8))) (type $type_3 (func)) - (type $type_8 (func (result anyref anyref))) (type $type_1 (func (param anyref i32 i32) (result i32))) (type $type_2 (func (param i32 i32) (result i32))) (type $type_4 (func (param anyref) (result i32))) (type $type_5 (func (param anyref) (result anyref anyref))) + (type $type_8 (func (result anyref anyref))) (import "future-wasi" "write" (func $fimport$0 (type $type_1) (param anyref i32 i32) (result i32))) (memory $0 1) (data $0 (i32.const 0) "hello") diff --git a/test/test.ml b/test/test.ml index 2d74985c..cad22181 100644 --- a/test/test.ml +++ b/test/test.ml @@ -462,6 +462,36 @@ let _ = let _ = Export.add_function_export wasm_mod "gc" "gc" let _ = assert (Module.validate wasm_mod == 1) +(* Test Heap_type.set_type_name and Heap_type.set_field_name *) +let list_type = + let builder = Type_builder.make 1 in + let temp_heap_type = Type_builder.get_temp_heap_type builder 0 in + let temp_ref_type = + Type_builder.get_temp_ref_type builder temp_heap_type true + in + Type_builder.set_struct_type builder 0 + [ + Type_builder. + { + type_ = Type.i31ref; + packed_type = Packed_type.not_packed; + mutable_ = false; + }; + Type_builder. + { + type_ = temp_ref_type; + packed_type = Packed_type.not_packed; + mutable_ = false; + }; + ]; + match Type_builder.build_and_dispose builder with + | Ok [ ty ] -> ty + | _ -> failwith "failed to make list type" + +let _ = Heap_type.set_type_name wasm_mod list_type "List" +let _ = Heap_type.set_field_name wasm_mod list_type 0 "head" +let _ = Heap_type.set_field_name wasm_mod list_type 1 "tail" + (* Shouldn't actually do anything since we aren't doing function renames *) let _ = Module.update_maps wasm_mod From ede872545f951378d350abdeba3f98b75e3934e2 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Mon, 9 Mar 2026 17:45:17 -0400 Subject: [PATCH 08/17] fix: Correct `Array.fill` binding --- src/expression.ml | 5 ++--- src/expression.mli | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/expression.ml b/src/expression.ml index 7c774b80..11fe09e9 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -922,9 +922,8 @@ module Array = struct external len : Module.t -> t -> t = "caml_binaryen_array_len" (** Module, array *) - external fill : Module.t -> Heap_type.t -> t -> t -> t -> t - = "caml_binaryen_array_fill" - (** Module, type, seg, offset, size *) + external fill : Module.t -> t -> t -> t -> t -> t = "caml_binaryen_array_fill" + (** Module, array, index, value, offset *) external copy : Module.t -> t -> t -> t -> t -> t -> t = "caml_binaryen_array_copy__bytecode" "caml_binaryen_array_copy" diff --git a/src/expression.mli b/src/expression.mli index b02d73df..775cb27d 100644 --- a/src/expression.mli +++ b/src/expression.mli @@ -409,8 +409,8 @@ module Array : sig val len : Module.t -> t -> t (** Module, array *) - val fill : Module.t -> Heap_type.t -> t -> t -> t -> t - (** Module, type, seg, offset, size *) + val fill : Module.t -> t -> t -> t -> t -> t + (** Module, array, index, value, offset *) val copy : Module.t -> t -> t -> t -> t -> t -> t (** Module, dest, dest index, src, src index, length *) From 2edfa0d417d7b16bbf89d741d27a3cde7ab03b00 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 21:05:20 -0400 Subject: [PATCH 09/17] chore: Correct `Call_ref` binding of `make_return` --- src/expression.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expression.ml b/src/expression.ml index 11fe09e9..9780b83b 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -594,7 +594,7 @@ module Call_ref = struct = "caml_binaryen_return_call_ref" (** Module, function value, params, type. *) - let make_return mod_ target params typ = make mod_ target params typ + let make_return mod_ target params typ = make_return mod_ target params typ external get_target : t -> t = "caml_binaryen_call_ref_get_target" external set_target : t -> t -> unit = "caml_binaryen_call_ref_set_target" From c910f5c8bb44399c2a0e13873afb8b6b2243d164 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 21:08:07 -0400 Subject: [PATCH 10/17] fix: Correct `Type_builder.size` --- src/type_builder.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type_builder.ml b/src/type_builder.ml index 28f33b03..1a41f101 100644 --- a/src/type_builder.ml +++ b/src/type_builder.ml @@ -15,7 +15,7 @@ type error = external make : int -> t = "caml_type_builder_create" external grow : t -> int -> unit = "caml_type_builder_grow" -external size : t -> int = "caml_type_builder_grow" +external size : t -> int = "caml_type_builder_get_size" external set_signature_type : t -> int -> Type.t -> Type.t -> unit = "caml_type_builder_set_signature_type" From 4d5a4666414130bbd66530cd74941a2e263ca9b1 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 21:14:14 -0400 Subject: [PATCH 11/17] fix: Correct `Type_builder.get_temp_tuple_type` --- src/type_builder.c | 7 +++---- src/type_builder.js | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/type_builder.c b/src/type_builder.c index b9e5658f..2ff5bd33 100644 --- a/src/type_builder.c +++ b/src/type_builder.c @@ -95,8 +95,8 @@ caml_type_builder_get_temp_heap_type(value _builder, value _index) { } CAMLprim value -caml_type_builder_get_temp_tuple_type(value _builder, value _types, value _numTypes) { - CAMLparam3(_builder, _types, _numTypes); +caml_type_builder_get_temp_tuple_type(value _builder, value _types) { + CAMLparam2(_builder, _types); TypeBuilderRef builder = TypeBuilderRef_val(_builder); _types = array_of_list(_types); int typesLen = array_length(_types); @@ -104,8 +104,7 @@ caml_type_builder_get_temp_tuple_type(value _builder, value _types, value _numTy for (int i = 0; i < typesLen; i++) { types[i] = BinaryenType_val(Field(_types, i)); } - int numTypes = Int_val(_numTypes); - CAMLreturn(alloc_BinaryenType(TypeBuilderGetTempTupleType(builder, types, numTypes))); + CAMLreturn(alloc_BinaryenType(TypeBuilderGetTempTupleType(builder, types, typesLen))); } CAMLprim value diff --git a/src/type_builder.js b/src/type_builder.js index b8082e32..2e587d7f 100644 --- a/src/type_builder.js +++ b/src/type_builder.js @@ -78,7 +78,7 @@ function caml_type_builder_get_temp_heap_type(builder, index) { //Provides: caml_type_builder_get_temp_tuple_type //Requires: caml_list_to_js_array -function caml_type_builder_get_temp_tuple_type(builder, types, numTypes) { +function caml_type_builder_get_temp_tuple_type(builder, types) { var tupleTypes = caml_list_to_js_array(types); return builder.getTempTupleType(tupleTypes); } From 4b7e668a8cb4ad05b32f278dd73c6391cd411f91 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 21:25:02 -0400 Subject: [PATCH 12/17] fix: Correct `Heap_type.is_sub_type` --- src/heap_type.ml | 2 +- src/heap_type.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/heap_type.ml b/src/heap_type.ml index d90aa16b..36ca38af 100644 --- a/src/heap_type.ml +++ b/src/heap_type.ml @@ -17,7 +17,7 @@ external is_struct : t -> bool = "caml_binaryen_heap_type_is_struct" external is_array : t -> bool = "caml_binaryen_heap_type_is_array" external is_bottom : t -> bool = "caml_binaryen_heap_type_is_bottom" external get_bottom : t -> t = "caml_binaryen_heap_type_get_bottom" -external is_sub_type : t -> bool = "caml_binaryen_heap_type_is_sub_type" +external is_sub_type : t -> t -> bool = "caml_binaryen_heap_type_is_sub_type" external set_type_name : Module.t -> t -> string -> unit = "caml_binaryen_module_set_type_name" diff --git a/src/heap_type.mli b/src/heap_type.mli index a4ea1341..471d1aa9 100644 --- a/src/heap_type.mli +++ b/src/heap_type.mli @@ -17,7 +17,7 @@ val is_struct : t -> bool val is_array : t -> bool val is_bottom : t -> bool val get_bottom : t -> t -val is_sub_type : t -> bool +val is_sub_type : t -> t -> bool val set_type_name : Module.t -> t -> string -> unit (** Sets the textual name of a compound `heapType`. Has no effect if the type From 7df4ac4ad9e62fcc5b6d4fbe302b5c1375c93cf5 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 21:34:28 -0400 Subject: [PATCH 13/17] fix: Correct `Heap_type.set_field_name` js binding --- src/heap_type.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heap_type.js b/src/heap_type.js index 034d3215..acf0a30b 100644 --- a/src/heap_type.js +++ b/src/heap_type.js @@ -120,6 +120,6 @@ function caml_binaryen_module_set_type_name(wasm_mod, heapType, name) { //Provides: caml_binaryen_module_set_field_name //Requires: caml_jsstring_of_string -function caml_binaryen_module_set_field_name(heapType, index, name) { +function caml_binaryen_module_set_field_name(wasm_mod, heapType, index, name) { wasm_mod.setFieldName(heapType, index, caml_jsstring_of_string(name)); } \ No newline at end of file From f6a7f8352041ba26b4527267a1348c58ee18a341 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 21:45:05 -0400 Subject: [PATCH 14/17] fix: Correct `Array.init_data` and `Array.init_elem` js binds --- src/expression.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/expression.js b/src/expression.js index aa1ef15f..73420ab4 100644 --- a/src/expression.js +++ b/src/expression.js @@ -1909,13 +1909,26 @@ function caml_binaryen_array_copy( //Provides: caml_binaryen_array_init_data //Requires: caml_jsstring_of_string -function caml_binaryen_array_init_data(name, ref, index, offset, size) { +function caml_binaryen_array_init_data(wasm_mod, name, ref, index, offset, size) { return wasm_mod.array.init_data(caml_jsstring_of_string(name), ref, index, offset, size); } +//Provides: caml_binaryen_array_init_data__bytecode +//Requires: caml_binaryen_array_init_data +function caml_binaryen_array_init_data__bytecode() { + return caml_binaryen_array_init_data( + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4], + arguments[5] + ); +} + //Provides: caml_binaryen_array_init_elem //Requires: caml_jsstring_of_string -function caml_binaryen_array_init_elem(name, ref, index, offset, size) { +function caml_binaryen_array_init_elem(wasm_mod, name, ref, index, offset, size) { return wasm_mod.array.init_elem(caml_jsstring_of_string(name), ref, index, offset, size); } From 1270aa5416de3e1e7aab9b65cd74e84f2d5f3dc4 Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Sat, 28 Mar 2026 22:50:05 -0400 Subject: [PATCH 15/17] fix: Correct value usage in `type_builder_build_and_dispose` c binding --- src/type_builder.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/type_builder.c b/src/type_builder.c index 2ff5bd33..98efeb1b 100644 --- a/src/type_builder.c +++ b/src/type_builder.c @@ -150,23 +150,27 @@ caml_conv_heap_type(BinaryenHeapType heapType) { return alloc_BinaryenHeapType(heapType); } -CAMLprim value -caml_type_builder_build_and_dispose(value _builder) { +CAMLprim value caml_type_builder_build_and_dispose(value _builder) { CAMLparam1(_builder); + CAMLlocal4(arr, ok, error, tuple); TypeBuilderRef builder = TypeBuilderRef_val(_builder); BinaryenIndex size = TypeBuilderGetSize(builder); BinaryenHeapType heapTypes[size + 1]; - heapTypes[size] = (BinaryenHeapType) NULL; BinaryenIndex errorIndex; TypeBuilderErrorReason errorReason; - bool success = TypeBuilderBuildAndDispose(builder, heapTypes, &errorIndex, &errorReason); + bool success = + TypeBuilderBuildAndDispose(builder, heapTypes, &errorIndex, &errorReason); if (success) { - value ok = caml_alloc_small(1, 0); - Field(ok, 0) = caml_alloc_array((void*)caml_conv_heap_type, (char const **)heapTypes); + arr = caml_alloc(size, 0); + for (mlsize_t i = 0; i < (mlsize_t)size; i++) { + Field(arr, i) = alloc_BinaryenHeapType(heapTypes[i]); + } + ok = caml_alloc_small(1, 0); + Field(ok, 0) = arr; CAMLreturn(ok); } else { - value error = caml_alloc_small(1, 1); - value tuple = caml_alloc_small(2, 0); + error = caml_alloc_small(1, 1); + tuple = caml_alloc_small(2, 0); Field(tuple, 0) = Val_int(errorIndex); Field(tuple, 1) = Val_int(errorReason); Field(error, 0) = tuple; From 50a6e89a3fa986ba7c83a8f54174ff6c77e28f6f Mon Sep 17 00:00:00 2001 From: Oscar Spencer Date: Tue, 31 Mar 2026 20:47:23 -0400 Subject: [PATCH 16/17] use Store_field to set fields --- src/type.c | 6 ++++-- src/type_builder.c | 9 +++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/type.c b/src/type.c index d5749a23..e8303ca5 100644 --- a/src/type.c +++ b/src/type.c @@ -147,14 +147,16 @@ caml_binaryen_type_create(value tys) { CAMLprim value caml_binaryen_type_expand(value _ty) { CAMLparam1(_ty); + CAMLlocal2(typeArray, field); BinaryenType ty = BinaryenType_val(_ty); int arity = BinaryenTypeArity(ty); BinaryenType* buf = malloc(sizeof(BinaryenType) * arity); BinaryenTypeExpand(ty, buf); - value typeArray = caml_alloc(arity, 0); + typeArray = caml_alloc(arity, 0); for (int i = 0; i < arity; i++) { - Field(typeArray, i) = alloc_BinaryenType(buf[i]); + field = alloc_BinaryenType(buf[i]); + Store_field(typeArray, i, field); } free(buf); diff --git a/src/type_builder.c b/src/type_builder.c index 98efeb1b..886c9891 100644 --- a/src/type_builder.c +++ b/src/type_builder.c @@ -152,7 +152,7 @@ caml_conv_heap_type(BinaryenHeapType heapType) { CAMLprim value caml_type_builder_build_and_dispose(value _builder) { CAMLparam1(_builder); - CAMLlocal4(arr, ok, error, tuple); + CAMLlocal5(arr, ok, error, tuple, field); TypeBuilderRef builder = TypeBuilderRef_val(_builder); BinaryenIndex size = TypeBuilderGetSize(builder); BinaryenHeapType heapTypes[size + 1]; @@ -163,17 +163,18 @@ CAMLprim value caml_type_builder_build_and_dispose(value _builder) { if (success) { arr = caml_alloc(size, 0); for (mlsize_t i = 0; i < (mlsize_t)size; i++) { - Field(arr, i) = alloc_BinaryenHeapType(heapTypes[i]); + field = alloc_BinaryenHeapType(heapTypes[i]); + Store_field(arr, i, field); } ok = caml_alloc_small(1, 0); - Field(ok, 0) = arr; + Store_field(ok, 0, arr); CAMLreturn(ok); } else { error = caml_alloc_small(1, 1); tuple = caml_alloc_small(2, 0); Field(tuple, 0) = Val_int(errorIndex); Field(tuple, 1) = Val_int(errorReason); - Field(error, 0) = tuple; + Store_field(error, 0, tuple); CAMLreturn(error); } } \ No newline at end of file From 717ace448687e4c73c40555aa2d03852d0cd3ede Mon Sep 17 00:00:00 2001 From: Spotandjake Date: Wed, 1 Apr 2026 14:34:40 -0400 Subject: [PATCH 17/17] fix: Correct js binding for `ref.eq` --- src/expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expression.js b/src/expression.js index 73420ab4..586acebb 100644 --- a/src/expression.js +++ b/src/expression.js @@ -1814,7 +1814,7 @@ function caml_binaryen_ref_func(wasm_mod, name, typ) { //Provides: caml_binaryen_ref_eq function caml_binaryen_ref_eq(wasm_mod, left, right) { - return wasm_mod.ref.func(left, right); + return wasm_mod.ref.eq(left, right); } // Struct operations