diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 31 | ||||
-rw-r--r-- | src/binaryen-c.h | 19 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 3 | ||||
-rw-r--r-- | src/ir/ExpressionAnalyzer.cpp | 5 | ||||
-rw-r--r-- | src/ir/ExpressionManipulator.cpp | 3 | ||||
-rw-r--r-- | src/ir/ReFinalize.cpp | 1 | ||||
-rw-r--r-- | src/ir/cost.h | 5 | ||||
-rw-r--r-- | src/ir/effects.h | 1 | ||||
-rw-r--r-- | src/ir/utils.h | 2 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 26 | ||||
-rw-r--r-- | src/passes/DeadCodeElimination.cpp | 10 | ||||
-rw-r--r-- | src/passes/Print.cpp | 9 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 18 | ||||
-rw-r--r-- | src/wasm-binary.h | 5 | ||||
-rw-r--r-- | src/wasm-builder.h | 7 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 15 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 1 | ||||
-rw-r--r-- | src/wasm-stack.h | 1 | ||||
-rw-r--r-- | src/wasm-traversal.h | 18 | ||||
-rw-r--r-- | src/wasm.h | 11 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 10 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 8 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 4 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 10 | ||||
-rw-r--r-- | src/wasm2js.h | 4 |
26 files changed, 239 insertions, 4 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 2f1d3f5ff..6dc6f7821 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -271,6 +271,7 @@ BinaryenExpressionId BinaryenRefIsNullId(void) { BinaryenExpressionId BinaryenRefFuncId(void) { return Expression::Id::RefFuncId; } +BinaryenExpressionId BinaryenRefEqId(void) { return Expression::Id::RefEqId; } BinaryenExpressionId BinaryenTryId(void) { return Expression::Id::TryId; } BinaryenExpressionId BinaryenThrowId(void) { return Expression::Id::ThrowId; } BinaryenExpressionId BinaryenRethrowId(void) { @@ -1290,6 +1291,13 @@ BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module, return static_cast<Expression*>(Builder(*(Module*)module).makeRefFunc(func)); } +BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module, + BinaryenExpressionRef left, + BinaryenExpressionRef right) { + return static_cast<Expression*>( + Builder(*(Module*)module).makeRefEq((Expression*)left, (Expression*)right)); +} + BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, BinaryenExpressionRef body, BinaryenExpressionRef catchBody) { @@ -2786,6 +2794,29 @@ void BinaryenRefFuncSetFunc(BinaryenExpressionRef expr, const char* funcName) { assert(expression->is<RefFunc>()); static_cast<RefFunc*>(expression)->func = funcName; } +// RefEq +BinaryenExpressionRef BinaryenRefEqGetLeft(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is<RefEq>()); + return static_cast<RefEq*>(expression)->left; +} +void BinaryenRefEqSetLeft(BinaryenExpressionRef expr, + BinaryenExpressionRef left) { + auto* expression = (Expression*)expr; + assert(expression->is<RefEq>()); + static_cast<RefEq*>(expression)->left = (Expression*)left; +} +BinaryenExpressionRef BinaryenRefEqGetRight(BinaryenExpressionRef expr) { + auto* expression = (Expression*)expr; + assert(expression->is<RefEq>()); + return static_cast<RefEq*>(expression)->right; +} +void BinaryenRefEqSetRight(BinaryenExpressionRef expr, + BinaryenExpressionRef right) { + auto* expression = (Expression*)expr; + assert(expression->is<RefEq>()); + static_cast<RefEq*>(expression)->right = (Expression*)right; +} // Try BinaryenExpressionRef BinaryenTryGetBody(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 3a3be4608..ff1af8ff4 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -166,6 +166,7 @@ BINARYEN_API BinaryenExpressionId BinaryenMemoryFillId(void); BINARYEN_API BinaryenExpressionId BinaryenRefNullId(void); BINARYEN_API BinaryenExpressionId BinaryenRefIsNullId(void); BINARYEN_API BinaryenExpressionId BinaryenRefFuncId(void); +BINARYEN_API BinaryenExpressionId BinaryenRefEqId(void); BINARYEN_API BinaryenExpressionId BinaryenTryId(void); BINARYEN_API BinaryenExpressionId BinaryenThrowId(void); BINARYEN_API BinaryenExpressionId BinaryenRethrowId(void); @@ -832,6 +833,9 @@ BINARYEN_API BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value); BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module, const char* func); +BINARYEN_API BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module, + BinaryenExpressionRef left, + BinaryenExpressionRef right); BINARYEN_API BinaryenExpressionRef BinaryenTry(BinaryenModuleRef module, BinaryenExpressionRef body, BinaryenExpressionRef catchBody); @@ -1710,6 +1714,21 @@ BINARYEN_API const char* BinaryenRefFuncGetFunc(BinaryenExpressionRef expr); BINARYEN_API void BinaryenRefFuncSetFunc(BinaryenExpressionRef expr, const char* funcName); +// RefEq + +// Gets the left expression of a `ref.eq` expression. +BINARYEN_API BinaryenExpressionRef +BinaryenRefEqGetLeft(BinaryenExpressionRef expr); +// Sets the left expression of a `ref.eq` expression. +BINARYEN_API void BinaryenRefEqSetLeft(BinaryenExpressionRef expr, + BinaryenExpressionRef left); +// Gets the right expression of a `ref.eq` expression. +BINARYEN_API BinaryenExpressionRef +BinaryenRefEqGetRight(BinaryenExpressionRef expr); +// Sets the right expression of a `ref.eq` expression. +BINARYEN_API void BinaryenRefEqSetRight(BinaryenExpressionRef expr, + BinaryenExpressionRef right); + // Try // Gets the body expression of a `try` expression. diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index d14e5bbdc..76616c320 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -2524,6 +2524,9 @@ switch (op[0]) { switch (op[2]) { case 'f': { switch (op[4]) { + case 'e': + if (strcmp(op, "ref.eq") == 0) { return makeRefEq(s); } + goto parse_error; case 'f': if (strcmp(op, "ref.func") == 0) { return makeRefFunc(s); } goto parse_error; diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp index a8d9ce44a..766d4023e 100644 --- a/src/ir/ExpressionAnalyzer.cpp +++ b/src/ir/ExpressionAnalyzer.cpp @@ -220,6 +220,7 @@ template<typename T> void visitImmediates(Expression* curr, T& visitor) { void visitRefNull(RefNull* curr) { visitor.visitType(curr->type); } void visitRefIsNull(RefIsNull* curr) {} void visitRefFunc(RefFunc* curr) { visitor.visitNonScopeName(curr->func); } + void visitRefEq(RefEq* curr) {} void visitTry(Try* curr) {} void visitThrow(Throw* curr) { visitor.visitNonScopeName(curr->event); } void visitRethrow(Rethrow* curr) {} @@ -479,9 +480,7 @@ size_t ExpressionAnalyzer::hash(Expression* curr) { "wasm64 will need changes here"); rehash(digest, curr); } - void visitAddress(Address curr) { - rehash(digest, curr.addr); - } + void visitAddress(Address curr) { rehash(digest, curr.addr); } }; return Hasher(curr).digest; diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp index e1264e96e..95fee632f 100644 --- a/src/ir/ExpressionManipulator.cpp +++ b/src/ir/ExpressionManipulator.cpp @@ -233,6 +233,9 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) { Expression* visitRefFunc(RefFunc* curr) { return builder.makeRefFunc(curr->func); } + Expression* visitRefEq(RefEq* curr) { + return builder.makeRefEq(copy(curr->left), copy(curr->right)); + } Expression* visitTry(Try* curr) { return builder.makeTry( copy(curr->body), copy(curr->catchBody), curr->type); diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index b6e2a1b59..99387ada1 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -124,6 +124,7 @@ void ReFinalize::visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); } void ReFinalize::visitRefNull(RefNull* curr) { curr->finalize(); } void ReFinalize::visitRefIsNull(RefIsNull* curr) { curr->finalize(); } void ReFinalize::visitRefFunc(RefFunc* curr) { curr->finalize(); } +void ReFinalize::visitRefEq(RefEq* curr) { curr->finalize(); } void ReFinalize::visitTry(Try* curr) { curr->finalize(); } void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); } void ReFinalize::visitRethrow(Rethrow* curr) { curr->finalize(); } diff --git a/src/ir/cost.h b/src/ir/cost.h index 056d51447..5df4917e4 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -757,8 +757,11 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> { Index visitMemorySize(MemorySize* curr) { return 1; } Index visitMemoryGrow(MemoryGrow* curr) { return 100; } Index visitRefNull(RefNull* curr) { return 1; } - Index visitRefIsNull(RefIsNull* curr) { return 1; } + Index visitRefIsNull(RefIsNull* curr) { return 1 + visit(curr->value); } Index visitRefFunc(RefFunc* curr) { return 1; } + Index visitRefEq(RefEq* curr) { + return 1 + visit(curr->left) + visit(curr->right); + } Index visitTry(Try* curr) { // We assume no exception will be thrown in most cases return visit(curr->body); diff --git a/src/ir/effects.h b/src/ir/effects.h index b973d7446..a90e902b0 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -475,6 +475,7 @@ struct EffectAnalyzer void visitRefNull(RefNull* curr) {} void visitRefIsNull(RefIsNull* curr) {} void visitRefFunc(RefFunc* curr) {} + void visitRefEq(RefEq* curr) {} void visitTry(Try* curr) {} void visitThrow(Throw* curr) { if (tryDepth == 0) { diff --git a/src/ir/utils.h b/src/ir/utils.h index 51fe4c9e7..428657e88 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -150,6 +150,7 @@ struct ReFinalize void visitRefNull(RefNull* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); + void visitRefEq(RefEq* curr); void visitTry(Try* curr); void visitThrow(Throw* curr); void visitRethrow(Rethrow* curr); @@ -219,6 +220,7 @@ struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> { void visitRefNull(RefNull* curr) { curr->finalize(); } void visitRefIsNull(RefIsNull* curr) { curr->finalize(); } void visitRefFunc(RefFunc* curr) { curr->finalize(); } + void visitRefEq(RefEq* curr) { curr->finalize(); } void visitTry(Try* curr) { curr->finalize(); } void visitThrow(Throw* curr) { curr->finalize(); } void visitRethrow(Rethrow* curr) { curr->finalize(); } diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 4703abc54..e24b50984 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -89,6 +89,7 @@ function initializeConstants() { 'RefNull', 'RefIsNull', 'RefFunc', + 'RefEq', 'Try', 'Throw', 'Rethrow', @@ -2093,6 +2094,9 @@ function wrapModule(module, self = {}) { }, 'func'(func) { return preserveStack(() => Module['_BinaryenRefFunc'](module, strToStack(func))); + }, + 'eq'(left, right) { + return Module['_BinaryenRefEq'](module, left, right); } }; @@ -2803,6 +2807,13 @@ Module['getExpressionInfo'] = function(expr) { 'type': type, 'func': UTF8ToString(Module['_BinaryenRefFuncGetFunc'](expr)), }; + case Module['RefEqId']: + return { + 'id': id, + 'type': type, + 'left': Module['_BinaryenRefEqGetLeft'](expr), + 'right': Module['_BinaryenRefEqGetRight'](expr) + }; case Module['TryId']: return { 'id': id, @@ -4100,6 +4111,21 @@ Module['RefFunc'] = makeExpressionWrapper({ } }); +Module['RefEq'] = makeExpressionWrapper({ + 'getLeft'(expr) { + return Module['_BinaryenRefEqGetLeft'](expr); + }, + 'setLeft'(expr, leftExpr) { + return Module['_BinaryenRefEqSetLeft'](expr, leftExpr); + }, + 'getRight'(expr) { + return Module['_BinaryenRefEqGetRight'](expr); + }, + 'setRight'(expr, rightExpr) { + return Module['_BinaryenRefEqSetRight'](expr, rightExpr); + } +}); + Module['Try'] = makeExpressionWrapper({ 'getBody'(expr) { return Module['_BinaryenTryGetBody'](expr); diff --git a/src/passes/DeadCodeElimination.cpp b/src/passes/DeadCodeElimination.cpp index 4215de3f8..bf1c0705a 100644 --- a/src/passes/DeadCodeElimination.cpp +++ b/src/passes/DeadCodeElimination.cpp @@ -361,6 +361,8 @@ struct DeadCodeElimination DELEGATE(RefIsNull); case Expression::Id::RefFuncId: DELEGATE(RefFunc); + case Expression::Id::RefEqId: + DELEGATE(RefEq); case Expression::Id::TryId: DELEGATE(Try); case Expression::Id::ThrowId: @@ -527,6 +529,14 @@ struct DeadCodeElimination blockifyReachableOperands({curr->delta}, curr->type); } + void visitRefIsNull(RefIsNull* curr) { + blockifyReachableOperands({curr->value}, curr->type); + } + + void visitRefEq(RefEq* curr) { + blockifyReachableOperands({curr->left, curr->right}, curr->type); + } + void visitFunction(Function* curr) { assert(reachableBreaks.size() == 0); } }; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 6955a7a5e..27c3e327c 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1441,6 +1441,7 @@ struct PrintExpressionContents printMedium(o, "ref.func "); printName(curr->func, o); } + void visitRefEq(RefEq* curr) { printMedium(o, "ref.eq"); } void visitTry(Try* curr) { printMedium(o, "try"); if (curr->type.isConcrete()) { @@ -1968,6 +1969,14 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { PrintExpressionContents(currFunction, o).visit(curr); o << ')'; } + void visitRefEq(RefEq* curr) { + o << '('; + PrintExpressionContents(currFunction, o).visit(curr); + incIndent(); + printFullLine(curr->left); + printFullLine(curr->right); + decIndent(); + } // try-catch-end is written in the folded wat format as // (try // (do diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 0783588cd..7ef24bbac 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -892,6 +892,8 @@ private: } if (type == Type::i32) { options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull); + options.add(FeatureSet::ReferenceTypes | FeatureSet::GC, + &Self::makeRefEq); } if (type.isTuple()) { options.add(FeatureSet::Multivalue, &Self::makeTupleMake); @@ -2640,6 +2642,14 @@ private: return builder.makeRefIsNull(make(getReferenceType())); } + Expression* makeRefEq(Type type) { + assert(type == Type::i32); + assert(wasm.features.hasReferenceTypes() && wasm.features.hasGC()); + auto* left = make(getEqReferenceType()); + auto* right = make(getEqReferenceType()); + return builder.makeRefEq(left, right); + } + Expression* makeMemoryInit() { if (!allowMemory) { return makeTrivial(Type::none); @@ -2723,6 +2733,14 @@ private: Type getReferenceType() { return pick(getReferenceTypes()); } + std::vector<Type> getEqReferenceTypes() { + return items( + FeatureOptions<Type>().add(FeatureSet::ReferenceTypes | FeatureSet::GC, + Type::eqref)); // TODO: i31ref + } + + Type getEqReferenceType() { return pick(getEqReferenceTypes()); } + Type getTupleType() { std::vector<Type> elements; size_t numElements = 2 + upTo(MAX_TUPLE_SIZE - 1); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 39980ee04..df800d470 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -927,6 +927,10 @@ enum ASTNodes { RefIsNull = 0xd1, RefFunc = 0xd2, + // GC opcodes + + RefEq = 0xd5, + // exception handling opcodes Try = 0x06, @@ -1458,6 +1462,7 @@ public: void visitRefNull(RefNull* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); + void visitRefEq(RefEq* curr); void visitTryOrTryInBlock(Expression*& out); void visitThrow(Throw* curr); void visitRethrow(Rethrow* curr); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 737dad16a..8c5d8722e 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -558,6 +558,13 @@ public: ret->finalize(); return ret; } + RefEq* makeRefEq(Expression* left, Expression* right) { + auto* ret = allocator.alloc<RefEq>(); + ret->left = left; + ret->right = right; + ret->finalize(); + return ret; + } Try* makeTry(Expression* body, Expression* catchBody) { auto* ret = allocator.alloc<Try>(); ret->body = body; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 69d6ff771..57ec65edd 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1260,6 +1260,21 @@ public: NOTE_NAME(curr->func); return Literal::makeFunc(curr->func); } + Flow visitRefEq(RefEq* curr) { + NOTE_ENTER("RefEq"); + Flow flow = visit(curr->left); + if (flow.breaking()) { + return flow; + } + auto left = flow.getSingleValue(); + flow = visit(curr->right); + if (flow.breaking()) { + return flow; + } + auto right = flow.getSingleValue(); + NOTE_EVAL2(left, right); + return Literal(int32_t(left == right)); + } Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); } Flow visitThrow(Throw* curr) { NOTE_ENTER("Throw"); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index f413ab5d4..5719084e4 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -236,6 +236,7 @@ private: Expression* makeRefNull(Element& s); Expression* makeRefIsNull(Element& s); Expression* makeRefFunc(Element& s); + Expression* makeRefEq(Element& s); Expression* makeTry(Element& s); Expression* makeTryOrCatchBody(Element& s, Type type, bool isTry); Expression* makeThrow(Element& s); diff --git a/src/wasm-stack.h b/src/wasm-stack.h index 13cce6d6f..b7a064168 100644 --- a/src/wasm-stack.h +++ b/src/wasm-stack.h @@ -137,6 +137,7 @@ public: void visitRefNull(RefNull* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); + void visitRefEq(RefEq* curr); void visitTry(Try* curr); void visitThrow(Throw* curr); void visitRethrow(Rethrow* curr); diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h index 94997caf1..8267f4767 100644 --- a/src/wasm-traversal.h +++ b/src/wasm-traversal.h @@ -76,6 +76,7 @@ template<typename SubType, typename ReturnType = void> struct Visitor { ReturnType visitRefNull(RefNull* curr) { return ReturnType(); } ReturnType visitRefIsNull(RefIsNull* curr) { return ReturnType(); } ReturnType visitRefFunc(RefFunc* curr) { return ReturnType(); } + ReturnType visitRefEq(RefEq* curr) { return ReturnType(); } ReturnType visitTry(Try* curr) { return ReturnType(); } ReturnType visitThrow(Throw* curr) { return ReturnType(); } ReturnType visitRethrow(Rethrow* curr) { return ReturnType(); } @@ -180,6 +181,8 @@ template<typename SubType, typename ReturnType = void> struct Visitor { DELEGATE(RefIsNull); case Expression::Id::RefFuncId: DELEGATE(RefFunc); + case Expression::Id::RefEqId: + DELEGATE(RefEq); case Expression::Id::TryId: DELEGATE(Try); case Expression::Id::ThrowId: @@ -260,6 +263,7 @@ struct OverriddenVisitor { UNIMPLEMENTED(RefNull); UNIMPLEMENTED(RefIsNull); UNIMPLEMENTED(RefFunc); + UNIMPLEMENTED(RefEq); UNIMPLEMENTED(Try); UNIMPLEMENTED(Throw); UNIMPLEMENTED(Rethrow); @@ -365,6 +369,8 @@ struct OverriddenVisitor { DELEGATE(RefIsNull); case Expression::Id::RefFuncId: DELEGATE(RefFunc); + case Expression::Id::RefEqId: + DELEGATE(RefEq); case Expression::Id::TryId: DELEGATE(Try); case Expression::Id::ThrowId: @@ -518,6 +524,9 @@ struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> { ReturnType visitRefFunc(RefFunc* curr) { return static_cast<SubType*>(this)->visitExpression(curr); } + ReturnType visitRefEq(RefEq* curr) { + return static_cast<SubType*>(this)->visitExpression(curr); + } ReturnType visitTry(Try* curr) { return static_cast<SubType*>(this)->visitExpression(curr); } @@ -835,6 +844,9 @@ struct Walker : public VisitorType { static void doVisitRefFunc(SubType* self, Expression** currp) { self->visitRefFunc((*currp)->cast<RefFunc>()); } + static void doVisitRefEq(SubType* self, Expression** currp) { + self->visitRefEq((*currp)->cast<RefEq>()); + } static void doVisitTry(SubType* self, Expression** currp) { self->visitTry((*currp)->cast<Try>()); } @@ -1108,6 +1120,12 @@ struct PostWalker : public Walker<SubType, VisitorType> { self->pushTask(SubType::doVisitRefFunc, currp); break; } + case Expression::Id::RefEqId: { + self->pushTask(SubType::doVisitRefEq, currp); + self->pushTask(SubType::scan, &curr->cast<RefEq>()->right); + self->pushTask(SubType::scan, &curr->cast<RefEq>()->left); + break; + } case Expression::Id::TryId: { self->pushTask(SubType::doVisitTry, currp); self->pushTask(SubType::scan, &curr->cast<Try>()->catchBody); diff --git a/src/wasm.h b/src/wasm.h index 9f61fac37..3f12f435e 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -553,6 +553,7 @@ public: RefNullId, RefIsNullId, RefFuncId, + RefEqId, TryId, ThrowId, RethrowId, @@ -1128,6 +1129,16 @@ public: void finalize(); }; +class RefEq : public SpecificExpression<Expression::RefEqId> { +public: + RefEq(MixedArena& allocator) {} + + Expression* left; + Expression* right; + + void finalize(); +}; + class Try : public SpecificExpression<Expression::TryId> { public: Try(MixedArena& allocator) {} diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index a6299c892..c1f698bb0 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2474,6 +2474,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { case BinaryConsts::RefFunc: visitRefFunc((curr = allocator.alloc<RefFunc>())->cast<RefFunc>()); break; + case BinaryConsts::RefEq: + visitRefEq((curr = allocator.alloc<RefEq>())->cast<RefEq>()); + break; case BinaryConsts::Try: visitTryOrTryInBlock(curr); break; @@ -4864,6 +4867,13 @@ void WasmBinaryBuilder::visitRefFunc(RefFunc* curr) { curr->finalize(); } +void WasmBinaryBuilder::visitRefEq(RefEq* curr) { + BYN_TRACE("zz node: RefEq\n"); + curr->right = popNonVoidExpression(); + curr->left = popNonVoidExpression(); + curr->finalize(); +} + void WasmBinaryBuilder::visitTryOrTryInBlock(Expression*& out) { BYN_TRACE("zz node: Try\n"); auto* curr = allocator.alloc<Try>(); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 2aa60979f..1bb83ec94 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1850,6 +1850,14 @@ Expression* SExpressionWasmBuilder::makeRefFunc(Element& s) { return ret; } +Expression* SExpressionWasmBuilder::makeRefEq(Element& s) { + auto ret = allocator.alloc<RefEq>(); + ret->left = parseExpression(s[1]); + ret->right = parseExpression(s[2]); + ret->finalize(); + return ret; +} + // try-catch-end is written in the folded wast format as // (try // ... diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 66f9e02dd..551275622 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -1701,6 +1701,10 @@ void BinaryInstWriter::visitRefFunc(RefFunc* curr) { << U32LEB(parent.getFunctionIndex(curr->func)); } +void BinaryInstWriter::visitRefEq(RefEq* curr) { + o << int8_t(BinaryConsts::RefEq); +} + void BinaryInstWriter::visitTry(Try* curr) { breakStack.emplace_back(IMPOSSIBLE_CONTINUE); o << int8_t(BinaryConsts::Try); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 16ba60d72..c1df740df 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -330,6 +330,7 @@ public: void visitMemoryGrow(MemoryGrow* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); + void visitRefEq(RefEq* curr); void visitTry(Try* curr); void visitThrow(Throw* curr); void visitRethrow(Rethrow* curr); @@ -1957,6 +1958,21 @@ void FunctionValidator::visitRefFunc(RefFunc* curr) { shouldBeTrue(!!func, curr, "function argument of ref.func must exist"); } +void FunctionValidator::visitRefEq(RefEq* curr) { + shouldBeTrue( + getModule()->features.hasGC(), curr, "ref.eq requires gc to be enabled"); + shouldBeSubTypeOrFirstIsUnreachable( + curr->left->type, + Type::eqref, + curr->left, + "ref.eq's left argument should be a subtype of eqref"); + shouldBeSubTypeOrFirstIsUnreachable( + curr->right->type, + Type::eqref, + curr->right, + "ref.eq's right argument should be a subtype of eqref"); +} + void FunctionValidator::visitTry(Try* curr) { if (curr->type != Type::unreachable) { shouldBeSubTypeOrFirstIsUnreachable( diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 6cc61a8a1..0b45f494d 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -192,6 +192,8 @@ const char* getExpressionName(Expression* curr) { return "ref.is_null"; case Expression::Id::RefFuncId: return "ref.func"; + case Expression::Id::RefEqId: + return "ref.eq"; case Expression::Id::TryId: return "try"; case Expression::Id::ThrowId: @@ -915,6 +917,14 @@ void RefIsNull::finalize() { void RefFunc::finalize() { type = Type::funcref; } +void RefEq::finalize() { + if (left->type == Type::unreachable || right->type == Type::unreachable) { + type = Type::unreachable; + } else { + type = Type::i32; + } +} + void Try::finalize() { type = Type::getLeastUpperBound(body->type, catchBody->type); } diff --git a/src/wasm2js.h b/src/wasm2js.h index 9350b38d6..7377dad31 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2019,6 +2019,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, unimplemented(curr); WASM_UNREACHABLE("unimp"); } + Ref visitRefEq(RefEq* curr) { + unimplemented(curr); + WASM_UNREACHABLE("unimp"); + } Ref visitTry(Try* curr) { unimplemented(curr); WASM_UNREACHABLE("unimp"); |