diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 16 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 12 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 14 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 11 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 46 |
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_*"); } |