From 48959ab5a74d849e9782f54b3535c6fca69d51d7 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 8 Dec 2022 11:50:45 -0600 Subject: Allow casting to basic heap types (#5332) The standard casting instructions now allow casting to basic heap types, not just user-defined types, but they also require that the intended type and argument type have a common supertype. Update the validator to use the standard rules, update the binary parser and printer to allow basic types, and update the tests to remove or modify newly invalid test cases. --- src/wasm/wasm-binary.cpp | 11 +++++--- src/wasm/wasm-stack.cpp | 6 ++--- src/wasm/wasm-validator.cpp | 61 ++++++++++++++++++++++++--------------------- 3 files changed, 44 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 7b2922d3c..996ee8cf6 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -6894,7 +6894,8 @@ bool WasmBinaryBuilder::maybeVisitI31Get(Expression*& out, uint32_t code) { bool WasmBinaryBuilder::maybeVisitRefTest(Expression*& out, uint32_t code) { if (code == BinaryConsts::RefTestStatic || code == BinaryConsts::RefTest) { - auto intendedType = getIndexedHeapType(); + bool legacy = code == BinaryConsts::RefTestStatic; + auto intendedType = legacy ? getIndexedHeapType() : getHeapType(); auto* ref = popNonVoidExpression(); out = Builder(wasm).makeRefTest(ref, intendedType); return true; @@ -6905,7 +6906,9 @@ bool WasmBinaryBuilder::maybeVisitRefTest(Expression*& out, uint32_t code) { bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) { if (code == BinaryConsts::RefCastStatic || code == BinaryConsts::RefCastNull || code == BinaryConsts::RefCastNop) { - auto intendedType = getIndexedHeapType(); + bool legacy = + code == BinaryConsts::RefCastStatic || code == BinaryConsts::RefCastNop; + auto intendedType = legacy ? getIndexedHeapType() : getHeapType(); auto* ref = popNonVoidExpression(); auto safety = code == BinaryConsts::RefCastNop ? RefCast::Unsafe : RefCast::Safe; @@ -6956,7 +6959,9 @@ bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) { auto name = getBreakTarget(getU32LEB()).name; HeapType intendedType; if (op == BrOnCast || op == BrOnCastFail) { - intendedType = getIndexedHeapType(); + bool legacy = code == BinaryConsts::BrOnCastStatic || + code == BinaryConsts::BrOnCastStaticFail; + intendedType = legacy ? getIndexedHeapType() : getHeapType(); } auto* ref = popNonVoidExpression(); out = Builder(wasm).makeBrOn(op, name, ref, intendedType); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 1f477a10c..c4b9598c7 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2026,7 +2026,7 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) { void BinaryInstWriter::visitRefTest(RefTest* curr) { o << int8_t(BinaryConsts::GCPrefix); o << U32LEB(BinaryConsts::RefTest); - parent.writeIndexedHeapType(curr->intendedType); + parent.writeHeapType(curr->intendedType); } void BinaryInstWriter::visitRefCast(RefCast* curr) { @@ -2036,7 +2036,7 @@ void BinaryInstWriter::visitRefCast(RefCast* curr) { } else { o << U32LEB(BinaryConsts::RefCastNull); } - parent.writeIndexedHeapType(curr->intendedType); + parent.writeHeapType(curr->intendedType); } void BinaryInstWriter::visitBrOn(BrOn* curr) { @@ -2078,7 +2078,7 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) { } o << U32LEB(getBreakIndex(curr->name)); if (curr->op == BrOnCast || curr->op == BrOnCastFail) { - parent.writeIndexedHeapType(curr->intendedType); + parent.writeHeapType(curr->intendedType); } } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index ba8712d35..16b6f5314 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2504,49 +2504,54 @@ void FunctionValidator::visitI31Get(I31Get* curr) { void FunctionValidator::visitRefTest(RefTest* curr) { shouldBeTrue( getModule()->features.hasGC(), curr, "ref.test requires gc [--enable-gc]"); - if (curr->ref->type != Type::unreachable) { - shouldBeTrue( - curr->ref->type.isRef(), curr, "ref.test ref must have ref type"); + if (curr->ref->type == Type::unreachable) { + return; } - shouldBeUnequal(curr->intendedType, - HeapType(), - curr, - "static ref.test must set intendedType field"); - shouldBeTrue( - !curr->intendedType.isBasic(), curr, "ref.test must test a non-basic"); + if (!shouldBeTrue( + curr->ref->type.isRef(), curr, "ref.test ref must have ref type")) { + return; + } + shouldBeEqual( + curr->intendedType.getBottom(), + curr->ref->type.getHeapType().getBottom(), + curr, + "ref.test target type and ref type must have a common supertype"); } void FunctionValidator::visitRefCast(RefCast* curr) { shouldBeTrue( getModule()->features.hasGC(), curr, "ref.cast requires gc [--enable-gc]"); - if (curr->ref->type != Type::unreachable) { - shouldBeTrue( - curr->ref->type.isRef(), curr, "ref.cast ref must have ref type"); + if (curr->ref->type == Type::unreachable) { + return; } - shouldBeUnequal(curr->intendedType, - HeapType(), - curr, - "static ref.cast must set intendedType field"); - shouldBeTrue( - !curr->intendedType.isBasic(), curr, "ref.cast must cast to a non-basic"); + if (!shouldBeTrue( + curr->ref->type.isRef(), curr, "ref.cast ref must have ref type")) { + return; + } + shouldBeEqual( + curr->intendedType.getBottom(), + curr->ref->type.getHeapType().getBottom(), + curr, + "ref.cast target type and ref type must have a common supertype"); } void FunctionValidator::visitBrOn(BrOn* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, "br_on_cast requires gc [--enable-gc]"); - if (curr->ref->type != Type::unreachable) { - shouldBeTrue( - curr->ref->type.isRef(), curr, "br_on_cast ref must have ref type"); + if (curr->ref->type == Type::unreachable) { + return; + } + if (!shouldBeTrue( + curr->ref->type.isRef(), curr, "br_on_cast ref must have ref type")) { + return; } if (curr->op == BrOnCast || curr->op == BrOnCastFail) { - shouldBeUnequal(curr->intendedType, - HeapType(), - curr, - "static br_on_cast* must set intendedType field"); - shouldBeTrue(!curr->intendedType.isBasic(), - curr, - "br_on_cast* must cast to a non-basic"); + shouldBeEqual( + curr->intendedType.getBottom(), + curr->ref->type.getHeapType().getBottom(), + curr, + "br_on_cast* target type and ref type must have a common supertype"); } else { shouldBeEqual(curr->intendedType, HeapType(), -- cgit v1.2.3