Skip to content

Commit a19c01c

Browse files
zherczegksh8281
authored andcommitted
Implement EqRef support
Signed-off-by: Zoltan Herczeg [email protected]
1 parent e36dca2 commit a19c01c

File tree

6 files changed

+718
-17
lines changed

6 files changed

+718
-17
lines changed

src/interpreter/Interpreter.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,23 +2213,25 @@ NEVER_INLINE bool Interpreter::testRefGeneric(void* refPtr, Value::Type type)
22132213
return type == Value::AnyRef;
22142214
}
22152215

2216-
ASSERT(type == Value::I31Ref || type == Value::StructRef || type == Value::ArrayRef);
2216+
ASSERT(type == Value::I31Ref || type == Value::StructRef
2217+
|| type == Value::ArrayRef || type == Value::EqRef);
22172218

22182219
if (Value::isI31Value(refPtr)) {
2219-
return type == Value::I31Ref;
2220-
}
2221-
2222-
if (type == Value::I31Ref) {
2223-
return false;
2220+
return type == Value::I31Ref || type == Value::EqRef;
22242221
}
22252222

22262223
Object::Kind kind = reinterpret_cast<Object*>(refPtr)->kind();
22272224

2228-
if (type == Value::StructRef) {
2225+
switch (type) {
2226+
case Value::I31Ref:
2227+
return false;
2228+
case Value::StructRef:
22292229
return kind == Object::StructKind;
2230+
case Value::ArrayRef:
2231+
return kind == Object::ArrayKind;
2232+
default:
2233+
return kind == Object::StructKind || kind == Object::ArrayKind;
22302234
}
2231-
2232-
return kind == Object::ArrayKind;
22332235
}
22342236

22352237
NEVER_INLINE bool Interpreter::testRefDefined(void* refPtr, const CompositeType** typeInfo)

