summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/wasm-binary.cpp12
-rw-r--r--src/wasm/wasm-s-parser.cpp10
-rw-r--r--src/wasm/wasm-stack.cpp10
-rw-r--r--src/wasm/wasm-validator.cpp24
-rw-r--r--src/wasm/wasm.cpp29
5 files changed, 64 insertions, 21 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index a4d652608..70aaa6a61 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -5678,10 +5678,14 @@ bool WasmBinaryBuilder::maybeVisitBrOnCast(Expression*& out, uint32_t code) {
if (code != BinaryConsts::BrOnCast) {
return false;
}
- auto* curr = allocator.alloc<BrOnCast>();
- WASM_UNREACHABLE("TODO (gc): br_on_cast");
- curr->finalize();
- out = curr;
+ auto name = getBreakTarget(getU32LEB()).name;
+ auto heapType1 = getHeapType();
+ auto heapType2 = getHeapType();
+ auto* ref = popNonVoidExpression();
+ validateHeapTypeUsingChild(ref, heapType1);
+ auto* rtt = popNonVoidExpression();
+ validateHeapTypeUsingChild(rtt, heapType2);
+ out = Builder(wasm).makeBrOnCast(name, heapType2, ref, rtt);
return true;
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index c1c227d21..32b62d0e1 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2108,10 +2108,12 @@ Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
}
Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s) {
- auto ret = allocator.alloc<BrOnCast>();
- WASM_UNREACHABLE("TODO (gc): br_on_cast");
- ret->finalize();
- return ret;
+ auto name = getLabel(*s[1]);
+ auto heapType = parseHeapType(*s[2]);
+ auto* ref = parseExpression(*s[3]);
+ auto* rtt = parseExpression(*s[4]);
+ validateHeapTypeUsingChild(rtt, heapType, s);
+ return Builder(wasm).makeBrOnCast(name, heapType, ref, rtt);
}
Expression* SExpressionWasmBuilder::makeRttCanon(Element& s) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 3a24d0cc0..6af7279bb 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1918,18 +1918,20 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) {
void BinaryInstWriter::visitRefTest(RefTest* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefTest);
parent.writeHeapType(curr->ref->type.getHeapType());
- parent.writeHeapType(curr->rtt->type.getHeapType());
+ parent.writeHeapType(curr->getCastType().getHeapType());
}
void BinaryInstWriter::visitRefCast(RefCast* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefCast);
parent.writeHeapType(curr->ref->type.getHeapType());
- parent.writeHeapType(curr->rtt->type.getHeapType());
+ parent.writeHeapType(curr->getCastType().getHeapType());
}
void BinaryInstWriter::visitBrOnCast(BrOnCast* curr) {
- o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnCast);
- WASM_UNREACHABLE("TODO (gc): br_on_cast");
+ o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnCast)
+ << U32LEB(getBreakIndex(curr->name));
+ parent.writeHeapType(curr->ref->type.getHeapType());
+ parent.writeHeapType(curr->getCastType().getHeapType());
}
void BinaryInstWriter::visitRttCanon(RttCanon* curr) {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index f110faf56..edcf3676d 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2214,11 +2214,11 @@ void FunctionValidator::visitRefCast(RefCast* curr) {
getModule()->features.hasGC(), curr, "ref.cast requires gc to be enabled");
if (curr->ref->type != Type::unreachable) {
shouldBeTrue(
- curr->ref->type.isRef(), curr, "ref.test ref must have ref type");
+ curr->ref->type.isRef(), curr, "ref.cast ref must have ref type");
}
if (curr->rtt->type != Type::unreachable) {
shouldBeTrue(
- curr->rtt->type.isRtt(), curr, "ref.test rtt must have rtt type");
+ curr->rtt->type.isRtt(), curr, "ref.cast rtt must have rtt type");
}
}
@@ -2226,7 +2226,19 @@ void FunctionValidator::visitBrOnCast(BrOnCast* curr) {
shouldBeTrue(getModule()->features.hasGC(),
curr,
"br_on_cast requires gc to be enabled");
- WASM_UNREACHABLE("TODO (gc): br_on_cast");
+ if (curr->ref->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->ref->type.isRef(), curr, "br_on_cast ref must have ref type");
+ }
+ if (curr->rtt->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->rtt->type.isRtt(), curr, "br_on_cast rtt must have rtt type");
+ shouldBeEqual(curr->rtt->type.getHeapType(),
+ curr->castType.getHeapType(),
+ curr,
+ "br_on_cast rtt must have the proper heap type");
+ noteBreak(curr->name, Type(curr->rtt->type.getHeapType(), Nullable), curr);
+ }
}
void FunctionValidator::visitRttCanon(RttCanon* curr) {
@@ -2368,15 +2380,15 @@ void FunctionValidator::visitArrayGet(ArrayGet* curr) {
getModule()->features.hasGC(), curr, "array.get requires gc to be enabled");
shouldBeEqualOrFirstIsUnreachable(
curr->index->type, Type(Type::i32), curr, "array.get index must be an i32");
+ if (curr->type == Type::unreachable) {
+ return;
+ }
const auto& element = curr->ref->type.getHeapType().getArray().element;
// If the type is not packed, it must be marked internally as unsigned, by
// convention.
if (element.type != Type::i32 || element.packedType == Field::not_packed) {
shouldBeFalse(curr->signed_, curr, "non-packed get cannot be signed");
}
- if (curr->type == Type::unreachable) {
- return;
- }
shouldBeEqual(
curr->type, element.type, curr, "array.get must have the proper type");
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 90120233d..436eedb2b 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1023,16 +1023,39 @@ void RefTest::finalize() {
}
}
+// Helper to get the cast type for a cast instruction. They all look at the rtt
+// operand's type.
+template<typename T> static Type doGetCastType(T* curr) {
+ if (curr->rtt->type == Type::unreachable) {
+ // We don't have the RTT type, so just return unreachable. The type in this
+ // case should not matter in practice, but it may be seen while debugging.
+ return Type::unreachable;
+ }
+ // TODO: make non-nullable when we support that
+ return Type(curr->rtt->type.getHeapType(), Nullable);
+}
+
+Type RefTest::getCastType() { return doGetCastType(this); }
+
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);
+ type = getCastType();
+ }
+}
+
+Type RefCast::getCastType() { return doGetCastType(this); }
+
+void BrOnCast::finalize() {
+ if (ref->type == Type::unreachable || rtt->type == Type::unreachable) {
+ type = Type::unreachable;
+ } else {
+ type = ref->type;
}
}
-// TODO (gc): br_on_cast
+Type BrOnCast::getCastType() { return castType; }
void RttCanon::finalize() {
// Nothing to do - the type must have been set already during construction.