summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2022-12-08 11:50:45 -0600
committerGitHub <noreply@github.com>2022-12-08 09:50:45 -0800
commit48959ab5a74d849e9782f54b3535c6fca69d51d7 (patch)
treeb6da926b399636eb2cfc34ce6adbdc24b8488bcc /src
parent2cb5cefb6392619d908ce2ab683815d7e22ac9a5 (diff)
downloadbinaryen-48959ab5a74d849e9782f54b3535c6fca69d51d7.tar.gz
binaryen-48959ab5a74d849e9782f54b3535c6fca69d51d7.tar.bz2
binaryen-48959ab5a74d849e9782f54b3535c6fca69d51d7.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wasm-binary.cpp11
-rw-r--r--src/wasm/wasm-stack.cpp6
-rw-r--r--src/wasm/wasm-validator.cpp61
3 files changed, 44 insertions, 34 deletions
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(),