src/jit/GarbageCollectorInl.h

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,89 @@ static void emitGCCastGeneric(sljit_compiler* compiler, Instruction* instr)
221221
if ((srcInfo & (JumpIfCastGeneric::IsSrcNullable | JumpIfCastGeneric::IsSrcTagged)) == 0) {
222222
sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_TMP_DEST_REG, 0, SLJIT_MEM1(srcReg), JITFieldAccessor::objectTypeInfo());
223223
if (label != nullptr) {
224-
label->jumpFrom(sljit_emit_cmp(compiler, isTestOrCastFail ? SLJIT_NOT_EQUAL : SLJIT_EQUAL, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind));
224+
sljit_s32 type = (genericType == Value::EqRef) ? SLJIT_LESS_EQUAL : SLJIT_EQUAL;
225+
if (isTestOrCastFail) {
226+
type ^= 0x1;
227+
}
228+
label->jumpFrom(sljit_emit_cmp(compiler, type, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind));
225229
} else if (!isTestOrCastFail) {
226-
context->appendTrapJump(ExecutionContext::CastFailureError, sljit_emit_cmp(compiler, SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind));
230+
sljit_s32 type = (genericType == Value::EqRef) ? SLJIT_GREATER : SLJIT_NOT_EQUAL;
231+
context->appendTrapJump(ExecutionContext::CastFailureError, sljit_emit_cmp(compiler, type, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind));
227232
} else {
228-
sljit_emit_op2u(compiler, SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind);
229-
sljit_emit_op_flags(compiler, SLJIT_MOV, args[1].arg, args[1].argw, SLJIT_EQUAL);
233+
sljit_s32 type = (genericType == Value::EqRef) ? SLJIT_SET_LESS_EQUAL : SLJIT_SET_Z;
234+
sljit_emit_op2u(compiler, SLJIT_SUB | type, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind);
235+
type = (genericType == Value::EqRef) ? SLJIT_LESS_EQUAL : SLJIT_EQUAL;
236+
sljit_emit_op_flags(compiler, SLJIT_MOV, args[1].arg, args[1].argw, type);
237+
}
238+
return;
239+
}
240+
241+
if (genericType == Value::EqRef) {
242+
if ((srcInfo & JumpIfCastGeneric::IsSrcTagged) != 0) {
243+
sljit_emit_op2(compiler, SLJIT_ROTR, SLJIT_TMP_DEST_REG, 0, srcReg, 0, SLJIT_IMM, 1);
244+
sljit_jump* jump = sljit_emit_cmp(compiler, SLJIT_SIG_LESS_EQUAL, SLJIT_TMP_DEST_REG, 0, SLJIT_IMM, 0);
245+
sljit_emit_op2(compiler, SLJIT_SHL, SLJIT_TMP_DEST_REG, 0, SLJIT_TMP_DEST_REG, 0, SLJIT_IMM, 1);
246+
247+
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_TMP_DEST_REG, 0, SLJIT_MEM1(SLJIT_TMP_DEST_REG), JITFieldAccessor::objectTypeInfo());
248+
sljit_emit_op2(compiler, SLJIT_SUB, SLJIT_TMP_DEST_REG, 0, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind + 1);
249+
sljit_set_label(jump, sljit_emit_label(compiler));
250+
251+
if (label != nullptr) {
252+
sljit_s32 type = ((srcInfo & JumpIfCastGeneric::IsNullable) == 0) ? SLJIT_SIG_LESS : SLJIT_SIG_LESS_EQUAL;
253+
if (isTestOrCastFail) {
254+
type ^= 0x1;
255+
}
256+
label->jumpFrom(sljit_emit_cmp(compiler, type, SLJIT_TMP_DEST_REG, 0, SLJIT_IMM, 0));
257+
} else if (!isTestOrCastFail) {
258+
sljit_s32 type = ((srcInfo & JumpIfCastGeneric::IsNullable) == 0) ? SLJIT_SIG_GREATER_EQUAL : SLJIT_SIG_GREATER;
259+
context->appendTrapJump(ExecutionContext::CastFailureError, sljit_emit_cmp(compiler, type, SLJIT_TMP_DEST_REG, 0, SLJIT_IMM, 0));
260+
} else {
261+
sljit_s32 type = ((srcInfo & JumpIfCastGeneric::IsNullable) == 0) ? SLJIT_SET_SIG_LESS : SLJIT_SET_SIG_LESS_EQUAL;
262+
sljit_emit_op2u(compiler, SLJIT_SUB | type, SLJIT_TMP_DEST_REG, 0, SLJIT_IMM, 0);
263+
type = ((srcInfo & JumpIfCastGeneric::IsNullable) == 0) ? SLJIT_SIG_LESS : SLJIT_SIG_LESS_EQUAL;
264+
sljit_emit_op_flags(compiler, SLJIT_MOV, args[1].arg, args[1].argw, type);
265+
}
266+
return;
267+
}
268+
269+
if (srcReg != SLJIT_TMP_DEST_REG && label == nullptr && isTestOrCastFail) {
270+
sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_TMP_DEST_REG, 0, srcReg, 0);
271+
srcReg = SLJIT_TMP_DEST_REG;
272+
}
273+
274+
sljit_jump* jump = sljit_emit_cmp(compiler, SLJIT_EQUAL, srcReg, 0, SLJIT_IMM, 0);
275+
sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_TMP_DEST_REG, 0, SLJIT_MEM1(srcReg), JITFieldAccessor::objectTypeInfo());
276+
277+
if (label != nullptr) {
278+
label->jumpFrom(sljit_emit_cmp(compiler, isTestOrCastFail ? SLJIT_GREATER : SLJIT_LESS_EQUAL, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind));
279+
if ((srcInfo & JumpIfCastGeneric::IsNullable) != 0) {
280+
isTestOrCastFail = !isTestOrCastFail;
281+
}
282+
283+
if (isTestOrCastFail) {
284+
label->jumpFrom(jump);
285+
} else {
286+
sljit_set_label(jump, sljit_emit_label(compiler));
287+
}
288+
} else if (!isTestOrCastFail) {
289+
context->appendTrapJump(ExecutionContext::CastFailureError, sljit_emit_cmp(compiler, SLJIT_GREATER, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind));
290+
if ((srcInfo & JumpIfCastGeneric::IsNullable) != 0) {
291+
sljit_set_label(jump, sljit_emit_label(compiler));
292+
} else {
293+
context->appendTrapJump(ExecutionContext::CastFailureError, jump);
294+
}
295+
} else {
296+
ASSERT(srcReg == SLJIT_TMP_DEST_REG);
297+
kind++;
298+
if ((srcInfo & JumpIfCastGeneric::IsNullable) != 0) {
299+
sljit_emit_op1(compiler, SLJIT_MOV_P, SLJIT_TMP_DEST_REG, 0, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)));
300+
} else {
301+
sljit_emit_op2(compiler, SLJIT_SUB, SLJIT_TMP_DEST_REG, 0, SLJIT_MEM1(SLJIT_TMP_DEST_REG), -static_cast<sljit_sw>(sizeof(sljit_up)), SLJIT_IMM, kind);
302+
kind = 0;
303+
}
304+
sljit_set_label(jump, sljit_emit_label(compiler));
305+
sljit_emit_op2u(compiler, SLJIT_SUB | SLJIT_SET_SIG_LESS, SLJIT_TMP_DEST_REG, 0, SLJIT_IMM, kind);
306+
sljit_emit_op_flags(compiler, SLJIT_MOV, args[1].arg, args[1].argw, SLJIT_SIG_LESS);
230307
}
231308
return;
232309
}

