diff --git a/src/analysis/lattices/conetype.h b/src/analysis/lattices/conetype.h index 2f2bda74b2c..25b469f38f7 100644 --- a/src/analysis/lattices/conetype.h +++ b/src/analysis/lattices/conetype.h @@ -47,7 +47,7 @@ struct ConeType { Element get(Type type) const noexcept { assert(!type.isTuple()); - if (!type.isRef() || type.isExact() || type.isNull() || + if (!type.isRef() || type.isExact() || type.isBottomRef() || type.getHeapType().isMaybeShared(HeapType::i31)) { return Element{type, 0}; } @@ -69,10 +69,10 @@ struct ConeType { return changed; } Index joineeToLub = 0, joinerToLub = 0; - if (!joinee.isBottom() && !joinee.type.isNull()) { + if (!joinee.isBottom() && !joinee.type.isBottomRef()) { joineeToLub = depthToSuper(joinee, lub); } - if (!joiner.isBottom() && !joiner.type.isNull()) { + if (!joiner.isBottom() && !joiner.type.isBottomRef()) { joinerToLub = depthToSuper(joiner, lub); } Index newDepth = @@ -102,7 +102,7 @@ struct ConeType { } Index newDepth; auto glb = Type::getGreatestLowerBound(meetee.type, meeter.type); - if (glb == Type::unreachable || glb.isNull()) { + if (glb == Type::unreachable || glb.isBottomRef()) { newDepth = 0; } else if (HeapType::isSubType(meetee.type.getHeapType(), meeter.type.getHeapType())) { @@ -146,14 +146,14 @@ struct ConeType { return a.depth < b.depth ? analysis::LESS : analysis::GREATER; } if (Type::isSubType(a.type, b.type)) { - if (a.type.isNull()) { + if (a.type.isBottomRef()) { return analysis::LESS; } Index diff = depthToSuper(a, b.type); return a.depth + diff <= b.depth ? analysis::LESS : analysis::NO_RELATION; } if (Type::isSubType(b.type, a.type)) { - if (b.type.isNull()) { + if (b.type.isBottomRef()) { return analysis::GREATER; } Index diff = depthToSuper(b, a.type); diff --git a/src/ir/effects.h b/src/ir/effects.h index 2e32cfa7a25..bd61f3c942b 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -697,7 +697,7 @@ class EffectAnalyzer { return true; } assert(type.isRef()); - if (type.isNull()) { + if (type.isBottomRef()) { parent.trap = true; return true; } @@ -1175,7 +1175,7 @@ class EffectAnalyzer { } void visitArrayStore(ArrayStore* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { parent.trap = true; return; } diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h index 4424944b8d2..e102856cde6 100644 --- a/src/ir/gc-type-utils.h +++ b/src/ir/gc-type-utils.h @@ -22,7 +22,7 @@ namespace wasm::GCTypeUtils { inline bool isUninhabitable(Type type) { - return type.isNonNullableRef() && type.getHeapType().isBottom(); + return type.isNonNullableRef() && type.isBottomRef(); } // Helper code to evaluate a reference at compile time and check if it is of a @@ -82,9 +82,7 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { return Unreachable; } - auto refHeapType = refType.getHeapType(); - - if (castType.isNonNullableRef() && refHeapType.isBottom()) { + if (castType.isNonNullableRef() && refType.isBottomRef()) { // Non-null references to bottom types do not exist, so there's no value // that could make the cast succeed. // @@ -103,8 +101,6 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { return Failure; } - auto castHeapType = castType.getHeapType(); - // Check whether a value of type `a` is known to also have type `b`, assuming // it is non-null. auto isHeapSubtype = [](Type a, Type b) { @@ -138,7 +134,7 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { auto castIsHeapSubType = isHeapSubtype(castType, refType); bool heapTypesCompatible = refIsHeapSubType || castIsHeapSubType; - if (!heapTypesCompatible || castHeapType.isBottom()) { + if (!heapTypesCompatible || castType.isBottomRef()) { // If the heap types are incompatible or if it is impossible to have a // non-null reference to the target heap type, then the only way the cast // can succeed is if it allows nulls and the input is null. diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 4570cb3b3d6..43655f20a5f 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -204,7 +204,7 @@ void PossibleContents::intersect(const PossibleContents& other) { } }; - if (newType == Type::unreachable || newType.isNull()) { + if (newType == Type::unreachable || newType.isBottomRef()) { setNoneOrNull(); return; } @@ -3182,7 +3182,7 @@ void Flower::filterPackedDataReads(PossibleContents& contents, } // If there is no struct or array to read, no value will ever be returned. - if (ref->type.isNull()) { + if (ref->type.isBottomRef()) { contents = PossibleContents::none(); return; } diff --git a/src/ir/properties.h b/src/ir/properties.h index 59c35cf9cae..bbad0cf726a 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -537,7 +537,7 @@ inline bool hasUnwritableTypeImmediate(Expression* curr) { #define DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(id, field) \ if (curr->cast()->field) { \ auto type = curr->cast()->field->type; \ - if (type == Type::unreachable || type.isNull()) { \ + if (type == Type::unreachable || type.isBottomRef()) { \ return true; \ } \ } diff --git a/src/ir/struct-utils.h b/src/ir/struct-utils.h index b4c69986fde..452fe42603c 100644 --- a/src/ir/struct-utils.h +++ b/src/ir/struct-utils.h @@ -222,7 +222,7 @@ struct StructScanner : public WalkerPass> { void visitStructSet(StructSet* curr) { auto type = curr->ref->type; - if (type == Type::unreachable || type.isNull()) { + if (type == Type::unreachable || type.isBottomRef()) { return; } @@ -237,7 +237,7 @@ struct StructScanner : public WalkerPass> { void visitStructGet(StructGet* curr) { auto type = curr->ref->type; - if (type == Type::unreachable || type.isNull()) { + if (type == Type::unreachable || type.isBottomRef()) { return; } @@ -250,7 +250,7 @@ struct StructScanner : public WalkerPass> { void visitStructWait(StructWait* curr) { auto type = curr->ref->type; - if (type == Type::unreachable || type.isNull()) { + if (type == Type::unreachable || type.isBottomRef()) { return; } @@ -263,7 +263,7 @@ struct StructScanner : public WalkerPass> { void visitStructRMW(StructRMW* curr) { auto type = curr->ref->type; - if (type == Type::unreachable || type.isNull()) { + if (type == Type::unreachable || type.isBottomRef()) { return; } @@ -286,7 +286,7 @@ struct StructScanner : public WalkerPass> { void visitStructCmpxchg(StructCmpxchg* curr) { auto type = curr->ref->type; - if (type == Type::unreachable || type.isNull()) { + if (type == Type::unreachable || type.isBottomRef()) { return; } diff --git a/src/literal.h b/src/literal.h index 07352a6eab8..b41dbb15cb4 100644 --- a/src/literal.h +++ b/src/literal.h @@ -108,7 +108,7 @@ class Literal { bool isContinuation() const { return type.isContinuation(); } bool isString() const { return type.isString(); } - bool isNull() const { return type.isNull(); } + bool isNull() const { return type.isBottomRef(); } bool isZero() const { switch (type.getBasic()) { diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 6957afa689e..ed948d745ad 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -38,6 +38,7 @@ #include #include +#include "ir/gc-type-utils.h" #include "ir/lubs.h" #include "ir/return-utils.h" #include "ir/type-updating.h" @@ -551,7 +552,7 @@ struct DAE : public Pass { // Do this for more complicated uninhabitable types such as non-nullable // references to structs with non-nullable reference cycles. bool wasReturnUninhabitable = - func->getResults().isNull() && func->getResults().isNonNullableRef(); + GCTypeUtils::isUninhabitable(func->getResults()); func->setResults(Type::none); // Remove the drops on the calls. Note that we must do this before updating // returns in ReturnUpdater, as there may be recursive calls of this diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 6937da2ef2e..fc06b1da524 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1768,7 +1768,8 @@ struct OptimizeInstructions // function and the null does not actually flow out. We can only optimize // here if a null definitely flows out (as only that would cause a trap). auto flowsOutNull = [&](Expression* child) { - return child->type.isNull() && !effects(child).transfersControlFlow(); + return child->type.isBottomRef() && + !effects(child).transfersControlFlow(); }; if (auto* iff = ref->dynCast()) { @@ -1859,7 +1860,7 @@ struct OptimizeInstructions auto fallthrough = getFallthrough(ref); - if (fallthrough->type.isNull()) { + if (fallthrough->type.isBottomRef()) { replaceCurrent( getDroppedChildrenAndAppend(curr, builder.makeUnreachable())); return true; @@ -2497,7 +2498,7 @@ struct OptimizeInstructions // null, because then we never get around to comparing the // descriptors. We still need to preserve the trap on null // descriptors, though. - if (refType.isNull()) { + if (refType.isBottomRef()) { assert(curr->type.isNullableRef()); if (curr->desc->type.isNullableRef()) { curr->desc = builder.makeRefAs(RefAsNonNull, curr->desc); @@ -2554,7 +2555,7 @@ struct OptimizeInstructions // because the intermediate expressions might have had side effects or // we need to check exactness. We can replace the cast with a drop // followed by a direct return of the value, though. - if (ref->type.isNull()) { + if (ref->type.isBottomRef()) { // We can materialize the resulting null value directly. // // The type must be nullable for us to do that, which it normally @@ -2615,7 +2616,7 @@ struct OptimizeInstructions // In this case, the cast succeeds because the value must be null, so we // can fall through to handle that case. assert(Type::isSubType(refType, ref->type)); - assert(refType.getHeapType().isBottom()); + assert(refType.isBottomRef()); } [[fallthrough]]; case GCTypeUtils::SuccessOnlyIfNull: { diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index a1357e6475c..35f66ccff3a 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -148,7 +148,7 @@ class PrecomputingExpressionRunner return Flow(NONCONSTANT_FLOW); } Flow visitStructGet(StructGet* curr) { - if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) { + if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) { return Flow(NONCONSTANT_FLOW); } switch (curr->order) { @@ -193,7 +193,7 @@ class PrecomputingExpressionRunner Flow visitArrayRMW(ArrayRMW* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayCmpxchg(ArrayCmpxchg* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayGet(ArrayGet* curr) { - if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) { + if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) { return Flow(NONCONSTANT_FLOW); } switch (curr->order) { diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 797a000ae8b..7015c224bfb 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -922,7 +922,7 @@ struct RemoveUnusedBrs : public WalkerPass> { switch (curr->op) { case BrOnNull: - if (refType.isNull()) { + if (refType.isBottomRef()) { // The branch will definitely be taken. replaceCurrent(builder.makeSequence( builder.makeDrop(curr->ref), builder.makeBreak(curr->name))); @@ -937,7 +937,7 @@ struct RemoveUnusedBrs : public WalkerPass> { } return; case BrOnNonNull: - if (refType.isNull()) { + if (refType.isBottomRef()) { // Definitely not taken. replaceCurrent(builder.makeDrop(curr->ref)); worked = true; diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 1f97b01ddba..9b58c52b789 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -197,7 +197,7 @@ struct Noter : public PostWalker> { } void visitStructGet(StructGet* curr) { - if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) { + if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) { return; } auto type = curr->ref->type.getHeapType(); diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp index 2d116748daf..bba1e2cba2d 100644 --- a/src/passes/TypeRefining.cpp +++ b/src/passes/TypeRefining.cpp @@ -262,7 +262,7 @@ struct TypeRefining : public Pass { auto& infos = finalInfos[{type, Inexact}]; for (Index i = 0; i < fields.size(); i++) { auto lub = infos[i].getLUB(); - if (lub.isRef() && !lub.isCastable() && !lub.isNull()) { + if (lub.isRef() && !lub.isCastable() && !lub.isBottomRef()) { infos[i] = LUBFinder(fields[i].type); } } @@ -413,13 +413,14 @@ struct TypeRefining : public Pass { } Type newFieldType; - if (!curr->ref->type.isNull()) { + if (!curr->ref->type.isBottomRef()) { auto oldType = curr->ref->type.getHeapType(); newFieldType = parent.finalInfos[{oldType, Inexact}][curr->index].getLUB(); } - if (curr->ref->type.isNull() || newFieldType == Type::unreachable || + if (curr->ref->type.isBottomRef() || + newFieldType == Type::unreachable || !Type::isSubType(newFieldType, curr->type)) { // This get will trap, or cannot be reached: either the ref is null, // or the field is never written any contents, or the contents we see diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp index ce72f853503..ffe450f7f5d 100644 --- a/src/tools/fuzzing/heap-types.cpp +++ b/src/tools/fuzzing/heap-types.cpp @@ -1027,7 +1027,7 @@ void Inhabitator::markBottomRefsNullable() { auto children = type.getTypeChildren(); for (size_t i = 0; i < children.size(); ++i) { auto child = children[i]; - if (child.isNonNullableRef() && child.getHeapType().isBottom()) { + if (child.isNonNullableRef() && child.isBottomRef()) { markNullable({type, i}); } } @@ -1400,9 +1400,11 @@ bool isUninhabitable(HeapType type, bool isUninhabitable(Type type, std::unordered_set& visited, std::unordered_set& visiting) { + if (GCTypeUtils::isUninhabitable(type)) { + return true; + } if (type.isNonNullableRef()) { - if (type.getHeapType().isBottom() || - type.getHeapType().isMaybeShared(HeapType::ext)) { + if (type.getHeapType().isMaybeShared(HeapType::ext)) { return true; } return isUninhabitable(type.getHeapType(), visited, visiting); diff --git a/src/wasm-type.h b/src/wasm-type.h index a7cf42e3fdc..123b4ddf60b 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -412,9 +412,7 @@ class Type { bool isFunction() const { return isRef() && getHeapType().isFunction(); } bool isSignature() const { return isRef() && getHeapType().isSignature(); } bool isData() const { return isRef() && getHeapType().isData(); } - - // Whether this type is only inhabited by null values. - bool isNull() const { return isRef() && getHeapType().isBottom(); } + bool isBottomRef() const { return isRef() && getHeapType().isBottom(); } bool isStruct() const { return isRef() && getHeapType().isStruct(); } bool isArray() const { return isRef() && getHeapType().isArray(); } bool isExn() const { return isRef() && getHeapType().isExn(); } diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 21881a8f578..5f20800ad3f 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -52,7 +52,7 @@ Literal::Literal(Type type) : type(type) { } } - if (type.isNull()) { + if (type.isBottomRef()) { assert(type.isNullableRef() && !type.isExact()); new (&gcData) std::shared_ptr(); return; @@ -503,8 +503,7 @@ bool Literal::operator==(const Literal& other) const { break; } } else if (type.isRef()) { - assert(type.isRef()); - if (type.isNull()) { + if (type.isBottomRef()) { return true; } if (type.isFunction()) { @@ -567,7 +566,7 @@ bool Literal::operator<(const Literal& other) const { } assert(type.isRef()); - if (type.isNull()) { + if (type.isBottomRef()) { // All nulls are equal, and hence not < return false; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index af68726e4b9..8e0e650de96 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2550,7 +2550,7 @@ void BinaryInstWriter::visitI31Get(I31Get* curr) { void BinaryInstWriter::visitCallRef(CallRef* curr) { assert(curr->target->type != Type::unreachable); - if (curr->target->type.isNull()) { + if (curr->target->type.isBottomRef()) { emitUnreachable(); return; } @@ -2571,7 +2571,7 @@ void BinaryInstWriter::visitRefTest(RefTest* curr) { } void BinaryInstWriter::visitRefCast(RefCast* curr) { - if (curr->desc && curr->desc->type.isNull()) { + if (curr->desc && curr->desc->type.isBottomRef()) { emitUnreachable(); return; } @@ -2593,7 +2593,7 @@ void BinaryInstWriter::visitRefCast(RefCast* curr) { } void BinaryInstWriter::visitRefGetDesc(RefGetDesc* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2604,7 +2604,7 @@ void BinaryInstWriter::visitRefGetDesc(RefGetDesc* curr) { void BinaryInstWriter::visitBrOn(BrOn* curr) { bool hasDesc = curr->op == BrOnCastDescEq || curr->op == BrOnCastDescEqFail; - if (hasDesc && curr->desc->type.isNull()) { + if (hasDesc && curr->desc->type.isBottomRef()) { emitUnreachable(); return; } @@ -2666,7 +2666,7 @@ void BinaryInstWriter::visitStructNew(StructNew* curr) { } void BinaryInstWriter::visitStructGet(StructGet* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2691,7 +2691,7 @@ void BinaryInstWriter::visitStructGet(StructGet* curr) { } void BinaryInstWriter::visitStructSet(StructSet* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2708,7 +2708,7 @@ void BinaryInstWriter::visitStructSet(StructSet* curr) { } void BinaryInstWriter::visitStructRMW(StructRMW* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2739,7 +2739,7 @@ void BinaryInstWriter::visitStructRMW(StructRMW* curr) { } void BinaryInstWriter::visitStructCmpxchg(StructCmpxchg* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2751,7 +2751,7 @@ void BinaryInstWriter::visitStructCmpxchg(StructCmpxchg* curr) { } void BinaryInstWriter::visitStructWait(StructWait* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2808,7 +2808,7 @@ void BinaryInstWriter::visitArrayNewFixed(ArrayNewFixed* curr) { } void BinaryInstWriter::visitArrayGet(ArrayGet* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2832,7 +2832,7 @@ void BinaryInstWriter::visitArrayGet(ArrayGet* curr) { } void BinaryInstWriter::visitArraySet(ArraySet* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2851,7 +2851,7 @@ void BinaryInstWriter::visitArrayLoad(ArrayLoad* curr) { if (curr->type == Type::unreachable) { return; } - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2867,7 +2867,7 @@ void BinaryInstWriter::visitArrayStore(ArrayStore* curr) { if (curr->type == Type::unreachable) { return; } - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2885,7 +2885,7 @@ void BinaryInstWriter::visitArrayLen(ArrayLen* curr) { } void BinaryInstWriter::visitArrayCopy(ArrayCopy* curr) { - if (curr->srcRef->type.isNull() || curr->destRef->type.isNull()) { + if (curr->srcRef->type.isBottomRef() || curr->destRef->type.isBottomRef()) { emitUnreachable(); return; } @@ -2896,7 +2896,7 @@ void BinaryInstWriter::visitArrayCopy(ArrayCopy* curr) { } void BinaryInstWriter::visitArrayFill(ArrayFill* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2906,7 +2906,7 @@ void BinaryInstWriter::visitArrayFill(ArrayFill* curr) { } void BinaryInstWriter::visitArrayInitData(ArrayInitData* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2917,7 +2917,7 @@ void BinaryInstWriter::visitArrayInitData(ArrayInitData* curr) { } void BinaryInstWriter::visitArrayInitElem(ArrayInitElem* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2928,7 +2928,7 @@ void BinaryInstWriter::visitArrayInitElem(ArrayInitElem* curr) { } void BinaryInstWriter::visitArrayRMW(ArrayRMW* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2958,7 +2958,7 @@ void BinaryInstWriter::visitArrayRMW(ArrayRMW* curr) { } void BinaryInstWriter::visitArrayCmpxchg(ArrayCmpxchg* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { emitUnreachable(); return; } @@ -2987,7 +2987,7 @@ void BinaryInstWriter::visitRefAs(RefAs* curr) { } void BinaryInstWriter::visitStringNew(StringNew* curr) { - if (curr->ref->type.isNull()) { + if (curr->ref->type.isBottomRef()) { // This is a bottom type, so this is an array-receiving operation that does // not receive an array. The spec allows this, but V8 does not, see // https://github.com/WebAssembly/stringref/issues/66 @@ -3032,7 +3032,7 @@ void BinaryInstWriter::visitStringMeasure(StringMeasure* curr) { } void BinaryInstWriter::visitStringEncode(StringEncode* curr) { - if (curr->str->type.isNull()) { + if (curr->str->type.isBottomRef()) { // See visitStringNew. emitUnreachable(); return; @@ -3142,7 +3142,7 @@ void BinaryInstWriter::visitSuspend(Suspend* curr) { } void BinaryInstWriter::visitContBind(ContBind* curr) { - if (curr->cont->type.isNull()) { + if (curr->cont->type.isBottomRef()) { emitUnreachable(); return; } @@ -3152,7 +3152,7 @@ void BinaryInstWriter::visitContBind(ContBind* curr) { } void BinaryInstWriter::visitResume(Resume* curr) { - if (curr->cont->type.isNull()) { + if (curr->cont->type.isBottomRef()) { emitUnreachable(); return; } @@ -3176,7 +3176,7 @@ void BinaryInstWriter::visitResume(Resume* curr) { } void BinaryInstWriter::visitResumeThrow(ResumeThrow* curr) { - if (curr->cont->type.isNull()) { + if (curr->cont->type.isBottomRef()) { emitUnreachable(); return; } @@ -3204,7 +3204,7 @@ void BinaryInstWriter::visitResumeThrow(ResumeThrow* curr) { } void BinaryInstWriter::visitStackSwitch(StackSwitch* curr) { - if (curr->cont->type.isNull()) { + if (curr->cont->type.isBottomRef()) { emitUnreachable(); return; } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 5f54af90018..e765945cabe 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2601,7 +2601,7 @@ void FunctionValidator::visitRefNull(RefNull* curr) { return; } shouldBeTrue( - curr->type.isNull(), curr, "ref.null must have a bottom heap type"); + curr->type.isBottomRef(), curr, "ref.null must have a bottom heap type"); } void FunctionValidator::visitRefIsNull(RefIsNull* curr) { @@ -3253,10 +3253,10 @@ void FunctionValidator::visitRefCast(RefCast* curr) { // Require descriptors to be valid even if the ref is unreachable. if (curr->desc && curr->desc->type != Type::unreachable) { auto descType = curr->desc->type; - bool isNull = descType.isNull(); + bool isBottom = descType.isBottomRef(); bool isDescriptor = descType.isRef() && descType.getHeapType().getDescribedType(); - shouldBeTrue(isNull || isDescriptor, + shouldBeTrue(isBottom || isDescriptor, curr, "ref.cast_desc_eq descriptor must be a descriptor reference"); } @@ -3513,7 +3513,7 @@ void FunctionValidator::visitStructGet(StructGet* curr) { curr, "struct.atomic.get requires threads [--enable-threads]"); } - if (curr->type == Type::unreachable || curr->ref->type.isNull()) { + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef()) { return; } if (!shouldBeTrue(curr->ref->type.isStruct(), @@ -3713,7 +3713,7 @@ void FunctionValidator::visitStructWait(StructWait* curr) { curr, "struct.wait timeout must be an i64"); - if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) { + if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) { return; } if (!shouldBeTrue(curr->ref->type.isStruct(), @@ -3946,9 +3946,7 @@ void FunctionValidator::visitArrayGet(ArrayGet* curr) { curr->index->type, Type(Type::i32), curr, "array.get index must be an i32"); const char* mustBeArray = "array.get target should be a specific array reference"; - if (curr->type == Type::unreachable || - !shouldBeTrue(curr->ref->type.isRef(), curr, mustBeArray) || - curr->ref->type.getHeapType().isBottom() || + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef() || !shouldBeTrue(curr->ref->type.isArray(), curr, mustBeArray)) { return; } @@ -3972,9 +3970,7 @@ void FunctionValidator::visitArraySet(ArraySet* curr) { return; } const char* mustBeArray = "array.set target should be an array reference"; - if (curr->type == Type::unreachable || - !shouldBeTrue(curr->ref->type.isRef(), curr, mustBeArray) || - curr->ref->type.getHeapType().isBottom() || + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef() || !shouldBeTrue(curr->ref->type.isArray(), curr, mustBeArray)) { return; } @@ -4007,9 +4003,7 @@ void FunctionValidator::visitArrayLoad(ArrayLoad* curr) { return; } const char* mustBeArray = "array load target should be an array reference"; - if (curr->type == Type::unreachable || - !shouldBeTrue(curr->ref->type.isRef(), curr, mustBeArray) || - curr->ref->type.getHeapType().isBottom() || + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef() || !shouldBeTrue(curr->ref->type.isArray(), curr, mustBeArray)) { return; } @@ -4037,9 +4031,7 @@ void FunctionValidator::visitArrayStore(ArrayStore* curr) { return; } const char* mustBeArray = "array store target should be an array reference"; - if (curr->type == Type::unreachable || - !shouldBeTrue(curr->ref->type.isRef(), curr, mustBeArray) || - curr->ref->type.getHeapType().isBottom() || + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef() || !shouldBeTrue(curr->ref->type.isArray(), curr, mustBeArray)) { return; } @@ -4133,9 +4125,7 @@ void FunctionValidator::visitArrayFill(ArrayFill* curr) { curr->size->type, Type(Type::i32), curr, "array.fill size must be an i32"); const char* mustBeArray = "array.fill destination should be an array reference"; - if (curr->type == Type::unreachable || - !shouldBeTrue(curr->ref->type.isRef(), curr, mustBeArray) || - curr->ref->type.getHeapType().isBottom() || + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef() || !shouldBeTrue(curr->ref->type.isArray(), curr, mustBeArray)) { return; } @@ -4168,9 +4158,7 @@ void FunctionValidator::visitArrayInit(ArrayInit* curr) { "array.init_* size must be an i32"); const char* mustBeArray = "array.init_* destination must be an array reference"; - if (curr->type == Type::unreachable || - !shouldBeTrue(curr->ref->type.isRef(), curr, mustBeArray) || - curr->ref->type.getHeapType().isBottom() || + if (curr->type == Type::unreachable || curr->ref->type.isBottomRef() || !shouldBeTrue(curr->ref->type.isArray(), curr, mustBeArray)) { return; } diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 0225e3dbb56..d3156275425 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1081,7 +1081,7 @@ void CallRef::finalize() { return; } assert(target->type.isRef()); - if (target->type.isNull()) { + if (target->type.isBottomRef()) { type = getMaximallyUninhabitable(type); return; } @@ -1112,7 +1112,7 @@ void RefCast::finalize() { } if (desc) { - if (desc->type.isNull()) { + if (desc->type.isBottomRef()) { // Cast will never be executed and the instruction will not be emitted. // Model this with an uninhabitable cast type. type = desc->type.with(NonNullable); @@ -1151,7 +1151,7 @@ void RefGetDesc::finalize() { return; } - if (ref->type.isNull()) { + if (ref->type.isBottomRef()) { // The operation will trap. Model it as returning an uninhabitable type. type = ref->type.with(NonNullable); } else { @@ -1182,7 +1182,7 @@ void BrOn::finalize() { castType = newCastType; assert(castType.isRef()); } else if (op == BrOnCastDescEq || op == BrOnCastDescEqFail) { - if (desc->type.isNull()) { + if (desc->type.isBottomRef()) { // Cast will never be executed and the instruction will not be emitted. // Model this with an uninhabitable cast type. castType = desc->type.with(NonNullable); @@ -1214,7 +1214,7 @@ void BrOn::finalize() { if (castType.isNullableRef()) { // Nulls take the branch, so the result is non-nullable. type = ref->type.with(NonNullable); - } else if (desc && desc->type.isNull()) { + } else if (desc && desc->type.isBottomRef()) { // Cast will never be executed and the instruction will not be emitted. // Model this with an uninhabitable result type. type = desc->type.with(NonNullable); @@ -1266,7 +1266,7 @@ Type BrOn::getSentType() { if (ref->type == Type::unreachable) { return Type::unreachable; } - if (desc && desc->type.isNull()) { + if (desc && desc->type.isBottomRef()) { // Cast will never be executed and the branch will not be taken. // Model this with an uninhabitable sent type. return desc->type.with(NonNullable); @@ -1292,7 +1292,7 @@ void StructNew::finalize() { void StructGet::finalize() { if (ref->type == Type::unreachable) { type = Type::unreachable; - } else if (ref->type.isNull()) { + } else if (ref->type.isBottomRef()) { // See comment on CallRef for explanation. if (type.isRef()) { // TODO: Make this exact. @@ -1314,7 +1314,7 @@ void StructSet::finalize() { void StructRMW::finalize() { if (ref->type == Type::unreachable || value->type == Type::unreachable) { type = Type::unreachable; - } else if (ref->type.isNull()) { + } else if (ref->type.isBottomRef()) { // We have no struct type to read the field off of, but the most precise // possible option is the type of the value we are using to make the // modification. @@ -1328,7 +1328,7 @@ void StructCmpxchg::finalize() { if (ref->type == Type::unreachable || expected->type == Type::unreachable || replacement->type == Type::unreachable) { type = Type::unreachable; - } else if (ref->type.isNull()) { + } else if (ref->type.isBottomRef()) { type = replacement->type; } else { type = ref->type.getHeapType().getStruct().fields[index].type; @@ -1391,7 +1391,7 @@ void ArrayNewFixed::finalize() { void ArrayGet::finalize() { if (ref->type == Type::unreachable || index->type == Type::unreachable) { type = Type::unreachable; - } else if (ref->type.isNull()) { + } else if (ref->type.isBottomRef()) { // See comment on CallRef for explanation. if (type.isRef()) { // TODO: Make this exact. @@ -1477,7 +1477,7 @@ void ArrayRMW::finalize() { if (ref->type == Type::unreachable || index->type == Type::unreachable || value->type == Type::unreachable) { type = Type::unreachable; - } else if (ref->type.isNull()) { + } else if (ref->type.isBottomRef()) { // We have no array type to read the field off of, but the most precise // possible option is the type of the value we are using to make the // modification. @@ -1492,7 +1492,7 @@ void ArrayCmpxchg::finalize() { expected->type == Type::unreachable || replacement->type == Type::unreachable) { type = Type::unreachable; - } else if (ref->type.isNull()) { + } else if (ref->type.isBottomRef()) { type = replacement->type; } else { type = ref->type.getHeapType().getArray().element.type; @@ -1637,7 +1637,7 @@ void Resume::finalize() { if (handleUnreachableOperands(this)) { return; } - if (cont->type.isNull()) { + if (cont->type.isBottomRef()) { type = getMaximallyUninhabitable(type); return; } @@ -1656,7 +1656,7 @@ void ResumeThrow::finalize() { if (handleUnreachableOperands(this)) { return; } - if (cont->type.isNull()) { + if (cont->type.isBottomRef()) { type = getMaximallyUninhabitable(type); return; } @@ -1675,7 +1675,7 @@ void StackSwitch::finalize() { if (handleUnreachableOperands(this)) { return; } - if (cont->type.isNull()) { + if (cont->type.isBottomRef()) { type = getMaximallyUninhabitable(type); return; }