summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp31
-rw-r--r--src/binaryen-c.h19
-rw-r--r--src/gen-s-parser.inc3
-rw-r--r--src/ir/ExpressionAnalyzer.cpp5
-rw-r--r--src/ir/ExpressionManipulator.cpp3
-rw-r--r--src/ir/ReFinalize.cpp1
-rw-r--r--src/ir/cost.h5
-rw-r--r--src/ir/effects.h1
-rw-r--r--src/ir/utils.h2
-rw-r--r--src/js/binaryen.js-post.js26
-rw-r--r--src/passes/DeadCodeElimination.cpp10
-rw-r--r--src/passes/Print.cpp9
-rw-r--r--src/tools/fuzzing.h18
-rw-r--r--src/wasm-binary.h5
-rw-r--r--src/wasm-builder.h7
-rw-r--r--src/wasm-interpreter.h15
-rw-r--r--src/wasm-s-parser.h1
-rw-r--r--src/wasm-stack.h1
-rw-r--r--src/wasm-traversal.h18
-rw-r--r--src/wasm.h11
-rw-r--r--src/wasm/wasm-binary.cpp10
-rw-r--r--src/wasm/wasm-s-parser.cpp8
-rw-r--r--src/wasm/wasm-stack.cpp4
-rw-r--r--src/wasm/wasm-validator.cpp16
-rw-r--r--src/wasm/wasm.cpp10
-rw-r--r--src/wasm2js.h4
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");