diff options
35 files changed, 430 insertions, 764 deletions
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index d66f10852..dd053ecee 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -495,7 +495,9 @@ instructions = [ # Multivalue pseudoinstructions ("tuple.make", "makeTupleMake(s)"), ("tuple.extract", "makeTupleExtract(s)"), - ("pop", "makePop(s)") + ("pop", "makePop(s)"), + # GC instructions + ("ref.eq", "makeRefEq(s)") ] 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"); diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index ab545aac9..a586691d3 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -28,7 +28,7 @@ ) ) -getExpressionInfo(throw) = {"id":44,"type":1,"event":"e"} -getExpressionInfo(br_on_exn) = {"id":46,"type":9,"name":"l","event":"e"} -getExpressionInfo(rethrow) = {"id":45,"type":1} -getExpressionInfo(try) = {"id":43,"type":0} +getExpressionInfo(throw) = {"id":45,"type":1,"event":"e"} +getExpressionInfo(br_on_exn) = {"id":47,"type":9,"name":"l","event":"e"} +getExpressionInfo(rethrow) = {"id":46,"type":1} +getExpressionInfo(try) = {"id":44,"type":0} diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js index b9a9a24fb..a97097afe 100644 --- a/test/binaryen.js/expressions.js +++ b/test/binaryen.js/expressions.js @@ -1400,6 +1400,37 @@ console.log("# RefFunc"); module.dispose(); })(); +console.log("# RefEq"); +(function testRefEq() { + const module = new binaryen.Module(); + + var left = module.local.get(0, binaryen.eqref); + var right = module.local.get(1, binaryen.eqref); + const theRefEq = binaryen.RefEq(module.ref.eq(left, right)); + assert(theRefEq instanceof binaryen.RefEq); + assert(theRefEq instanceof binaryen.Expression); + assert(theRefEq.left === left); + assert(theRefEq.right === right); + assert(theRefEq.type === binaryen.i32); + + theRefEq.left = left = module.local.get(2, binaryen.eqref); + assert(theRefEq.left === left); + theRefEq.right = right = module.local.get(3, binaryen.eqref); + assert(theRefEq.right === right); + theRefEq.type = binaryen.f64; + theRefEq.finalize(); + assert(theRefEq.type === binaryen.i32); + + console.log(theRefEq.toText()); + assert( + theRefEq.toText() + == + "(ref.eq\n (local.get $2)\n (local.get $3)\n)\n" + ); + + module.dispose(); +})(); + console.log("# Try"); (function testTry() { const module = new binaryen.Module(); diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt index a8946875a..22c4f2747 100644 --- a/test/binaryen.js/expressions.js.txt +++ b/test/binaryen.js/expressions.js.txt @@ -210,6 +210,12 @@ # RefFunc (ref.func $b) +# RefEq +(ref.eq + (local.get $2) + (local.get $3) +) + # Try (try (result i32) (do diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 342315682..69c812bf7 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -155,11 +155,15 @@ function test_ids() { console.log("DataDropId: " + binaryen.DataDropId); console.log("MemoryCopyId: " + binaryen.MemoryCopyId); console.log("MemoryFillId: " + binaryen.MemoryFillId); + console.log("PopId: " + binaryen.PopId); + console.log("RefNullId: " + binaryen.RefNullId); + console.log("RefIsNullId: " + binaryen.RefIsNullId); + console.log("RefFuncId: " + binaryen.RefFuncId); + console.log("RefEqId: " + binaryen.RefEqId); console.log("TryId: " + binaryen.TryId); console.log("ThrowId: " + binaryen.ThrowId); console.log("RethrowId: " + binaryen.RethrowId); console.log("BrOnExnId: " + binaryen.BrOnExnId); - console.log("PopId: " + binaryen.PopId); } function test_core() { @@ -521,6 +525,9 @@ function test_core() { module.ref.is_null(module.ref.func("kitchen()sinker")), module.select(temp10, module.ref.null(binaryen.funcref), module.ref.func("kitchen()sinker"), binaryen.funcref), + // GC + module.ref.eq(module.ref.null(binaryen.eqref), module.ref.null(binaryen.eqref)), + // Exception handling module.try( module.throw("a-event", [module.i32.const(0)]), diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 413a2236c..b94811be5 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -79,11 +79,15 @@ MemoryInitId: 35 DataDropId: 36 MemoryCopyId: 37 MemoryFillId: 38 -TryId: 43 -ThrowId: 44 -RethrowId: 45 -BrOnExnId: 46 PopId: 39 +RefNullId: 40 +RefIsNullId: 41 +RefFuncId: 42 +RefEqId: 43 +TryId: 44 +ThrowId: 45 +RethrowId: 46 +BrOnExnId: 47 getExpressionInfo={"id":15,"type":4,"op":6} (f32.neg (f32.const -33.61199951171875) @@ -1841,6 +1845,12 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} (i32.const 1) ) ) + (drop + (ref.eq + (ref.null eq) + (ref.null eq) + ) + ) (try (do (throw $a-event @@ -3698,6 +3708,12 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} (i32.const 1) ) ) + (drop + (ref.eq + (ref.null eq) + (ref.null eq) + ) + ) (try (do (throw $a-event diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index 442394e12..6b4aaec7d 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -740,6 +740,10 @@ void test_core() { BinaryenRefNull(module, BinaryenTypeFuncref()), BinaryenRefFunc(module, "kitchen()sinker"), BinaryenTypeFuncref()), + // GC + BinaryenRefEq(module, + BinaryenRefNull(module, BinaryenTypeEqref()), + BinaryenRefNull(module, BinaryenTypeEqref())), // Exception handling BinaryenTry(module, tryBody, catchBody), // Atomics diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index 405848140..e2dd48ad4 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -1776,6 +1776,12 @@ BinaryenFeatureAll: 4095 (i32.const 1) ) ) + (drop + (ref.eq + (ref.null eq) + (ref.null eq) + ) + ) (try (do (throw $a-event diff --git a/test/passes/translate-to-fuzz_all-features.txt b/test/passes/translate-to-fuzz_all-features.txt index b03dbbb20..50cc583ac 100644 --- a/test/passes/translate-to-fuzz_all-features.txt +++ b/test/passes/translate-to-fuzz_all-features.txt @@ -1,24 +1,14 @@ (module - (type $f32_=>_none (func (param f32))) + (type $none_=>_funcref_anyref_f32_exnref (func (result funcref anyref f32 exnref))) (type $none_=>_none (func)) - (type $none_=>_f32_i64_funcref (func (result f32 i64 funcref))) + (type $f32_=>_none (func (param f32))) (type $i32_=>_none (func (param i32))) - (type $i32_f64_=>_none (func (param i32 f64))) (type $i64_=>_none (func (param i64))) (type $f64_=>_none (func (param f64))) (type $v128_=>_none (func (param v128))) (type $exnref_=>_none (func (param exnref))) (type $none_=>_i32 (func (result i32))) - (type $funcref_anyref_=>_f64 (func (param funcref anyref) (result f64))) - (type $anyref_eqref_=>_f64 (func (param anyref eqref) (result f64))) - (type $funcref_f64_=>_v128 (func (param funcref f64) (result v128))) - (type $none_=>_funcref (func (result funcref))) - (type $v128_=>_funcref (func (param v128) (result funcref))) - (type $v128_anyref_f32_=>_funcref (func (param v128 anyref f32) (result funcref))) - (type $externref_i32_v128_i64_=>_externref (func (param externref i32 v128 i64) (result externref))) - (type $f32_eqref_=>_anyref (func (param f32 eqref) (result anyref))) - (type $none_=>_eqref_eqref_eqref_eqref_eqref (func (result eqref eqref eqref eqref eqref))) - (type $exnref_=>_eqref_eqref_eqref_eqref_eqref (func (param exnref) (result eqref eqref eqref eqref eqref))) + (type $f32_i32_anyref_=>_i64 (func (param f32 i32 anyref) (result i64))) (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) (import "fuzzing-support" "log-i64" (func $log-i64 (param i64))) (import "fuzzing-support" "log-f32" (func $log-f32 (param f32))) @@ -27,8 +17,7 @@ (import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref))) (memory $0 (shared 1 1)) (data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3") - (table $0 12 12 funcref) - (elem (i32.const 0) $func_7 $func_7 $func_8 $func_8 $func_9 $func_9 $func_9 $func_13 $func_13 $func_13 $func_17 $func_19) + (table $0 0 0 funcref) (global $global$5 (mut eqref) (ref.null eq)) (global $global$4 (mut externref) (ref.null extern)) (global $global$3 (mut exnref) (ref.null exn)) @@ -44,14 +33,8 @@ (global $hangLimit (mut i32) (i32.const 10)) (export "hashMemory" (func $hashMemory)) (export "memory" (memory $0)) - (export "func_9" (func $func_9)) - (export "func_10_invoker" (func $func_10_invoker)) - (export "func_12" (func $func_12)) - (export "func_13_invoker" (func $func_13_invoker)) - (export "func_17" (func $func_17)) - (export "func_19" (func $func_19)) - (export "func_19_invoker" (func $func_19_invoker)) - (export "func_21" (func $func_21)) + (export "func_7" (func $func_7)) + (export "func_8_invoker" (func $func_8_invoker)) (export "hangLimitInitializer" (func $hangLimitInitializer)) (func $hashMemory (result i32) (local $0 i32) @@ -312,528 +295,97 @@ (i32.eqz (i32.const 32768) ) - (block $label$1 (result f64) + (block $label$1 (br_if $label$0 (i32.eqz - (loop $label$2 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (ref.eq + (ref.null eq) + (loop $label$21 + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) ) - ) - ) - (block $label$3 (result i32) - (nop) - (local.tee $7 - (local.tee $2 - (local.tee $7 - (local.tee $2 - (local.tee $2 - (local.tee $2 - (local.tee $2 - (local.tee $2 - (local.get $7) - ) - ) - ) - ) - ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) ) ) ) + (block $label$22 + (nop) + (br $label$21) + ) ) ) ) ) - (call $log-exnref - (ref.null exn) - ) - (f64.const 11839) - ) - (block $label$4 (result f64) - (nop) - (f64.nearest - (f64.const 1.6005841300030413e-215) - ) - ) - ) - ) - (call $log-exnref - (ref.null exn) - ) - ) - ) - (func $func_8 (param $0 funcref) (param $1 anyref) (result f64) - (local $2 i64) - (local $3 (f64 i32 anyref i64 exnref)) - (local $4 v128) - (local $5 (v128 f32 exnref)) - (local $6 f32) - (local $7 i32) - (local $8 (funcref eqref)) - (local $9 i64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (f64.const 4806734720588042541890704e256) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (f64.const 9223372036854775808) - ) - (func $func_9 (param $0 i32) (param $1 f64) - (local $2 i32) - (local $3 funcref) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 - (f32.store offset=3 align=2 - (i32.and - (local.get $0) - (i32.const 15) - ) - (if (result f32) - (local.tee $2 - (local.tee $2 - (block $label$1 - (call_indirect (type $f32_=>_none) - (f32.div - (f32.const 4189) - (f32.const 1396855168) - ) - (i32.atomic.rmw8.cmpxchg_u offset=3 - (i32.and - (call $hashMemory) - (i32.const 15) - ) - (local.tee $0 - (local.get $2) - ) - (loop $label$3 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (loop $label$4 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$5 (result i32) - (v128.store offset=22 align=8 - (i32.and - (i32.load16_u offset=4 align=1 - (i32.and - (ref.is_null - (ref.null extern) - ) - (i32.const 15) - ) - ) - (i32.const 15) - ) - (i16x8.ne - (i16x8.gt_u - (select - (if (result v128) - (i32.eqz - (i32.const 2147483647) - ) - (block $label$8 (result v128) - (nop) - (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) - ) - (block $label$9 (result v128) - (if (result v128) - (i32.const -96) - (v128.const i32x4 0xffffff99 0xffffffff 0x00000000 0x40648000) - (v128.const i32x4 0x00005f01 0x0000b03f 0x644b1d80 0x4fb2ff39) - ) - ) - ) - (v128.const i32x4 0x00000000 0x40eff640 0x00000000 0xc1300000) - (local.tee $0 - (if (result i32) - (local.tee $0 - (local.get $0) - ) - (block $label$6 (result i32) - (local.set $0 - (local.get $2) - ) - (if (result i32) - (if (result i32) - (i32.eqz - (local.get $2) - ) - (i32.const 127) - (i32.const -128) - ) - (i32.const 26) - (i32.const -32768) - ) - ) - (block $label$7 - (atomic.fence) - (br $label$3) - ) - ) - ) - ) - (tuple.extract 4 - (tuple.make - (ref.null extern) - (i32.const 126) - (f32.const 2.5923033978570846e-30) - (i64.const 6796583934299212805) - (v128.const i32x4 0x00000008 0x00000000 0x000000fe 0x00000000) - ) - ) - ) - (v128.const i32x4 0x0057ff7f 0x00470000 0x00014359 0x007f3028) - ) - ) - (atomic.notify offset=3 - (i32.and - (if (result i32) - (i32.eqz - (f32.ge - (f32.sqrt - (f32.const -0.1029999852180481) - ) - (f32x4.extract_lane 0 - (v128.const i32x4 0x080a617e 0xcf000000 0xda800000 0xc20c0000) - ) - ) - ) - (select - (local.tee $0 - (local.tee $2 - (local.tee $2 - (local.tee $2 - (local.get $2) - ) - ) - ) - ) - (local.get $2) - (i32.const 0) - ) - (local.tee $0 - (br_if $label$5 - (f64.gt - (select - (local.get $1) - (if (result f64) - (i32.eqz - (local.get $2) - ) - (local.get $1) - (f64.const 2.5823598491911832e-236) - ) - (local.get $0) - ) - (local.get $1) - ) - (i32.const 609887560) - ) - ) - ) - (i32.const 15) - ) - (i64.eq - (tuple.extract 0 - (tuple.make - (i64.const 82) - (i32.const 0) - ) - ) - (i64.const 2147483646) - ) - ) - ) - ) - ) + (if + (i32.eqz + (i32.const -33554432) + ) + (block $label$2 + (br_if $label$2 + (i32.eqz + (local.get $2) ) ) - (br $label$0) + (call $log-i32 + (call $hashMemory) + ) + ) + (drop + (ref.null extern) ) ) + (br $label$0) ) - (f32.demote_f64 - (block $label$2 - (call_indirect (type $f32_=>_none) - (f32.div - (f32.const 4189) - (f32.const 1396855168) + (loop $label$4 (result f64) + (block + (if + (i32.eqz + (global.get $hangLimit) ) - (i32.atomic.rmw8.cmpxchg_u offset=3 - (i32.and - (call $hashMemory) - (i32.const 15) - ) - (local.tee $0 - (local.get $2) - ) - (i32.const -94) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) ) ) - (br $label$0) ) + (f64.const 82) ) - (f32.const -2147483648) - ) - ) - (call_indirect (type $f32_=>_none) - (f32.sqrt - (f32.const -0.1029999852180481) - ) - (i32.atomic.rmw8.cmpxchg_u offset=3 - (i32.and - (call $hashMemory) - (i32.const 2147483647) - ) - (local.tee $0 - (local.get $2) - ) - (i32.const 536870912) ) ) - ) - ) - (func $func_10 (result f32 i64 funcref) - (local $0 i64) - (local $1 (exnref exnref exnref exnref f32)) - (local $2 externref) - (local $3 (v128 funcref)) - (local $4 externref) - (local $5 (i32 f32)) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (tuple.make - (f32.const 2047.8480224609375) - (i64.const -127) - (ref.null func) - ) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 (result f32 i64 funcref) - (call $log-f64 - (f64.const 1.44) - ) - (call $log-i32 - (call $hashMemory) - ) - (tuple.make - (f32.const 527435904) - (i64.const 2147483648) - (ref.null func) - ) - ) - ) - (func $func_10_invoker - (drop - (call $func_10) - ) - (call $log-i32 - (call $hashMemory) - ) - (drop - (call $func_10) - ) - (call $log-i32 - (call $hashMemory) - ) - ) - (func $func_12 (result funcref) - (local $0 anyref) - (local $1 eqref) - (local $2 i64) - (local $3 (anyref exnref i64 i32 anyref v128)) - (local $4 externref) - (local $5 anyref) - (local $6 f32) - (local $7 v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (ref.func $func_10) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (ref.null func) - ) - (func $func_13 (param $0 exnref) (result eqref eqref eqref eqref eqref) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (tuple.make - (ref.null eq) - (ref.null eq) - (ref.null eq) - (ref.null eq) - (ref.null eq) - ) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 - (return - (tuple.make - (ref.null eq) - (ref.null eq) - (ref.null eq) - (ref.null eq) - (ref.null eq) - ) - ) - ) - ) - (func $func_13_invoker - (drop - (call $func_13 - (ref.null exn) - ) - ) - ) - (func $func_15 (param $0 anyref) (param $1 eqref) (result f64) - (local $2 (f64 eqref funcref i32)) - (local $3 v128) - (local $4 i64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (f64.const 303201560) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (f64.const 1.8039635330443502e-221) - ) - (func $func_16 (param $0 funcref) (param $1 f64) (result v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (v128.const i32x4 0x00000000 0x41400000 0x00000000 0x40458000) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 - (if - (i32.const 10793) - (call_indirect (type $f32_=>_none) - (f32.const 3402823466385288598117041e14) - (i32.const 0) - ) - (block $label$1 - (call $log-i32 - (call $hashMemory) + (call $log-v128 + (loop $label$50 (result v128) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) ) - (call $log-f32 - (loop $label$2 (result f32) + (block $label$51 (result v128) + (loop $label$52 (block (if (i32.eqz (global.get $hangLimit) ) - (return - (v128.const i32x4 0x41700000 0x5f000000 0x3f800000 0x41a00000) - ) + (return) ) (global.set $hangLimit (i32.sub @@ -842,73 +394,26 @@ ) ) ) - (block (result f32) - (block $label$3 - (call $log-i32 - (call $hashMemory) - ) - (call $log-v128 - (loop $label$4 (result v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (v128.const i32x4 0x152dffff 0x8000ffa4 0x1f484608 0x02193720) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$5 (result v128) - (call $log-i32 - (i32.const -1) - ) - (v128.const i32x4 0x00020000 0xff8000b0 0xffb40001 0xffff5657) - ) - ) - ) - ) - (br_if $label$2 - (if (result i32) - (i32.eqz - (f32.ge - (f32.const 3402823466385288598117041e14) - (f32.const 3402823466385288598117041e14) - ) - ) - (i32.const 0) - (i32.const -65537) - ) + (block $label$53 + (call $log-i32 + (call $hashMemory) ) - (f32.const 0.004999999888241291) ) ) + (local.get $5) ) ) ) - (return - (v128.const i32x4 0x1b145c08 0xffffffe0 0x00400000 0x00000052) - ) ) ) - (func $func_17 (param $0 v128) (param $1 anyref) (param $2 f32) (result funcref) - (local $3 i64) - (local $4 (externref i32)) - (local $5 i32) - (local $6 f64) + (func $func_8 (param $0 f32) (param $1 i32) (param $2 anyref) (result i64) (block (if (i32.eqz (global.get $hangLimit) ) (return - (ref.func $log-exnref) + (i64.const -2147483647) ) ) (global.set $hangLimit @@ -918,80 +423,40 @@ ) ) ) - (ref.null func) + (i64.const 6438275382591167256) ) - (func $func_18 (param $0 externref) (param $1 i32) (param $2 v128) (param $3 i64) (result externref) - (local $4 funcref) - (local $5 eqref) - (local $6 eqref) - (local $7 (f64 funcref f64 i32)) - (local $8 externref) - (local $9 i32) - (local $10 i64) - (local $11 eqref) - (local $12 externref) - (local $13 funcref) - (local $14 f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (local.get $8) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$0 (result externref) - (nop) - (local.get $0) - ) - ) - (func $func_19 (param $0 f32) (param $1 eqref) (result anyref) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (ref.null any) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (ref.null any) - ) - (func $func_19_invoker + (func $func_8_invoker (drop - (call $func_19 - (f32.const 58) - (ref.null eq) + (call $func_8 + (f32.const -nan:0x7fffcb) + (i32.const -51) + (ref.null any) ) ) - (call $log-i32 - (call $hashMemory) - ) ) - (func $func_21 (param $0 v128) (result funcref) - (local $1 i64) + (func $func_10 (result funcref anyref f32 exnref) + (local $0 f64) + (local $1 v128) + (local $2 (i32 eqref anyref exnref)) + (local $3 eqref) + (local $4 externref) + (local $5 anyref) + (local $6 f64) + (local $7 funcref) + (local $8 (i64 externref v128 f64 f32 exnref)) + (local $9 anyref) (block (if (i32.eqz (global.get $hangLimit) ) (return - (ref.func $hashMemory) + (tuple.make + (ref.null func) + (ref.null any) + (f32.const -nan:0x7ffffc) + (ref.null exn) + ) ) ) (global.set $hangLimit @@ -1001,127 +466,21 @@ ) ) ) - (block $label$0 (result funcref) - (drop - (tuple.make - (ref.null exn) - (ref.null eq) - (i32.const 26) - (v128.const i32x4 0x1715037b 0x00000027 0x000007ff 0xf8000000) - (f64.const 9.532824124368358e-130) - ) - ) + (block (result funcref anyref f32 exnref) (block $label$1 - (block $label$2 - (local.tee $1 - (i64.shr_s - (loop $label$3 (result i64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (ref.func $log-f32) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i64) - (nop) - (br_if $label$3 - (i32.eqz - (i32.const -32766) - ) - ) - (i64.trunc_f32_s - (f32.min - (f32.load offset=3 - (i32.and - (i32.const 454758683) - (i32.const 15) - ) - ) - (f32.const 1023.5869750976562) - ) - ) - ) - ) - (if - (i32.eqz - (i32.const 2049) - ) - (block $label$4 - (nop) - (br $label$1) - ) - (block $label$5 - (i64.store16 offset=2 - (i32.and - (block $label$6 (result i32) - (call $log-i64 - (i64.const 1949228928397086024) - ) - (i32.const 2) - ) - (i32.const 15) - ) - (local.get $1) - ) - (br $label$2) - ) - ) - ) - ) - (nop) + (call $log-i32 + (call $hashMemory) ) - (block $label$7 - (nop) + (call $log-v128 + (local.get $1) ) ) - (call $func_21 - (if (result v128) - (i32.eqz - (i32.const 760829235) - ) - (block $label$8 - (return - (ref.null func) - ) - ) - (loop $label$9 (result v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (ref.func $func_19) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result v128) - (nop) - (br_if $label$9 - (ref.is_null - (global.get $global$2) - ) - ) - (local.get $0) - ) - ) - ) + (nop) + (tuple.make + (ref.func $func_10) + (ref.null any) + (f32.const 7710) + (ref.null exn) ) ) ) |