summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/cost.h8
-rw-r--r--src/ir/effects.h7
-rw-r--r--src/passes/Print.cpp22
-rw-r--r--src/wasm-builder.h10
-rw-r--r--src/wasm-delegations-fields.h6
-rw-r--r--src/wasm-type.h2
-rw-r--r--src/wasm.h10
-rw-r--r--src/wasm/wasm-binary.cpp22
-rw-r--r--src/wasm/wasm-s-parser.cpp18
-rw-r--r--src/wasm/wasm-stack.cpp6
-rw-r--r--src/wasm/wasm-validator.cpp18
-rw-r--r--src/wasm/wasm.cpp19
12 files changed, 103 insertions, 45 deletions
diff --git a/src/ir/cost.h b/src/ir/cost.h
index b71e1ea0e..66a316bf6 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -560,8 +560,12 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
Index visitDataDrop(DataDrop* curr) { return 5; }
Index visitI31New(I31New* curr) { return 3 + visit(curr->value); }
Index visitI31Get(I31Get* curr) { return 2 + visit(curr->i31); }
- Index visitRefTest(RefTest* curr) { WASM_UNREACHABLE("TODO: GC"); }
- Index visitRefCast(RefCast* curr) { WASM_UNREACHABLE("TODO: GC"); }
+ Index visitRefTest(RefTest* curr) {
+ return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->rtt);
+ }
+ Index visitRefCast(RefCast* curr) {
+ return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->rtt);
+ }
Index visitBrOnCast(BrOnCast* curr) { WASM_UNREACHABLE("TODO: GC"); }
Index visitRttCanon(RttCanon* curr) {
// TODO: investigate actual RTT costs in VMs
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 94387c2cf..3cbddc491 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -545,11 +545,10 @@ private:
// traps when the arg is null
parent.implicitTrap = true;
}
- void visitRefTest(RefTest* curr) {
- WASM_UNREACHABLE("TODO (gc): ref.test");
- }
+ void visitRefTest(RefTest* curr) {}
void visitRefCast(RefCast* curr) {
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ // Traps if the ref is not null and it has an invalid rtt.
+ parent.implicitTrap = true;
}
void visitBrOnCast(BrOnCast* curr) {
WASM_UNREACHABLE("TODO (gc): br_on_cast");
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 694b1b118..4007b6daa 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -1692,12 +1692,12 @@ struct PrintExpressionContents
}
}
void visitRefTest(RefTest* curr) {
- printMedium(o, "ref.test");
- WASM_UNREACHABLE("TODO (gc): ref.test");
+ printMedium(o, "ref.test ");
+ printHeapTypeName(o, curr->rtt->type.getHeapType());
}
void visitRefCast(RefCast* curr) {
- printMedium(o, "ref.cast");
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ printMedium(o, "ref.cast ");
+ printHeapTypeName(o, curr->rtt->type.getHeapType());
}
void visitBrOnCast(BrOnCast* curr) {
printMedium(o, "br_on_cast");
@@ -1717,7 +1717,7 @@ struct PrintExpressionContents
o << "default_";
}
o << "with_rtt ";
- printHeapTypeName(o, curr->rtt->type.getRtt().heapType);
+ printHeapTypeName(o, curr->rtt->type.getHeapType());
}
void visitStructGet(StructGet* curr) {
const auto& field =
@@ -1747,7 +1747,7 @@ struct PrintExpressionContents
o << "default_";
}
o << "with_rtt ";
- printHeapTypeName(o, curr->rtt->type.getRtt().heapType);
+ printHeapTypeName(o, curr->rtt->type.getHeapType());
}
void visitArrayGet(ArrayGet* curr) {
const auto& element = curr->ref->type.getHeapType().getArray().element;
@@ -2394,12 +2394,18 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
void visitRefTest(RefTest* curr) {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
- WASM_UNREACHABLE("TODO (gc): ref.test");
+ incIndent();
+ printFullLine(curr->ref);
+ printFullLine(curr->rtt);
+ decIndent();
}
void visitRefCast(RefCast* curr) {
o << '(';
PrintExpressionContents(currFunction, o).visit(curr);
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ incIndent();
+ printFullLine(curr->ref);
+ printFullLine(curr->rtt);
+ decIndent();
}
void visitBrOnCast(BrOnCast* curr) {
o << '(';
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 73c8f9823..59c8d4c1b 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -691,15 +691,17 @@ public:
ret->finalize();
return ret;
}
- RefTest* makeRefTest() {
+ RefTest* makeRefTest(Expression* ref, Expression* rtt) {
auto* ret = wasm.allocator.alloc<RefTest>();
- WASM_UNREACHABLE("TODO (gc): ref.test");
+ ret->ref = ref;
+ ret->rtt = rtt;
ret->finalize();
return ret;
}
- RefCast* makeRefCast() {
+ RefCast* makeRefCast(Expression* ref, Expression* rtt) {
auto* ret = wasm.allocator.alloc<RefCast>();
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ ret->ref = ref;
+ ret->rtt = rtt;
ret->finalize();
return ret;
}
diff --git a/src/wasm-delegations-fields.h b/src/wasm-delegations-fields.h
index b90bf720b..d53af695f 100644
--- a/src/wasm-delegations-fields.h
+++ b/src/wasm-delegations-fields.h
@@ -559,13 +559,15 @@ switch (DELEGATE_ID) {
}
case Expression::Id::RefTestId: {
DELEGATE_START(RefTest);
- WASM_UNREACHABLE("TODO (gc): ref.test");
+ DELEGATE_FIELD_CHILD(RefTest, ref);
+ DELEGATE_FIELD_CHILD(RefTest, rtt);
DELEGATE_END(RefTest);
break;
}
case Expression::Id::RefCastId: {
DELEGATE_START(RefCast);
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ DELEGATE_FIELD_CHILD(RefCast, ref);
+ DELEGATE_FIELD_CHILD(RefCast, rtt);
DELEGATE_END(RefCast);
break;
}
diff --git a/src/wasm-type.h b/src/wasm-type.h
index a76e30b42..0df515f79 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -352,7 +352,7 @@ struct Tuple {
std::string toString() const;
// Prevent accidental copies
- Struct& operator=(const Struct&) = delete;
+ Tuple& operator=(const Tuple&) = delete;
private:
void validate() {
diff --git a/src/wasm.h b/src/wasm.h
index 0cc2f430c..0c6566407 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1310,14 +1310,20 @@ class RefTest : public SpecificExpression<Expression::RefTestId> {
public:
RefTest(MixedArena& allocator) {}
- void finalize() { WASM_UNREACHABLE("TODO (gc): ref.test"); }
+ Expression* ref;
+ Expression* rtt;
+
+ void finalize();
};
class RefCast : public SpecificExpression<Expression::RefCastId> {
public:
RefCast(MixedArena& allocator) {}
- void finalize() { WASM_UNREACHABLE("TODO (gc): ref.cast"); }
+ Expression* ref;
+ Expression* rtt;
+
+ void finalize();
};
class BrOnCast : public SpecificExpression<Expression::BrOnCastId> {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 0c68264a3..1b3d50a41 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -5599,10 +5599,13 @@ bool WasmBinaryBuilder::maybeVisitRefTest(Expression*& out, uint32_t code) {
if (code != BinaryConsts::RefTest) {
return false;
}
- auto* curr = allocator.alloc<RefTest>();
- WASM_UNREACHABLE("TODO (gc): ref.test");
- curr->finalize();
- out = curr;
+ auto heapType1 = getHeapType();
+ auto heapType2 = getHeapType();
+ auto* ref = popNonVoidExpression();
+ validateHeapTypeUsingChild(ref, heapType1);
+ auto* rtt = popNonVoidExpression();
+ validateHeapTypeUsingChild(rtt, heapType2);
+ out = Builder(wasm).makeRefTest(ref, rtt);
return true;
}
@@ -5610,10 +5613,13 @@ bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) {
if (code != BinaryConsts::RefCast) {
return false;
}
- auto* curr = allocator.alloc<RefCast>();
- WASM_UNREACHABLE("TODO (gc): ref.cast");
- curr->finalize();
- out = curr;
+ auto heapType1 = getHeapType();
+ auto heapType2 = getHeapType();
+ auto* ref = popNonVoidExpression();
+ validateHeapTypeUsingChild(ref, heapType1);
+ auto* rtt = popNonVoidExpression();
+ validateHeapTypeUsingChild(rtt, heapType2);
+ out = Builder(wasm).makeRefCast(ref, rtt);
return true;
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index b9f321b14..85bc2aba9 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2093,17 +2093,19 @@ Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) {
}
Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
- auto ret = allocator.alloc<RefTest>();
- WASM_UNREACHABLE("TODO (gc): ref.test");
- ret->finalize();
- return ret;
+ auto heapType = parseHeapType(*s[1]);
+ auto* ref = parseExpression(*s[2]);
+ auto* rtt = parseExpression(*s[3]);
+ validateHeapTypeUsingChild(rtt, heapType, s);
+ return Builder(wasm).makeRefTest(ref, rtt);
}
Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
- auto ret = allocator.alloc<RefCast>();
- WASM_UNREACHABLE("TODO (gc): ref.cast");
- ret->finalize();
- return ret;
+ auto heapType = parseHeapType(*s[1]);
+ auto* ref = parseExpression(*s[2]);
+ auto* rtt = parseExpression(*s[3]);
+ validateHeapTypeUsingChild(rtt, heapType, s);
+ return Builder(wasm).makeRefCast(ref, rtt);
}
Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 60c352c5d..741aef5ce 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1882,12 +1882,14 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) {
void BinaryInstWriter::visitRefTest(RefTest* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefTest);
- WASM_UNREACHABLE("TODO (gc): ref.test");
+ parent.writeHeapType(curr->ref->type.getHeapType());
+ parent.writeHeapType(curr->rtt->type.getHeapType());
}
void BinaryInstWriter::visitRefCast(RefCast* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefCast);
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ parent.writeHeapType(curr->ref->type.getHeapType());
+ parent.writeHeapType(curr->rtt->type.getHeapType());
}
void BinaryInstWriter::visitBrOnCast(BrOnCast* curr) {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index cf92cf4d3..56cf9c114 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2192,13 +2192,27 @@ void FunctionValidator::visitI31Get(I31Get* curr) {
void FunctionValidator::visitRefTest(RefTest* curr) {
shouldBeTrue(
getModule()->features.hasGC(), curr, "ref.test requires gc to be enabled");
- WASM_UNREACHABLE("TODO (gc): ref.test");
+ if (curr->ref->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->ref->type.isRef(), curr, "ref.test ref must have ref type");
+ }
+ if (curr->rtt->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->rtt->type.isRtt(), curr, "ref.test rtt must have rtt type");
+ }
}
void FunctionValidator::visitRefCast(RefCast* curr) {
shouldBeTrue(
getModule()->features.hasGC(), curr, "ref.cast requires gc to be enabled");
- WASM_UNREACHABLE("TODO (gc): ref.cast");
+ if (curr->ref->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->ref->type.isRef(), curr, "ref.test ref must have ref type");
+ }
+ if (curr->rtt->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->rtt->type.isRtt(), curr, "ref.test rtt must have rtt type");
+ }
}
void FunctionValidator::visitBrOnCast(BrOnCast* curr) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 2eed06981..93a14aecc 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1080,8 +1080,23 @@ void CallRef::finalize(Type type_) {
finalize();
}
-// TODO (gc): ref.test
-// TODO (gc): ref.cast
+void RefTest::finalize() {
+ if (ref->type == Type::unreachable || rtt->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = Type::i32;
+ }
+}
+
+void RefCast::finalize() {
+ if (ref->type == Type::unreachable || rtt->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ // TODO: make non-nullable when we support that
+ type = Type(rtt->type.getHeapType(), /* nullable = */ true);
+ }
+}
+
// TODO (gc): br_on_cast
void RttCanon::finalize() {