summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/wasm-binary.cpp16
-rw-r--r--src/wasm/wasm-s-parser.cpp12
-rw-r--r--src/wasm/wasm-stack.cpp14
-rw-r--r--src/wasm/wasm-validator.cpp11
-rw-r--r--src/wasm/wasm.cpp46
5 files changed, 75 insertions, 24 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index c6fb361bd..61fd65eab 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -6931,6 +6931,7 @@ bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) {
bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) {
BrOnOp op;
+ auto nullability = NonNullable;
switch (code) {
case BinaryConsts::BrOnNull:
op = BrOnNull;
@@ -6946,6 +6947,14 @@ bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) {
case BinaryConsts::BrOnCastFail:
op = BrOnCastFail;
break;
+ case BinaryConsts::BrOnCastNull:
+ op = BrOnCast;
+ nullability = Nullable;
+ break;
+ case BinaryConsts::BrOnCastFailNull:
+ op = BrOnCastFail;
+ nullability = Nullable;
+ break;
case BinaryConsts::BrOnFunc:
op = BrOnFunc;
break;
@@ -6968,14 +6977,15 @@ bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) {
return false;
}
auto name = getBreakTarget(getU32LEB()).name;
- HeapType intendedType;
+ Type castType = Type::none;
if (op == BrOnCast || op == BrOnCastFail) {
bool legacy = code == BinaryConsts::BrOnCastStatic ||
code == BinaryConsts::BrOnCastStaticFail;
- intendedType = legacy ? getIndexedHeapType() : getHeapType();
+ auto type = legacy ? getIndexedHeapType() : getHeapType();
+ castType = Type(type, nullability);
}
auto* ref = popNonVoidExpression();
- out = Builder(wasm).makeBrOn(op, name, ref, intendedType);
+ out = Builder(wasm).makeBrOn(op, name, ref, castType);
return true;
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 2f791609a..fd3cbcc23 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2821,12 +2821,18 @@ Expression* SExpressionWasmBuilder::makeRefCastNop(Element& s) {
Expression* SExpressionWasmBuilder::makeBrOn(Element& s, BrOnOp op) {
int i = 1;
auto name = getLabel(*s[i++]);
- HeapType heapType;
+ Type castType = Type::none;
if (op == BrOnCast || op == BrOnCastFail) {
- heapType = parseHeapType(*s[i++]);
+ auto nullability = NonNullable;
+ if (s[i]->str().str == "null") {
+ nullability = Nullable;
+ ++i;
+ }
+ auto type = parseHeapType(*s[i++]);
+ castType = Type(type, nullability);
}
auto* ref = parseExpression(*s[i]);
- return Builder(wasm).makeBrOn(op, name, ref, heapType);
+ return Builder(wasm).makeBrOn(op, name, ref, castType);
}
Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index e24060f2a..fbf73b7c2 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -2058,11 +2058,19 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) {
break;
case BrOnCast:
o << int8_t(BinaryConsts::GCPrefix);
- o << U32LEB(BinaryConsts::BrOnCast);
+ if (curr->castType.isNullable()) {
+ o << U32LEB(BinaryConsts::BrOnCastNull);
+ } else {
+ o << U32LEB(BinaryConsts::BrOnCast);
+ }
break;
case BrOnCastFail:
o << int8_t(BinaryConsts::GCPrefix);
- o << U32LEB(BinaryConsts::BrOnCastFail);
+ if (curr->castType.isNullable()) {
+ o << U32LEB(BinaryConsts::BrOnCastFailNull);
+ } else {
+ o << U32LEB(BinaryConsts::BrOnCastFail);
+ }
break;
case BrOnFunc:
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnFunc);
@@ -2087,7 +2095,7 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) {
}
o << U32LEB(getBreakIndex(curr->name));
if (curr->op == BrOnCast || curr->op == BrOnCastFail) {
- parent.writeHeapType(curr->intendedType);
+ parent.writeHeapType(curr->castType.getHeapType());
}
}
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index bec9b0ad0..486f13d24 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2554,14 +2554,19 @@ void FunctionValidator::visitBrOn(BrOn* curr) {
return;
}
if (curr->op == BrOnCast || curr->op == BrOnCastFail) {
+ if (!shouldBeTrue(curr->castType.isRef(),
+ curr,
+ "br_on_cast must have reference cast type")) {
+ return;
+ }
shouldBeEqual(
- curr->intendedType.getBottom(),
+ curr->castType.getHeapType().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(),
+ shouldBeEqual(curr->castType,
+ Type(Type::none),
curr,
"non-cast br_on* must not set intendedType field");
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 682936461..de18966ff 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -968,18 +968,12 @@ void BrOn::finalize() {
// us flow out the null, but it does not).
type = Type::none;
break;
- case BrOnCast:
case BrOnFunc:
case BrOnData:
case BrOnI31:
// If we do not branch, we return the input in this case.
type = ref->type;
break;
- case BrOnCastFail:
- // If we do not branch, the cast worked, and we have something of the cast
- // type.
- type = Type(intendedType, NonNullable);
- break;
case BrOnNonFunc:
type = Type(HeapType::func, NonNullable);
break;
@@ -989,6 +983,26 @@ void BrOn::finalize() {
case BrOnNonI31:
type = Type(HeapType::i31, NonNullable);
break;
+ case BrOnCast:
+ if (castType.isNullable()) {
+ // Nulls take the branch, so the result is non-nullable.
+ type = Type(ref->type.getHeapType(), NonNullable);
+ } else {
+ // Nulls do not take the branch, so the result is non-nullable only if
+ // the input is.
+ type = ref->type;
+ }
+ break;
+ case BrOnCastFail:
+ if (castType.isNullable()) {
+ // Nulls do not take the branch, so the result is non-nullable only if
+ // the input is.
+ type = Type(castType.getHeapType(), ref->type.getNullability());
+ } else {
+ // Nulls take the branch, so the result is non-nullable.
+ type = castType;
+ }
+ break;
default:
WASM_UNREACHABLE("invalid br_on_*");
}
@@ -1007,22 +1021,30 @@ Type BrOn::getSentType() {
}
// BrOnNonNull sends the non-nullable type on the branch.
return Type(ref->type.getHeapType(), NonNullable);
- case BrOnCast:
- if (ref->type == Type::unreachable) {
- return Type::unreachable;
- }
- return Type(intendedType, NonNullable);
case BrOnFunc:
return Type(HeapType::func, NonNullable);
case BrOnData:
return Type(HeapType::data, NonNullable);
case BrOnI31:
return Type(HeapType::i31, NonNullable);
- case BrOnCastFail:
case BrOnNonFunc:
case BrOnNonData:
case BrOnNonI31:
return ref->type;
+ case BrOnCast:
+ // The same as the result type of br_on_cast_fail.
+ if (castType.isNullable()) {
+ return Type(castType.getHeapType(), ref->type.getNullability());
+ } else {
+ return castType;
+ }
+ case BrOnCastFail:
+ // The same as the result type of br_on_cast.
+ if (castType.isNullable()) {
+ return Type(ref->type.getHeapType(), NonNullable);
+ } else {
+ return ref->type;
+ }
default:
WASM_UNREACHABLE("invalid br_on_*");
}