diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 10 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 10 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 24 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 29 |
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. |