src/parser/WASMParser.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,6 +2594,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate {
25942594
case Walrus::Value::I31Ref:
25952595
case Walrus::Value::StructRef:
25962596
case Walrus::Value::ArrayRef:
2597+
case Walrus::Value::EqRef:
25972598
break;
25982599
case Walrus::Value::NoAnyRef:
25992600
case Walrus::Value::NoExternRef:
@@ -2693,8 +2694,17 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate {
26932694
virtual void OnGCUnaryExpr(int opcode) override
26942695
{
26952696
switch (opcode) {
2696-
case Opcode::RefEq:
2697+
case Opcode::RefEq: {
2698+
auto src1 = popVMStack();
2699+
auto src0 = popVMStack();
2700+
auto dst = computeExprResultPosition(Walrus::Value::Type::I32);
2701+
if (sizeof(void*) == 4) {
2702+
pushByteCode(Walrus::I32Eq(src0, src1, dst), WASMOpcode::RefEqOpcode);
2703+
} else {
2704+
pushByteCode(Walrus::I64Eq(src0, src1, dst), WASMOpcode::RefEqOpcode);
2705+
}
26972706
break;
2707+
}
26982708
case Opcode::ArrayLen: {
26992709
bool isNullable = Walrus::Value::isNullableRefType(peekVMStackInfo().valueType());
27002710
auto src = popVMStack();
@@ -2703,9 +2713,13 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate {
27032713
break;
27042714
}
27052715
case Opcode::AnyConvertExtern:
2716+
case Opcode::ExternConvertAny: {
2717+
Walrus::Value::Type type = (opcode == Opcode::AnyConvertExtern) ? Walrus::Value::Type::AnyRef : Walrus::Value::Type::ExternRef;
2718+
auto src = popVMStack();
2719+
auto dst = computeExprResultPosition(type);
2720+
generateMoveCodeIfNeeds(src, dst, type);
27062721
break;
2707-
case Opcode::ExternConvertAny:
2708-
break;
2722+
}
27092723
case Opcode::RefI31: {
27102724
auto src = popVMStack();
27112725
auto dst = computeExprResultPosition(Walrus::Value::Type::I31Ref);
@@ -3008,7 +3022,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate {
30083022
}
30093023
if (m_shouldContinueToGenerateByteCode) {
30103024
for (size_t i = 0; i < m_currentFunctionType->result().size() && m_vmStack.size(); i++) {
3011-
ASSERT(popVMStackInfo().valueType() == m_currentFunctionType->result()[m_currentFunctionType->result().size() - i - 1]);
3025+
ASSERT(toDebugType(popVMStackInfo().valueType()) == toDebugType(m_currentFunctionType->result()[m_currentFunctionType->result().size() - i - 1]));
30123026
}
30133027
ASSERT(m_vmStack.empty());
30143028
}

test/extended/gc/ref_eq.wast

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
(module
2+
(type $st (sub (struct)))
3+
(type $st' (sub (struct (field i32))))
4+
(type $at (array i8))
5+
(type $st-sub1 (sub $st (struct)))
6+
(type $st-sub2 (sub $st (struct)))
7+
(type $st'-sub1 (sub $st' (struct (field i32))))
8+
(type $st'-sub2 (sub $st' (struct (field i32))))
9+
10+
(table 20 (ref null eq))
11+
12+
(func (export "init")
13+
(table.set (i32.const 0) (ref.null eq))
14+
(table.set (i32.const 1) (ref.null i31))
15+
(table.set (i32.const 2) (ref.i31 (i32.const 7)))
16+
(table.set (i32.const 3) (ref.i31 (i32.const 7)))
17+
(table.set (i32.const 4) (ref.i31 (i32.const 8)))
18+
(table.set (i32.const 5) (struct.new_default $st))
19+
(table.set (i32.const 6) (struct.new_default $st))
20+
(table.set (i32.const 7) (array.new_default $at (i32.const 0)))
21+
(table.set (i32.const 8) (array.new_default $at (i32.const 0)))
22+
)
23+
24+
(func (export "eq") (param $i i32) (param $j i32) (result i32)
25+
(ref.eq (table.get (local.get $i)) (table.get (local.get $j)))
26+
)
27+
)
28+
29+
(invoke "init")
30+
31+
(assert_return (invoke "eq" (i32.const 0) (i32.const 0)) (i32.const 1))
32+
(assert_return (invoke "eq" (i32.const 0) (i32.const 1)) (i32.const 1))
33+
(assert_return (invoke "eq" (i32.const 0) (i32.const 2)) (i32.const 0))
34+
(assert_return (invoke "eq" (i32.const 0) (i32.const 3)) (i32.const 0))
35+
(assert_return (invoke "eq" (i32.const 0) (i32.const 4)) (i32.const 0))
36+
(assert_return (invoke "eq" (i32.const 0) (i32.const 5)) (i32.const 0))
37+
(assert_return (invoke "eq" (i32.const 0) (i32.const 6)) (i32.const 0))
38+
(assert_return (invoke "eq" (i32.const 0) (i32.const 7)) (i32.const 0))
39+
(assert_return (invoke "eq" (i32.const 0) (i32.const 8)) (i32.const 0))
40+
41+
(assert_return (invoke "eq" (i32.const 1) (i32.const 0)) (i32.const 1))
42+
(assert_return (invoke "eq" (i32.const 1) (i32.const 1)) (i32.const 1))
43+
(assert_return (invoke "eq" (i32.const 1) (i32.const 2)) (i32.const 0))
44+
(assert_return (invoke "eq" (i32.const 1) (i32.const 3)) (i32.const 0))
45+
(assert_return (invoke "eq" (i32.const 1) (i32.const 4)) (i32.const 0))
46+
(assert_return (invoke "eq" (i32.const 1) (i32.const 5)) (i32.const 0))
47+
(assert_return (invoke "eq" (i32.const 1) (i32.const 6)) (i32.const 0))
48+
(assert_return (invoke "eq" (i32.const 1) (i32.const 7)) (i32.const 0))
49+
(assert_return (invoke "eq" (i32.const 1) (i32.const 8)) (i32.const 0))
50+
51+
(assert_return (invoke "eq" (i32.const 2) (i32.const 0)) (i32.const 0))
52+
(assert_return (invoke "eq" (i32.const 2) (i32.const 1)) (i32.const 0))
53+
(assert_return (invoke "eq" (i32.const 2) (i32.const 2)) (i32.const 1))
54+
(assert_return (invoke "eq" (i32.const 2) (i32.const 3)) (i32.const 1))
55+
(assert_return (invoke "eq" (i32.const 2) (i32.const 4)) (i32.const 0))
56+
(assert_return (invoke "eq" (i32.const 2) (i32.const 5)) (i32.const 0))
57+
(assert_return (invoke "eq" (i32.const 2) (i32.const 6)) (i32.const 0))
58+
(assert_return (invoke "eq" (i32.const 2) (i32.const 7)) (i32.const 0))
59+
(assert_return (invoke "eq" (i32.const 2) (i32.const 8)) (i32.const 0))
60+
61+
(assert_return (invoke "eq" (i32.const 3) (i32.const 0)) (i32.const 0))
62+
(assert_return (invoke "eq" (i32.const 3) (i32.const 1)) (i32.const 0))
63+
(assert_return (invoke "eq" (i32.const 3) (i32.const 2)) (i32.const 1))
64+
(assert_return (invoke "eq" (i32.const 3) (i32.const 3)) (i32.const 1))
65+
(assert_return (invoke "eq" (i32.const 3) (i32.const 4)) (i32.const 0))
66+
(assert_return (invoke "eq" (i32.const 3) (i32.const 5)) (i32.const 0))
67+
(assert_return (invoke "eq" (i32.const 3) (i32.const 6)) (i32.const 0))
68+
(assert_return (invoke "eq" (i32.const 3) (i32.const 7)) (i32.const 0))
69+
(assert_return (invoke "eq" (i32.const 3) (i32.const 8)) (i32.const 0))
70+
71+
(assert_return (invoke "eq" (i32.const 4) (i32.const 0)) (i32.const 0))
72+
(assert_return (invoke "eq" (i32.const 4) (i32.const 1)) (i32.const 0))
73+
(assert_return (invoke "eq" (i32.const 4) (i32.const 2)) (i32.const 0))
74+
(assert_return (invoke "eq" (i32.const 4) (i32.const 3)) (i32.const 0))
75+
(assert_return (invoke "eq" (i32.const 4) (i32.const 4)) (i32.const 1))
76+
(assert_return (invoke "eq" (i32.const 4) (i32.const 5)) (i32.const 0))
77+
(assert_return (invoke "eq" (i32.const 4) (i32.const 6)) (i32.const 0))
78+
(assert_return (invoke "eq" (i32.const 4) (i32.const 7)) (i32.const 0))
79+
(assert_return (invoke "eq" (i32.const 4) (i32.const 8)) (i32.const 0))
80+
81+
(assert_return (invoke "eq" (i32.const 5) (i32.const 0)) (i32.const 0))
82+
(assert_return (invoke "eq" (i32.const 5) (i32.const 1)) (i32.const 0))
83+
(assert_return (invoke "eq" (i32.const 5) (i32.const 2)) (i32.const 0))
84+
(assert_return (invoke "eq" (i32.const 5) (i32.const 3)) (i32.const 0))
85+
(assert_return (invoke "eq" (i32.const 5) (i32.const 4)) (i32.const 0))
86+
(assert_return (invoke "eq" (i32.const 5) (i32.const 5)) (i32.const 1))
87+
(assert_return (invoke "eq" (i32.const 5) (i32.const 6)) (i32.const 0))
88+
(assert_return (invoke "eq" (i32.const 5) (i32.const 7)) (i32.const 0))
89+
(assert_return (invoke "eq" (i32.const 5) (i32.const 8)) (i32.const 0))
90+
91+
(assert_return (invoke "eq" (i32.const 6) (i32.const 0)) (i32.const 0))
92+
(assert_return (invoke "eq" (i32.const 6) (i32.const 1)) (i32.const 0))
93+
(assert_return (invoke "eq" (i32.const 6) (i32.const 2)) (i32.const 0))
94+
(assert_return (invoke "eq" (i32.const 6) (i32.const 3)) (i32.const 0))
95+
(assert_return (invoke "eq" (i32.const 6) (i32.const 4)) (i32.const 0))
96+
(assert_return (invoke "eq" (i32.const 6) (i32.const 5)) (i32.const 0))
97+
(assert_return (invoke "eq" (i32.const 6) (i32.const 6)) (i32.const 1))
98+
(assert_return (invoke "eq" (i32.const 6) (i32.const 7)) (i32.const 0))
99+
(assert_return (invoke "eq" (i32.const 6) (i32.const 8)) (i32.const 0))
100+
101+
(assert_return (invoke "eq" (i32.const 7) (i32.const 0)) (i32.const 0))
102+
(assert_return (invoke "eq" (i32.const 7) (i32.const 1)) (i32.const 0))
103+
(assert_return (invoke "eq" (i32.const 7) (i32.const 2)) (i32.const 0))
104+
(assert_return (invoke "eq" (i32.const 7) (i32.const 3)) (i32.const 0))
105+
(assert_return (invoke "eq" (i32.const 7) (i32.const 4)) (i32.const 0))
106+
(assert_return (invoke "eq" (i32.const 7) (i32.const 5)) (i32.const 0))
107+
(assert_return (invoke "eq" (i32.const 7) (i32.const 6)) (i32.const 0))
108+
(assert_return (invoke "eq" (i32.const 7) (i32.const 7)) (i32.const 1))
109+
(assert_return (invoke "eq" (i32.const 7) (i32.const 8)) (i32.const 0))
110+
111+
(assert_return (invoke "eq" (i32.const 8) (i32.const 0)) (i32.const 0))
112+
(assert_return (invoke "eq" (i32.const 8) (i32.const 1)) (i32.const 0))
113+
(assert_return (invoke "eq" (i32.const 8) (i32.const 2)) (i32.const 0))
114+
(assert_return (invoke "eq" (i32.const 8) (i32.const 3)) (i32.const 0))
115+
(assert_return (invoke "eq" (i32.const 8) (i32.const 4)) (i32.const 0))
116+
(assert_return (invoke "eq" (i32.const 8) (i32.const 5)) (i32.const 0))
117+
(assert_return (invoke "eq" (i32.const 8) (i32.const 6)) (i32.const 0))
118+
(assert_return (invoke "eq" (i32.const 8) (i32.const 7)) (i32.const 0))
119+
(assert_return (invoke "eq" (i32.const 8) (i32.const 8)) (i32.const 1))
120+
121+
(assert_invalid
122+
(module
123+
(func (export "eq") (param $r (ref any)) (result i32)
124+
(ref.eq (local.get $r) (local.get $r))
125+
)
126+
)
127+
"type mismatch"
128+
)
129+
(assert_invalid
130+
(module
131+
(func (export "eq") (param $r (ref null any)) (result i32)
132+
(ref.eq (local.get $r) (local.get $r))
133+
)
134+
)
135+
"type mismatch"
136+
)
137+
(assert_invalid
138+
(module
139+
(func (export "eq") (param $r (ref func)) (result i32)
140+
(ref.eq (local.get $r) (local.get $r))
141+
)
142+
)
143+
"type mismatch"
144+
)
145+
(assert_invalid
146+
(module
147+
(func (export "eq") (param $r (ref null func)) (result i32)
148+
(ref.eq (local.get $r) (local.get $r))
149+
)
150+
)
151+
"type mismatch"
152+
)
153+
(assert_invalid
154+
(module
155+
(func (export "eq") (param $r (ref extern)) (result i32)
156+
(ref.eq (local.get $r) (local.get $r))
157+
)
158+
)
159+
"type mismatch"
160+
)
161+
(assert_invalid
162+
(module
163+
(func (export "eq") (param $r (ref null extern)) (result i32)
164+
(ref.eq (local.get $r) (local.get $r))
165+
)
166+
)
167+
"type mismatch"
168+
)

0 commit comments

Comments
 (0)