Commit 63261c26 authored by Matthias Liedtke's avatar Matthias Liedtke Committed by V8 LUCI CQ

[wasm-gc] Disallow anyref in JS interop

Also fix eqref/i31ref fromJS() handling to accept unwrapped Smis.
This does not convert HeapNumbers to Smis if they fit.

Bug: v8:7748
Change-Id: Ida70a826f9541b7f3fbe9eecbb2b4fe362b5ef70
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3829477
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82558}
parent 4e10c14e
...@@ -6302,7 +6302,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6302,7 +6302,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::HeapType::kEq: case wasm::HeapType::kEq:
case wasm::HeapType::kData: case wasm::HeapType::kData:
case wasm::HeapType::kArray: case wasm::HeapType::kArray:
case wasm::HeapType::kI31:
// TODO(7748): Update this when JS interop is settled. // TODO(7748): Update this when JS interop is settled.
if (type.kind() == wasm::kRefNull) { if (type.kind() == wasm::kRefNull) {
auto done = auto done =
...@@ -6322,30 +6321,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6322,30 +6321,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return node; return node;
case wasm::HeapType::kExtern: case wasm::HeapType::kExtern:
return node; return node;
case wasm::HeapType::kAny: {
if (!enabled_features_.has_gc()) return node;
// Wrap {node} in object wrapper if it is an array/struct.
// Extract external function if this is a WasmInternalFunction.
// Otherwise (i.e. null and external refs), return input.
// Treat i31 as externref because they are indistinguishable from
// Smis.
// TODO(7748): Update this when JS interop is settled.
auto wrap = gasm_->MakeLabel();
auto done = gasm_->MakeLabel(MachineRepresentation::kTaggedPointer);
gasm_->GotoIf(IsSmi(node), &done, node);
gasm_->GotoIf(gasm_->IsDataRefMap(gasm_->LoadMap(node)), &wrap);
// This includes the case where {node == null}.
gasm_->Goto(&done, node);
gasm_->Bind(&wrap);
gasm_->Goto(&done, BuildAllocateObjectWrapper(node, context));
gasm_->Bind(&done);
return done.PhiAt(0);
}
case wasm::HeapType::kNone: case wasm::HeapType::kNone:
case wasm::HeapType::kNoFunc: case wasm::HeapType::kNoFunc:
case wasm::HeapType::kNoExtern: case wasm::HeapType::kNoExtern:
case wasm::HeapType::kI31:
case wasm::HeapType::kAny:
UNREACHABLE(); UNREACHABLE();
default: default:
DCHECK(type.has_index()); DCHECK(type.has_index());
...@@ -6468,10 +6448,14 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6468,10 +6448,14 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
target, input, context); target, input, context);
} }
enum class I31Check : bool { Invalid, Valid };
void BuildCheckValidRefValue(Node* input, Node* js_context, void BuildCheckValidRefValue(Node* input, Node* js_context,
wasm::ValueType type) { wasm::ValueType type, I31Check i31_check) {
// Make sure ValueType fits in a Smi. // Make sure ValueType fits in a Smi.
static_assert(wasm::ValueType::kLastUsedBit + 1 <= kSmiValueSize); static_assert(wasm::ValueType::kLastUsedBit + 1 <= kSmiValueSize);
auto done = gasm_->MakeLabel();
// The instance node is always defined: if an instance is not available, it // The instance node is always defined: if an instance is not available, it
// is the undefined value. // is the undefined value.
Node* inputs[] = {GetInstance(), input, Node* inputs[] = {GetInstance(), input,
...@@ -6481,16 +6465,15 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6481,16 +6465,15 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* check = gasm_->BuildChangeSmiToInt32(BuildCallToRuntimeWithContext( Node* check = gasm_->BuildChangeSmiToInt32(BuildCallToRuntimeWithContext(
Runtime::kWasmIsValidRefValue, js_context, inputs, 3)); Runtime::kWasmIsValidRefValue, js_context, inputs, 3));
Diamond type_check(graph(), mcgraph()->common(), check, BranchHint::kTrue); gasm_->GotoIf(check, &done, BranchHint::kTrue);
type_check.Chain(control()); if (i31_check == I31Check::Valid) {
SetControl(type_check.if_false); Node* is_smi = IsSmi(input);
gasm_->GotoIf(is_smi, &done, BranchHint::kTrue);
Node* old_effect = effect(); }
BuildCallToRuntimeWithContext(Runtime::kWasmThrowJSTypeError, js_context, BuildCallToRuntimeWithContext(Runtime::kWasmThrowJSTypeError, js_context,
nullptr, 0); nullptr, 0);
gasm_->Goto(&done);
SetEffectControl(type_check.EffectPhi(old_effect, effect()), gasm_->Bind(&done);
type_check.merge);
} }
Node* BuildCheckString(Node* input, Node* js_context, wasm::ValueType type) { Node* BuildCheckString(Node* input, Node* js_context, wasm::ValueType type) {
...@@ -6520,33 +6503,23 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6520,33 +6503,23 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
switch (type.heap_representation()) { switch (type.heap_representation()) {
case wasm::HeapType::kExtern: case wasm::HeapType::kExtern:
return input; return input;
case wasm::HeapType::kAny:
if (!enabled_features_.has_gc()) return input;
// If this is a wrapper for arrays/structs/i31s, unpack it.
// TODO(7748): Update this when JS interop has settled.
// We prefer not to unwrap functions here, because deciding whether
// that's valid for a given function is expensive (specifically,
// it's not valid for plain JS functions, because they don't have
// a WasmFunctionData/WasmInternalFunction inside). The consequence
// is that passing a funcref to JS and taking it back as {anyref}
// turns it into an opaque pointer that can't be cast back to
// {funcref}.
return BuildUnpackObjectWrapper(input, js_context,
kLeaveFunctionsAlone);
case wasm::HeapType::kFunc: case wasm::HeapType::kFunc:
BuildCheckValidRefValue(input, js_context, type); BuildCheckValidRefValue(input, js_context, type, I31Check::Invalid);
return BuildUnpackObjectWrapper(input, js_context, return BuildUnpackObjectWrapper(input, js_context,
kUnwrapWasmExternalFunctions); kUnwrapWasmExternalFunctions);
case wasm::HeapType::kData: case wasm::HeapType::kData:
case wasm::HeapType::kArray: case wasm::HeapType::kArray:
// TODO(7748): Update this when JS interop has settled.
BuildCheckValidRefValue(input, js_context, type, I31Check::Invalid);
// This will just return {input} if the object is not wrapped, i.e.
// if it is null (given the check just above).
return BuildUnpackObjectWrapper(input, js_context,
kLeaveFunctionsAlone);
case wasm::HeapType::kEq: case wasm::HeapType::kEq:
case wasm::HeapType::kI31:
// TODO(7748): Update this when JS interop has settled. // TODO(7748): Update this when JS interop has settled.
BuildCheckValidRefValue(input, js_context, type); BuildCheckValidRefValue(input, js_context, type, I31Check::Valid);
// This will just return {input} if the object is not wrapped, i.e. // This will just return {input} if the object is not wrapped, i.e.
// if it is null (given the check just above). // if it is null (given the check just above).
// Skip function unpacking here to save code size (they can't occur
// anyway).
return BuildUnpackObjectWrapper(input, js_context, return BuildUnpackObjectWrapper(input, js_context,
kLeaveFunctionsAlone); kLeaveFunctionsAlone);
case wasm::HeapType::kString: case wasm::HeapType::kString:
...@@ -6554,10 +6527,13 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6554,10 +6527,13 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::HeapType::kNone: case wasm::HeapType::kNone:
case wasm::HeapType::kNoFunc: case wasm::HeapType::kNoFunc:
case wasm::HeapType::kNoExtern: case wasm::HeapType::kNoExtern:
case wasm::HeapType::kAny:
case wasm::HeapType::kI31:
UNREACHABLE(); UNREACHABLE();
default: default:
if (module_->has_signature(type.ref_index())) { if (module_->has_signature(type.ref_index())) {
BuildCheckValidRefValue(input, js_context, type); BuildCheckValidRefValue(input, js_context, type,
I31Check::Invalid);
return BuildUnpackObjectWrapper(input, js_context, return BuildUnpackObjectWrapper(input, js_context,
kUnwrapWasmExternalFunctions); kUnwrapWasmExternalFunctions);
} }
......
...@@ -50,6 +50,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmModule* module, ...@@ -50,6 +50,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmModule* module,
case HeapType::kNone: case HeapType::kNone:
case HeapType::kNoFunc: case HeapType::kNoFunc:
case HeapType::kNoExtern: case HeapType::kNoExtern:
case HeapType::kAny:
case HeapType::kI31:
return false; return false;
default: default:
break; break;
......
...@@ -11,13 +11,13 @@ var instance = (function () { ...@@ -11,13 +11,13 @@ var instance = (function () {
let struct_index = builder.addStruct([makeField(kWasmI32, true)]); let struct_index = builder.addStruct([makeField(kWasmI32, true)]);
let callback = builder.addImport( let callback = builder.addImport(
'import', 'callback', {params: [kWasmAnyRef], results: []}); 'import', 'callback', {params: [kWasmExternRef], results: []});
builder.addFunction("object", { params: [], results: [kWasmEqRef] }) builder.addFunction("object", { params: [], results: [kWasmEqRef] })
.addBody([kGCPrefix, kExprStructNewDefault, struct_index]).exportFunc(); .addBody([kGCPrefix, kExprStructNewDefault, struct_index]).exportFunc();
builder.addFunction( builder.addFunction(
'roundtrip', {params: [kWasmEqRef, kWasmAnyRef], results: []}) 'roundtrip', {params: [kWasmEqRef, kWasmExternRef], results: []})
.addBody([ .addBody([
kExprLocalGet, 1, kExprLocalGet, 1,
kExprCallFunction, callback, kExprCallFunction, callback,
......
...@@ -10,7 +10,7 @@ var builder = new WasmModuleBuilder(); ...@@ -10,7 +10,7 @@ var builder = new WasmModuleBuilder();
let i16Array = builder.addArray(kWasmI16, true); let i16Array = builder.addArray(kWasmI16, true);
builder.addFunction('getHelloArray', makeSig([], [kWasmAnyRef])) builder.addFunction('getHelloArray', makeSig([], [kWasmArrayRef]))
.addBody([ .addBody([
...wasmI32Const(72), ...wasmI32Const(69), ...wasmI32Const(76), ...wasmI32Const(72), ...wasmI32Const(69), ...wasmI32Const(76),
...wasmI32Const(76), ...wasmI32Const(79), ...wasmI32Const(76), ...wasmI32Const(79),
...@@ -18,7 +18,7 @@ builder.addFunction('getHelloArray', makeSig([], [kWasmAnyRef])) ...@@ -18,7 +18,7 @@ builder.addFunction('getHelloArray', makeSig([], [kWasmAnyRef]))
]) ])
.exportFunc(); .exportFunc();
builder.addFunction('getChar', makeSig([kWasmAnyRef, kWasmI32], [kWasmI32])) builder.addFunction('getChar', makeSig([kWasmArrayRef, kWasmI32], [kWasmI32]))
.addBody([ .addBody([
kExprLocalGet, 0, kGCPrefix, kExprRefAsData, kGCPrefix, kExprLocalGet, 0, kGCPrefix, kExprRefAsData, kGCPrefix,
kExprRefCastStatic, i16Array, kExprLocalGet, 1, kGCPrefix, kExprArrayGetS, kExprRefCastStatic, i16Array, kExprLocalGet, 1, kGCPrefix, kExprArrayGetS,
......
...@@ -162,7 +162,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -162,7 +162,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kGCPrefix, kExprStructGet, composite_struct_index, 0]) kGCPrefix, kExprStructGet, composite_struct_index, 0])
.exportFunc(); .exportFunc();
builder.addFunction("field_2_default", makeSig([], [kWasmAnyRef])) builder.addFunction("field_2_default", makeSig([], [kWasmDataRef]))
.addBody([ .addBody([
kExprGlobalGet, global_default.index, kExprGlobalGet, global_default.index,
kGCPrefix, kExprStructGet, composite_struct_index, 1]) kGCPrefix, kExprStructGet, composite_struct_index, 1])
...@@ -245,7 +245,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -245,7 +245,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kGCPrefix, kExprStructGet, struct_index, 0]) kGCPrefix, kExprStructGet, struct_index, 0])
.exportFunc(); .exportFunc();
builder.addFunction("element1", makeSig([], [kWasmAnyRef])) builder.addFunction("element1", makeSig([], [kWasmDataRef]))
.addBody([ .addBody([
kExprGlobalGet, global.index, kExprGlobalGet, global.index,
kExprI32Const, 1, kExprI32Const, 1,
......
...@@ -20,7 +20,7 @@ let instance = (() => { ...@@ -20,7 +20,7 @@ let instance = (() => {
* type_internalize -> consume type by externref, internalize * type_internalize -> consume type by externref, internalize
*/ */
builder.addFunction('struct_producer', makeSig([kWasmI32], [kWasmAnyRef])) builder.addFunction('struct_producer', makeSig([kWasmI32], [kWasmEqRef]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kGCPrefix, kExprStructNew, struct]) kGCPrefix, kExprStructNew, struct])
...@@ -36,7 +36,7 @@ let instance = (() => { ...@@ -36,7 +36,7 @@ let instance = (() => {
.exportFunc(); .exportFunc();
builder.addFunction('struct_consumer', builder.addFunction('struct_consumer',
makeSig([kWasmAnyRef], [kWasmI32, kWasmI32])) makeSig([kWasmEqRef], [kWasmI32, kWasmI32]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kExprRefIsNull, kExprRefIsNull,
...@@ -76,7 +76,7 @@ let instance = (() => { ...@@ -76,7 +76,7 @@ let instance = (() => {
]) ])
.exportFunc(); .exportFunc();
builder.addFunction('i31_producer', makeSig([kWasmI32], [kWasmAnyRef])) builder.addFunction('i31_producer', makeSig([kWasmI32], [kWasmEqRef]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kGCPrefix, kExprI31New]) kGCPrefix, kExprI31New])
...@@ -92,7 +92,7 @@ let instance = (() => { ...@@ -92,7 +92,7 @@ let instance = (() => {
.exportFunc(); .exportFunc();
builder.addFunction('i31_consumer', builder.addFunction('i31_consumer',
makeSig([kWasmAnyRef], [kWasmI32, kWasmI32])) makeSig([kWasmEqRef], [kWasmI32, kWasmI32]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kExprRefIsNull, kExprRefIsNull,
...@@ -132,7 +132,7 @@ let instance = (() => { ...@@ -132,7 +132,7 @@ let instance = (() => {
let array = builder.addArray(kWasmI32, true); let array = builder.addArray(kWasmI32, true);
builder.addFunction('array_producer', makeSig([kWasmI32], [kWasmAnyRef])) builder.addFunction('array_producer', makeSig([kWasmI32], [kWasmEqRef]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kGCPrefix, kExprArrayNewFixedStatic, array, 1]) kGCPrefix, kExprArrayNewFixedStatic, array, 1])
...@@ -148,7 +148,7 @@ let instance = (() => { ...@@ -148,7 +148,7 @@ let instance = (() => {
.exportFunc(); .exportFunc();
builder.addFunction('array_consumer', builder.addFunction('array_consumer',
makeSig([kWasmAnyRef], [kWasmI32, kWasmI32])) makeSig([kWasmEqRef], [kWasmI32, kWasmI32]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kExprRefIsNull, kExprRefIsNull,
...@@ -198,9 +198,17 @@ for (let type of ["struct", "i31", "array"]) { ...@@ -198,9 +198,17 @@ for (let type of ["struct", "i31", "array"]) {
let fnConsume = instance.exports[`${type}_${consume}`]; let fnConsume = instance.exports[`${type}_${consume}`];
// A null is converted to (ref null none). // A null is converted to (ref null none).
assertEquals([0, 1], fnConsume(null)); assertEquals([0, 1], fnConsume(null));
// Passing a JavaScript object is allowed and can be internalized if (consume == "internalize") {
// but will fail on casting it. // Passing a JavaScript object is fine on internalize but fails on
assertTraps(kTrapIllegalCast, () => fnConsume({})); // casting it to dataref/arrayref/i31ref.
var errorType = WebAssembly.RuntimeError;
var errorMsg = "illegal cast";
} else {
// Passing a JavaScript object fails as it is not convertible to eqref.
var errorType = TypeError;
var errorMsg = "type incompatibility when transforming from/to JS";
}
assertThrows(() => fnConsume({}), errorType, errorMsg);
for (let produce of ["producer", "externalize"]) { for (let produce of ["producer", "externalize"]) {
let fnProduce = instance.exports[`${type}_${produce}`]; let fnProduce = instance.exports[`${type}_${produce}`];
......
...@@ -10,7 +10,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); ...@@ -10,7 +10,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
let instance = (() => { let instance = (() => {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
let struct = builder.addStruct([makeField(kWasmI32, true)]); let struct = builder.addStruct([makeField(kWasmI32, true)]);
builder.addFunction('createStruct', makeSig([kWasmI32], [kWasmAnyRef])) builder.addFunction('createStruct', makeSig([kWasmI32], [kWasmEqRef]))
.addBody([ .addBody([
kExprLocalGet, 0, kExprLocalGet, 0,
kGCPrefix, kExprStructNew, struct]) kGCPrefix, kExprStructNew, struct])
......
...@@ -27,7 +27,7 @@ let instance = (() => { ...@@ -27,7 +27,7 @@ let instance = (() => {
]) ])
.exportFunc(); .exportFunc();
builder.addFunction('i31_producer', makeSig([], [kWasmI31Ref])) builder.addFunction('i31_as_eq_producer', makeSig([], [kWasmEqRef]))
.addBody([kExprI32Const, 5, kGCPrefix, kExprI31New]) .addBody([kExprI32Const, 5, kGCPrefix, kExprI31New])
.exportFunc(); .exportFunc();
...@@ -36,7 +36,6 @@ let instance = (() => { ...@@ -36,7 +36,6 @@ let instance = (() => {
.exportFunc(); .exportFunc();
let test_types = { let test_types = {
i31: kWasmI31Ref,
struct: kWasmDataRef, struct: kWasmDataRef,
array: kWasmDataRef, array: kWasmDataRef,
raw_struct: struct, raw_struct: struct,
...@@ -68,26 +67,16 @@ let instance = (() => { ...@@ -68,26 +67,16 @@ let instance = (() => {
// Wasm-exposed null is the same as JS null. // Wasm-exposed null is the same as JS null.
assertEquals(instance.exports.struct_null(), null); assertEquals(instance.exports.struct_null(), null);
// We can roundtrip an i31.
instance.exports.i31_id(instance.exports.i31_producer());
// We can roundtrip any null as i31.
instance.exports.i31_id(instance.exports.i31_null());
instance.exports.i31_id(instance.exports.struct_null());
// We cannot roundtrip a struct as i31.
assertThrows(
() => instance.exports.i31_id(instance.exports.struct_producer()),
TypeError, 'type incompatibility when transforming from/to JS');
// We can roundtrip a struct as dataref. // We can roundtrip a struct as dataref.
instance.exports.data_id(instance.exports.struct_producer()); instance.exports.data_id(instance.exports.struct_producer());
// We can roundtrip an array as dataref. // We can roundtrip an array as dataref.
instance.exports.data_id(instance.exports.array_producer()); instance.exports.data_id(instance.exports.array_producer());
// We can roundtrip any null as dataref. // We can roundtrip null as dataref.
instance.exports.data_id(instance.exports.data_null()); instance.exports.data_id(instance.exports.data_null());
instance.exports.data_id(instance.exports.i31_null());
// We cannot roundtrip an i31 as dataref. // We cannot roundtrip an i31 as dataref.
assertThrows( assertThrows(
() => instance.exports.data_id(instance.exports.i31_producer()), TypeError, () => instance.exports.data_id(instance.exports.i31_as_eq_producer()),
TypeError,
'type incompatibility when transforming from/to JS'); 'type incompatibility when transforming from/to JS');
// We can roundtrip a struct as eqref. // We can roundtrip a struct as eqref.
...@@ -95,35 +84,27 @@ instance.exports.eq_id(instance.exports.struct_producer()); ...@@ -95,35 +84,27 @@ instance.exports.eq_id(instance.exports.struct_producer());
// We can roundtrip an array as eqref. // We can roundtrip an array as eqref.
instance.exports.eq_id(instance.exports.array_producer()); instance.exports.eq_id(instance.exports.array_producer());
// We can roundtrip an i31 as eqref. // We can roundtrip an i31 as eqref.
instance.exports.eq_id(instance.exports.i31_producer()); instance.exports.eq_id(instance.exports.i31_as_eq_producer());
// We can roundtrip any null as eqref. // We can roundtrip any null as eqref.
instance.exports.eq_id(instance.exports.data_null()); instance.exports.eq_id(instance.exports.data_null());
instance.exports.eq_id(instance.exports.i31_null()); instance.exports.eq_id(instance.exports.eq_null());
instance.exports.eq_id(instance.exports.func_null()); instance.exports.eq_id(instance.exports.func_null());
// We cannot roundtrip a func as eqref. // We cannot roundtrip a func as eqref.
assertThrows( assertThrows(
() => instance.exports.eq_id(instance.exports.func_producer()), TypeError, () => instance.exports.eq_id(instance.exports.func_producer()), TypeError,
'type incompatibility when transforming from/to JS'); 'type incompatibility when transforming from/to JS');
// We can roundtrip a struct as anyref. // Anyref is not allowed at the JS interface.
instance.exports.any_id(instance.exports.struct_producer()); assertThrows(
// We can roundtrip an array as anyref. () => instance.exports.any_null(), TypeError,
instance.exports.any_id(instance.exports.array_producer()); 'type incompatibility when transforming from/to JS');
// We can roundtrip an i31 as anyref. assertThrows(
instance.exports.any_id(instance.exports.i31_producer()); () => instance.exports.any_id(), TypeError,
// We can roundtrip a func as anyref. 'type incompatibility when transforming from/to JS');
instance.exports.any_id(instance.exports.func_producer());
// We can roundtrip any null as anyref.
instance.exports.any_id(instance.exports.data_null());
instance.exports.any_id(instance.exports.i31_null());
instance.exports.any_id(instance.exports.func_null());
// We can roundtrip a JS object as anyref.
instance.exports.any_id(instance);
// We can roundtrip a typed function. // We can roundtrip a typed function.
instance.exports.typed_func_id(instance.exports.func_producer()); instance.exports.typed_func_id(instance.exports.func_producer());
// We can roundtrip any null as typed funcion. // We can roundtrip any null as typed funcion.
instance.exports.typed_func_id(instance.exports.i31_null());
instance.exports.typed_func_id(instance.exports.struct_null()); instance.exports.typed_func_id(instance.exports.struct_null());
// We cannot roundtrip a struct as typed funcion. // We cannot roundtrip a struct as typed funcion.
assertThrows( assertThrows(
...@@ -133,11 +114,11 @@ assertThrows( ...@@ -133,11 +114,11 @@ assertThrows(
// We can roundtrip a func. // We can roundtrip a func.
instance.exports.func_id(instance.exports.func_producer()); instance.exports.func_id(instance.exports.func_producer());
// We can roundtrip any null as func. // We can roundtrip any null as func.
instance.exports.func_id(instance.exports.i31_null());
instance.exports.func_id(instance.exports.struct_null()); instance.exports.func_id(instance.exports.struct_null());
// We cannot roundtrip an i31 as func. // We cannot roundtrip an i31 as func.
assertThrows( assertThrows(
() => instance.exports.func_id(instance.exports.i31_producer()), TypeError, () => instance.exports.func_id(instance.exports.i31_as_eq_producer()),
TypeError,
'type incompatibility when transforming from/to JS'); 'type incompatibility when transforming from/to JS');
// We cannot directly roundtrip structs or arrays. // We cannot directly roundtrip structs or arrays.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment