diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 53748beef9d..32d6c0334e0 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -158,7 +158,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { case HeapType::nocont: case HeapType::noexn: case HeapType::nowaitqueue: - assert(type.isNullable()); + assert(type.isNullableRef()); return Literal::makeNull(heapType); } } @@ -397,7 +397,7 @@ BinaryenHeapType BinaryenTypeGetHeapType(BinaryenType type) { return Type(type).getHeapType().getID(); } bool BinaryenTypeIsNullable(BinaryenType type) { - return Type(type).isNullable(); + return Type(type).isNullableRef(); } BinaryenType BinaryenTypeFromHeapType(BinaryenHeapType heapType, bool nullable) { diff --git a/src/ir/LocalStructuralDominance.cpp b/src/ir/LocalStructuralDominance.cpp index 37cd7f4bae6..ade2750c294 100644 --- a/src/ir/LocalStructuralDominance.cpp +++ b/src/ir/LocalStructuralDominance.cpp @@ -47,7 +47,7 @@ LocalStructuralDominance::LocalStructuralDominance(Function* func, for (auto type : var) { // Check if we have any non-nullable vars (or tuple vars with // non-nullable elements) at all. - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { hasNonNullableVar = true; break; } @@ -78,7 +78,7 @@ LocalStructuralDominance::LocalStructuralDominance(Function* func, auto localType = func->getLocalType(i); bool interesting = false; for (auto type : localType) { - if (type.isRef() && (mode == All || type.isNonNullable())) { + if ((mode == All && type.isRef()) || type.isNonNullableRef()) { interesting = true; break; } diff --git a/src/ir/cost.h b/src/ir/cost.h index f2789666369..edc462d765a 100644 --- a/src/ir/cost.h +++ b/src/ir/cost.h @@ -885,7 +885,7 @@ struct CostAnalyzer : public OverriddenVisitor { private: CostType nullCheckCost(Expression* ref) { // A nullable type requires a bounds check in most VMs. - return ref->type.isNullable(); + return ref->type.isNullableRef(); } }; diff --git a/src/ir/effects.h b/src/ir/effects.h index f3504fd4104..2e32cfa7a25 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -701,7 +701,7 @@ class EffectAnalyzer { parent.trap = true; return true; } - if (type.isNullable()) { + if (type.isNullableRef()) { parent.implicitTrap = true; } diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h index f46b1b97179..4424944b8d2 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.isNonNullable() && type.getHeapType().isBottom(); + return type.isNonNullableRef() && type.getHeapType().isBottom(); } // Helper code to evaluate a reference at compile time and check if it is of a @@ -84,7 +84,7 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { auto refHeapType = refType.getHeapType(); - if (castType.isNonNullable() && refHeapType.isBottom()) { + if (castType.isNonNullableRef() && refHeapType.isBottom()) { // Non-null references to bottom types do not exist, so there's no value // that could make the cast succeed. // @@ -123,15 +123,15 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { if (refIsHeapSubType) { // The heap type is a subtype. All we need is for nullability to work out as // well, and then the cast must succeed. - if (castType.isNullable() || refType.isNonNullable()) { + if (castType.isNullableRef() || refType.isNonNullableRef()) { return Success; } // If the heap type part of the cast is compatible but the cast as a whole // is not, we must have a nullable input ref that we are casting to a // non-nullable type. - assert(refType.isNullable()); - assert(castType.isNonNullable()); + assert(refType.isNullableRef()); + assert(castType.isNonNullableRef()); return SuccessOnlyIfNonNull; } @@ -144,7 +144,7 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { // can succeed is if it allows nulls and the input is null. // // Note that this handles uninhabitability of the cast type. - if (refType.isNonNullable() || castType.isNonNullable()) { + if (refType.isNonNullableRef() || castType.isNonNullableRef()) { return Failure; } diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 381d4e49441..4570cb3b3d6 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -197,7 +197,7 @@ void PossibleContents::intersect(const PossibleContents& other) { auto newType = Type::getGreatestLowerBound(type, otherType); auto setNoneOrNull = [&]() { - if (newType.isNullable()) { + if (newType.isNullableRef()) { value = Literal::makeNull(heapType); } else { value = None(); @@ -278,7 +278,7 @@ bool PossibleContents::haveIntersection(const PossibleContents& a, auto aHeapType = aType.getHeapType(); auto bHeapType = bType.getHeapType(); - if (aType.isNullable() && bType.isNullable() && + if (aType.isNullableRef() && bType.isNullableRef() && aHeapType.getBottom() == bHeapType.getBottom()) { // A compatible null is possible on both sides. return true; @@ -356,7 +356,7 @@ bool PossibleContents::isSubContents(const PossibleContents& a, if (b.isFullConeType()) { if (a.isNull()) { - return b.getType().isNullable(); + return b.getType().isNullableRef(); } return Type::isSubType(a.getType(), b.getType()); } @@ -1764,7 +1764,7 @@ void TNHOracle::scan(Function* func, // This function is called with the reference that will be trapped on, // if it is null. void notePossibleTrap(Expression* expr) { - if (!expr->type.isRef() || expr->type.isNonNullable()) { + if (!expr->type.isNullableRef()) { return; } noteCast(expr, Type(expr->type.getHeapType(), NonNullable)); diff --git a/src/ir/possible-contents.h b/src/ir/possible-contents.h index b7270b840d2..e240df4b7ff 100644 --- a/src/ir/possible-contents.h +++ b/src/ir/possible-contents.h @@ -400,7 +400,7 @@ class PossibleContents { if (wasm && wasm->typeNames.contains(h)) { o << " $" << wasm->typeNames[h].name; } - if (t.isNullable()) { + if (t.isNullableRef()) { o << " null"; } } diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp index 2643e3ea3c6..423e7cd9791 100644 --- a/src/ir/type-updating.cpp +++ b/src/ir/type-updating.cpp @@ -506,7 +506,7 @@ void handleNonDefaultableLocals(Function* func, Module& wasm) { bool hasNonNullable = false; for (auto varType : func->vars) { for (auto type : varType) { - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { hasNonNullable = true; break; } @@ -529,7 +529,7 @@ void handleNonDefaultableLocals(Function* func, Module& wasm) { // LocalStructuralDominance should have only looked at non-nullable indexes // since we told it to ignore nullable ones. Also, params always dominate // and should not appear here. - assert(func->getLocalType(index).isNonNullable() || + assert(func->getLocalType(index).isNonNullableRef() || func->getLocalType(index).isTuple()); assert(!func->isParam(index)); } @@ -572,7 +572,7 @@ void handleNonDefaultableLocals(Function* func, Module& wasm) { for (size_t i = 0, size = type.size(); i < size; ++i) { elems[i] = builder.makeTupleExtract( builder.makeLocalGet(set->index, validType), i); - if (type[i].isNonNullable()) { + if (type[i].isNonNullableRef()) { elems[i] = builder.makeRefAs(RefAsNonNull, elems[i]); } } @@ -592,7 +592,7 @@ void handleNonDefaultableLocals(Function* func, Module& wasm) { Type getValidLocalType(Type type, FeatureSet features) { assert(type.isConcrete()); - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { return type.with(Nullable); } if (type.isTuple()) { @@ -606,7 +606,7 @@ Type getValidLocalType(Type type, FeatureSet features) { } Expression* fixLocalGet(LocalGet* get, Module& wasm) { - if (get->type.isNonNullable()) { + if (get->type.isNonNullableRef()) { // The get should now return a nullable value, and a ref.as_non_null // fixes that up. get->type = getValidLocalType(get->type, wasm.features); @@ -621,7 +621,7 @@ Expression* fixLocalGet(LocalGet* get, Module& wasm) { auto* elemGet = i == 0 ? get : builder.makeLocalGet(get->index, get->type); elems[i] = builder.makeTupleExtract(elemGet, i); - if (type[i].isNonNullable()) { + if (type[i].isNonNullableRef()) { elems[i] = builder.makeRefAs(RefAsNonNull, elems[i]); } } diff --git a/src/passes/AbstractTypeRefining.cpp b/src/passes/AbstractTypeRefining.cpp index a22488dd1c4..b7b12733835 100644 --- a/src/passes/AbstractTypeRefining.cpp +++ b/src/passes/AbstractTypeRefining.cpp @@ -383,7 +383,7 @@ struct AbstractTypeRefining : public Pass { Builder builder(*getModule()); if (curr->type.isExact() || (curr->desc && optimized->isBottom())) { if (curr->desc) { - if (curr->desc->type.isNullable() && + if (curr->desc->type.isNullableRef() && !getPassOptions().trapsNeverHappen) { curr->desc = builder.makeRefAs(RefAsNonNull, curr->desc); } @@ -442,7 +442,7 @@ struct AbstractTypeRefining : public Pass { bool isFail = curr->op == BrOnCastDescEqFail; if (curr->castType.isExact() || (curr->desc && optimized->isBottom())) { if (curr->desc) { - if (curr->desc->type.isNullable() && + if (curr->desc->type.isNullableRef() && !getPassOptions().trapsNeverHappen) { curr->desc = builder.makeRefAs(RefAsNonNull, curr->desc); } diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index fba3fca0c00..6957afa689e 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -551,7 +551,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().isNonNullable(); + func->getResults().isNull() && func->getResults().isNonNullableRef(); 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/DeadArgumentElimination2.cpp b/src/passes/DeadArgumentElimination2.cpp index 4597ae76ef5..6fd7adfd893 100644 --- a/src/passes/DeadArgumentElimination2.cpp +++ b/src/passes/DeadArgumentElimination2.cpp @@ -1097,7 +1097,7 @@ struct Optimizer // Add new vars to replace the removed params. for (Index i = removedParams.size(); i > 0; --i) { auto& [type, name] = removedParams[i - 1]; - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { hasNewNonNullableLocal = true; } Builder::addVar(func, name, type); diff --git a/src/passes/GlobalStructInference.cpp b/src/passes/GlobalStructInference.cpp index 744baee5e69..1e3d6d3d33b 100644 --- a/src/passes/GlobalStructInference.cpp +++ b/src/passes/GlobalStructInference.cpp @@ -672,7 +672,7 @@ struct GlobalStructInference : public Pass { // We must add a cast to non-null in some cases: A read of a null // descriptor returns a non-null value, so if there was a null in the // global, that would not validate by itself. - if (ret->type.isNullable() && curr->type.isNonNullable()) { + if (ret->type.isNullableRef() && curr->type.isNonNullableRef()) { ret = builder.makeRefAs(RefAsNonNull, ret); } diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp index 0e41774957b..a7b9adb07a7 100644 --- a/src/passes/Heap2Local.cpp +++ b/src/passes/Heap2Local.cpp @@ -769,7 +769,7 @@ struct Struct2Local : PostWalker { // Preserve the trapping on null descriptors by inserting a // ref.as_non_null. Expression* desc = curr->desc; - if (curr->desc->type.isNullable()) { + if (curr->desc->type.isNullableRef()) { desc = builder.makeRefAs(RefAsNonNull, desc); } contents.push_back(builder.makeLocalSet(tempIndexes[numTemps - 1], desc)); @@ -898,7 +898,8 @@ struct Struct2Local : PostWalker { // side effects, but that local.set would not be reflected in the parent // map, so it would not be updated if the allocation flowing through // that desc operand were later optimized. - if (allocIsCastDescEq && !allocIsCastRef && curr->type.isNullable()) { + if (allocIsCastDescEq && !allocIsCastRef && + curr->type.isNullableRef()) { // There might be a null value to let through. Reuse curr as a cast to // null. Use a scratch local to move the reference value past the desc // value. diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp index 6f34cf7f8da..660eda9dac2 100644 --- a/src/passes/InstrumentLocals.cpp +++ b/src/passes/InstrumentLocals.cpp @@ -76,9 +76,9 @@ struct InstrumentLocals : public WalkerPass> { Name import; if (curr->type.isRef()) { auto heapType = curr->type.getHeapType(); - if (heapType == HeapType::func && curr->type.isNullable()) { + if (heapType == HeapType::func && curr->type.isNullableRef()) { import = get_funcref; - } else if (heapType == HeapType::ext && curr->type.isNullable()) { + } else if (heapType == HeapType::ext && curr->type.isNullableRef()) { import = get_externref; } else { WASM_UNREACHABLE("TODO: general reference types"); @@ -129,9 +129,9 @@ struct InstrumentLocals : public WalkerPass> { } if (type.isRef()) { auto heapType = type.getHeapType(); - if (heapType == HeapType::func && type.isNullable()) { + if (heapType == HeapType::func && type.isNullableRef()) { import = set_funcref; - } else if (heapType == HeapType::ext && type.isNullable()) { + } else if (heapType == HeapType::ext && type.isNullableRef()) { import = set_externref; } else { WASM_UNREACHABLE("TODO: general reference types"); diff --git a/src/passes/LocalSubtyping.cpp b/src/passes/LocalSubtyping.cpp index 583c10cf25f..5deda5e7069 100644 --- a/src/passes/LocalSubtyping.cpp +++ b/src/passes/LocalSubtyping.cpp @@ -150,7 +150,7 @@ struct LocalSubtyping : public WalkerPass> { assert(newType != Type::none); // in valid wasm there must be a LUB // Remove non-nullability if we disallow that in locals. - if (newType.isNonNullable()) { + if (newType.isNonNullableRef()) { if (cannotBeNonNullable.contains(i)) { newType = newType.with(Nullable); } diff --git a/src/passes/MakeSharedObjects.cpp b/src/passes/MakeSharedObjects.cpp index 8a52fb79948..e55d031c10a 100644 --- a/src/passes/MakeSharedObjects.cpp +++ b/src/passes/MakeSharedObjects.cpp @@ -251,7 +251,7 @@ struct LazyTable { Type sharedI31Nullable = Type(HeapTypes::i31.getBasic(Shared), Nullable); Expression* res = builder.makeCall(getRefToIndexName(), {arg}, sharedI31Nullable); - if (targetType.isNonNullable()) { + if (targetType.isNonNullableRef()) { res = builder.makeRefAs(RefAsNonNull, res); } return res; @@ -564,7 +564,7 @@ struct MakeSharedObjects return; } Builder builder(*getModule()); - if (curr->ref->type.isNonNullable()) { + if (curr->ref->type.isNonNullableRef()) { // (ref.test castType (table.get $t (i31.get_u ref))) curr->ref = builder.makeTableGet( funcTable.getName(), builder.makeI31Get(curr->ref, false), funcref); @@ -582,7 +582,7 @@ struct MakeSharedObjects auto* cond = builder.makeRefIsNull( builder.makeLocalTee(scratch, curr->ref, scratchType)); auto* ifNull = - builder.makeConst(Literal(int32_t(curr->castType.isNullable()))); + builder.makeConst(Literal(int32_t(curr->castType.isNullableRef()))); curr->ref = builder.makeTableGet( funcTable.getName(), builder.makeI31Get(builder.makeLocalGet(scratch, scratchType), false), @@ -630,7 +630,7 @@ struct MakeSharedObjects auto* tee = builder.makeLocalTee(scratch, curr->ref, scratchType); auto* isNull = builder.makeRefIsNull(tee); Expression* ifNull = nullptr; - if (curr->type.isNullable()) { + if (curr->type.isNullableRef()) { ifNull = builder.makeLocalGet(scratch, scratchType); } else { ifNull = builder.makeUnreachable(); @@ -640,7 +640,7 @@ struct MakeSharedObjects auto* tableGet = builder.makeTableGet(funcTable.getName(), i31get, funcref); auto* refTest = builder.makeRefTest(tableGet, curr->type); Expression* ifPass = builder.makeLocalGet(scratch, scratchType); - if (curr->type.isNonNullable()) { + if (curr->type.isNonNullableRef()) { ifPass = builder.makeRefAs(RefAsNonNull, ifPass); } auto* ifFail = builder.makeUnreachable(); @@ -676,7 +676,7 @@ struct MakeSharedObjects Type sharedAnyNullable = Type(HeapTypes::any.getBasic(Shared), Nullable); Expression* call = builder.makeCall(getExternToAnyName(), {ext}, sharedAnyNullable); - if (curr->type.isNonNullable()) { + if (curr->type.isNonNullableRef()) { call = builder.makeRefAs(RefAsNonNull, call); } replaceCurrent(call); diff --git a/src/passes/OptimizeCasts.cpp b/src/passes/OptimizeCasts.cpp index 25852027a0c..820d53804f6 100644 --- a/src/passes/OptimizeCasts.cpp +++ b/src/passes/OptimizeCasts.cpp @@ -270,7 +270,7 @@ struct EarlyCastFinder // As we only move RefAsNonNull RefAs casts right now, we should // ignore a LocalGet if the type is already non-nullable, as // adding an extra ref.as_non_null has no effect. - if (!currRefAsMove[curr->index].target && curr->type.isNullable()) { + if (!currRefAsMove[curr->index].target && curr->type.isNullableRef()) { currRefAsMove[curr->index].target = curr; } } diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 01f3907508d..4d523adbea1 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1232,7 +1232,7 @@ struct OptimizeInstructions // in some cases, by removing or moving the ref.as_non_null operation. if (auto* as = curr->value->dynCast()) { if (as->op == RefAsNonNull && - getFunction()->getLocalType(curr->index).isNullable()) { + getFunction()->getLocalType(curr->index).isNullableRef()) { // (local.tee (ref.as_non_null ..)) // => // (ref.as_non_null (local.tee ..)) @@ -1822,7 +1822,7 @@ struct OptimizeInstructions // (ref.cast ;; now non-nullable // // Either way we trap here, but refining the type may have benefits later. - if (ref->type.isNullable()) { + if (ref->type.isNullableRef()) { if (auto* cast = ref->dynCast()) { // Note that we must be the last child of the parent, otherwise effects // in the middle may need to remain: @@ -1884,7 +1884,7 @@ struct OptimizeInstructions auto leftIsHeapSubtype = HeapType::isSubType(leftHeapType, rightHeapType); auto rightIsHeapSubtype = HeapType::isSubType(rightHeapType, leftHeapType); if (!leftIsHeapSubtype && !rightIsHeapSubtype && - (leftType.isNonNullable() || rightType.isNonNullable())) { + (leftType.isNonNullableRef() || rightType.isNonNullableRef())) { // The heap types have no intersection, so the only thing that can // possibly appear on both sides is null, but one of the two is non- // nullable, which rules that out. So there is no way that the same @@ -2495,8 +2495,8 @@ struct OptimizeInstructions // descriptors. We still need to preserve the trap on null // descriptors, though. if (refType.isNull()) { - assert(curr->type.isNullable()); - if (curr->desc->type.isNullable()) { + assert(curr->type.isNullableRef()); + if (curr->desc->type.isNullableRef()) { curr->desc = builder.makeRefAs(RefAsNonNull, curr->desc); } replaceCurrent(getDroppedChildrenAndAppend( @@ -2568,7 +2568,7 @@ struct OptimizeInstructions // to be successful, but since the input is uninhabitable we won't // even reach the cast. Such casts will be evaluated as // Unreachable, so we'll not hit this assertion. - assert(curr->type.isNullable()); + assert(curr->type.isNullableRef()); auto nullType = curr->type.getHeapType().getBottom(); replaceCurrent( getDroppedChildrenAndAppend(curr, @@ -2650,7 +2650,7 @@ struct OptimizeInstructions return; } - if (curr->type.isNonNullable() && trapOnNull(curr, curr->ref)) { + if (curr->type.isNonNullableRef() && trapOnNull(curr, curr->ref)) { return; } @@ -2674,7 +2674,7 @@ struct OptimizeInstructions // we can improve nullability. Type improvedType = curr->type; if (curr->desc) { - if (curr->type.isNullable() && refType.isNonNullable()) { + if (curr->type.isNullableRef() && refType.isNonNullableRef()) { improvedType = curr->type.with(NonNullable); } } else { @@ -2847,7 +2847,7 @@ struct OptimizeInstructions // constant, but this warrants more investigation. TODO Builder builder(*getModule()); - if (curr->value->type.isNonNullable()) { + if (curr->value->type.isNonNullableRef()) { replaceCurrent( builder.makeSequence(builder.makeDrop(curr->value), builder.makeConst(Literal::makeZero(Type::i32)))); @@ -2901,7 +2901,7 @@ struct OptimizeInstructions return; } skipNonNullCast(curr->value, curr); - if (!curr->value->type.isNullable()) { + if (!curr->value->type.isNullableRef()) { replaceCurrent(curr->value); return; } @@ -2916,7 +2916,7 @@ struct OptimizeInstructions if (auto* cast = curr->value->dynCast()) { // The cast cannot be non-nullable, or we would have handled this right // above by just removing the ref.as, since it would not be needed. - assert(!cast->type.isNonNullable()); + assert(!cast->type.isNonNullableRef()); cast->type = cast->type.with(NonNullable); replaceCurrent(cast); } diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 64da911a151..797a000ae8b 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -892,7 +892,7 @@ struct RemoveUnusedBrs : public WalkerPass> { if (Type::isSubType(expr->type, type)) { return expr; } - if (type.isNonNullable() && expr->type.isNullable() && + if (type.isNonNullableRef() && expr->type.isNullableRef() && Type::isSubType(expr->type.with(NonNullable), type)) { return builder.makeRefAs(RefAsNonNull, expr); } @@ -907,7 +907,7 @@ struct RemoveUnusedBrs : public WalkerPass> { auto getRefValue = [&]() -> Expression* { if (curr->desc) { // Preserve the trap on a null descriptor. - if (curr->desc->type.isNullable()) { + if (curr->desc->type.isNullableRef()) { curr->desc = builder.makeRefAs(RefAsNonNull, curr->desc); } Block* ref = @@ -929,7 +929,7 @@ struct RemoveUnusedBrs : public WalkerPass> { worked = true; return; } - if (refType.isNonNullable()) { + if (refType.isNonNullableRef()) { // The branch will definitely not be taken. replaceCurrent(maybeCast(curr->ref, curr->type)); worked = true; @@ -943,7 +943,7 @@ struct RemoveUnusedBrs : public WalkerPass> { worked = true; return; } - if (refType.isNonNullable()) { + if (refType.isNonNullableRef()) { // Definitely taken. replaceCurrent(builder.makeBreak( curr->name, maybeCast(curr->ref, curr->getSentType()))); @@ -971,7 +971,7 @@ struct RemoveUnusedBrs : public WalkerPass> { } else { // For descriptor casts, the target heap type is controlled by the // descriptor operand, but we can still improve nullability. - if (improvedType.isNullable() && refType.isNonNullable()) { + if (improvedType.isNullableRef() && refType.isNonNullableRef()) { improvedType = improvedType.with(NonNullable); } } @@ -992,7 +992,8 @@ struct RemoveUnusedBrs : public WalkerPass> { // that would *un*refine the send type. // TODO: Consider allowing this change if the branch target // expects a nullable type anyway. - if (curr->castType.isNullable() && improvedType.isNonNullable()) { + if (curr->castType.isNullableRef() && + improvedType.isNonNullableRef()) { improvedType = improvedType.with(Nullable); } } diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index ee2079b31d6..1f97b01ddba 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -1129,7 +1129,7 @@ struct RemoveUnusedModuleElements : public Pass { struct NullDescFinder : PostWalker { bool mayTrap = false; void visitStructNew(StructNew* curr) { - if (curr->desc && curr->desc->type.isNullable()) { + if (curr->desc && curr->desc->type.isNullableRef()) { mayTrap = true; } } diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp index ebf33183be8..e3b408d85bd 100644 --- a/src/passes/TypeRefining.cpp +++ b/src/passes/TypeRefining.cpp @@ -597,7 +597,7 @@ struct TypeRefining : public Pass { auto heapType = type.getHeapType(); if (heapType.isBottom()) { auto* drop = builder.makeDrop(value); - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { // This will just trap. Make it trap, and update parents' types. refinalize = true; return builder.makeSequence(drop, builder.makeUnreachable()); diff --git a/src/passes/Unsubtyping.cpp b/src/passes/Unsubtyping.cpp index c4bd9885e48..a5e0c91727c 100644 --- a/src/passes/Unsubtyping.cpp +++ b/src/passes/Unsubtyping.cpp @@ -768,7 +768,7 @@ struct Unsubtyping : Pass, Noter { // a trap, then we have no way to preserve that trap without keeping the // descriptor around. if (trapsNeverHappen || getFunction() || - curr->desc->type.isNonNullable()) { + curr->desc->type.isNonNullableRef()) { return; } // We must preserve the potential trap. When we update the instructions @@ -1106,7 +1106,7 @@ struct Unsubtyping : Pass, Noter { if (auto* func = getFunction()) { // Preserve a trap from a null descriptor if necessary. if (!getPassOptions().trapsNeverHappen && - curr->desc->type.isNullable()) { + curr->desc->type.isNullableRef()) { curr->desc = Builder(*getModule()).makeRefAs(RefAsNonNull, curr->desc); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index c202c210d7e..d9ed0d9e9fc 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1035,7 +1035,7 @@ void TranslateToFuzzReader::finalizeTable() { if (!preserveImportsAndExports) { // Avoid an imported table (which the fuzz harness would need to handle). table->module = table->base = Name(); - if (table->type.isNonNullable()) { + if (table->type.isNonNullableRef()) { table->init = makeConst(table->type); } } @@ -1981,7 +1981,7 @@ void TranslateToFuzzReader::recombine(Function* func) { std::vector ret; ret.push_back(type); - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { auto nullable = getRelevantTypes(type.with(Nullable)); ret.insert(ret.end(), nullable.begin(), nullable.end()); } @@ -2966,7 +2966,7 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) { if (heapType.isBasic()) { options.add(FeatureSet::ReferenceTypes | FeatureSet::GC, &Self::makeBasicRef); - if (type.isNullable() && funcContext) { + if (type.isNullableRef() && funcContext) { if (heapType == HeapType::func) { options.add(FeatureSet::ReferenceTypes, &Self::makeTableGet); } @@ -3105,7 +3105,7 @@ Expression* TranslateToFuzzReader::makeTrivial(Type type) { // If we have a function context, use a local half the time. Use a local // less often if the local is non-nullable, however, as then we might be // using it before it was set, which would trap. - if (funcContext && oneIn(type.isNonNullable() ? 10 : 2)) { + if (funcContext && oneIn(type.isNonNullableRef() ? 10 : 2)) { return makeLocalGet(type); } @@ -3579,7 +3579,7 @@ Expression* TranslateToFuzzReader::makeLocalGet(Type type) { // nullable local we prefer a tee later down.). auto index = builder.addVar(funcContext->func, type); LocalSet* tee = nullptr; - if (choice == 1 || type.isNonNullable()) { + if (choice == 1 || type.isNonNullableRef()) { // Create the tee here before adding the local to typeLocals (or else we // might end up using it prematurely inside the make() call). tee = builder.makeLocalTee(index, make(type), type); @@ -4227,10 +4227,10 @@ Expression* TranslateToFuzzReader::makeRefFuncConst(Type type) { // but only rarely if the type is non-nullable (because in that case we'd need // to add a ref.as_non_null to validate, and the code will trap when we get // here). - if ((type.isNullable() && oneIn(2)) || - (type.isNonNullable() && oneIn(16) && funcContext)) { + if ((type.isNullableRef() && oneIn(2)) || + (type.isNonNullableRef() && oneIn(16) && funcContext)) { Expression* ret = builder.makeRefNull(HeapTypes::nofunc.getBasic(share)); - if (!type.isNullable()) { + if (!type.isNullableRef()) { assert(funcContext); ret = builder.makeRefAs(RefAsNonNull, ret); } @@ -4265,7 +4265,7 @@ Expression* TranslateToFuzzReader::makeConst(Type type) { if (type.isRef()) { assert(wasm.features.hasReferenceTypes()); // With a low chance, just emit a null if that is valid. - if (type.isNullable() && oneIn(8)) { + if (type.isNullableRef() && oneIn(8)) { return builder.makeRefNull(type.getHeapType()); } if (type.getHeapType().isString()) { @@ -4312,7 +4312,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { !preserveImportsAndExports && isImportableGlobalType(type); if (canImport) { bool shouldImport; - if (type.isNonNullable()) { + if (type.isNonNullableRef()) { // If we are not in a function context, casting a null is not an // option, so always use a global. Otherwise very rarely cast a null. shouldImport = !funcContext || !oneIn(16); @@ -4339,7 +4339,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { } // Use a null value, making it non-null if necessary. auto null = builder.makeRefNull(HeapTypes::ext.getBasic(share)); - if (!type.isNullable()) { + if (!type.isNullableRef()) { return builder.makeRefAs(RefAsNonNull, null); } return null; @@ -4347,7 +4347,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { case HeapType::func: { // Rarely, emit a call to imported table.get (when nullable, unshared, and // where we can emit a call). - if (!trivialNesting && type.isNullable() && share == Unshared && + if (!trivialNesting && type.isNullableRef() && share == Unshared && funcContext && tableGetImportName && !oneIn(3)) { return makeImportTableGet(); } @@ -4355,7 +4355,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { } case HeapType::cont: { // Most of the time, avoid null continuations, as they will trap. - if (type.isNullable() && oneIn(4)) { + if (type.isNullableRef() && oneIn(4)) { return builder.makeRefNull(HeapTypes::cont.getBasic(share)); } // Emit the simplest possible continuation. @@ -4377,7 +4377,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { // Without wasm GC all we have is an "abstract" eqref type, which is // a subtype of anyref, but we cannot create constants of it, except // for null. - assert(type.isNullable()); + assert(type.isNullableRef()); return builder.makeRefNull(HeapTypes::none.getBasic(share)); } auto nullability = getSubType(type.getNullability()); @@ -4398,7 +4398,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { } case HeapType::i31: { assert(wasm.features.hasGC()); - if (type.isNullable() && oneIn(4)) { + if (type.isNullableRef() && oneIn(4)) { return builder.makeRefNull(HeapTypes::none.getBasic(share)); } return builder.makeRefI31(makeConst(Type::i32), share); @@ -4434,9 +4434,9 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { case HeapType::exn: { // If nullable, sometimes emit a null. If not in a function context, see // below, we need a null as well regardless of the type. - if ((type.isNullable() && oneIn(2)) || !funcContext) { + if ((type.isNullableRef() && oneIn(2)) || !funcContext) { auto* null = builder.makeRefNull(HeapTypes::exn.getBasic(share)); - if (type.isNullable()) { + if (type.isNullableRef()) { return null; } // The type is non-nullable, so we are here because we are in a non- @@ -4489,7 +4489,7 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { case HeapType::nocont: case HeapType::noexn: { auto null = builder.makeRefNull(heapType.getBasic(share)); - if (!type.isNullable()) { + if (!type.isNullableRef()) { return builder.makeRefAs(RefAsNonNull, null); } return null; @@ -4524,7 +4524,7 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) { // inhabitable.) const auto LIMIT = fuzzParams.NESTING_LIMIT + 1; AutoNester nester(*this); - if (type.isNullable() && + if (type.isNullableRef() && (random.finished() || nesting >= LIMIT || oneIn(LIMIT - nesting + 1))) { return builder.makeRefNull(heapType); } @@ -4533,7 +4533,7 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) { // something here to avoid infinite recursion. In the worse case we'll emit a // cast to non-null of a null, which validates, but it will trap at runtime // which is not ideal. - if (type.isNonNullable() && (random.finished() || nesting >= LIMIT)) { + if (type.isNonNullableRef() && (random.finished() || nesting >= LIMIT)) { // If we have a function context then we can at least emit a local.get, // sometimes, which is less bad. Note that we need to check typeLocals // manually here to avoid infinite recursion (as makeLocalGet will fall back @@ -6057,11 +6057,11 @@ Expression* TranslateToFuzzReader::makeBrOn(Type type) { // trivial. refType = oneIn(5) ? getSubType(castType) : getSuperType(castType); } - if (targetType.isNonNullable()) { + if (targetType.isNonNullableRef()) { // And it must have the right nullability for the target, as mentioned // above: if the target type is non-nullable then either the ref or the // cast types must be. - if (!refType.isNonNullable() && !castType.isNonNullable()) { + if (!refType.isNonNullableRef() && !castType.isNonNullableRef()) { // Pick one to make non-nullable. if (oneIn(2)) { refType = Type(refType.getHeapType(), NonNullable); @@ -6083,7 +6083,7 @@ Expression* TranslateToFuzzReader::makeBrOn(Type type) { // There is no nullability to adjust: if targetType is non-nullable then // both refType and castType are as well, as subtypes of it. But we can // also allow castType to be nullable (it is not sent to the target). - if (castType.isNonNullable() && oneIn(2)) { + if (castType.isNonNullableRef() && oneIn(2)) { castType = Type(castType.getHeapType(), Nullable); } break; diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp index ee9ce65df3c..ce72f853503 100644 --- a/src/tools/fuzzing/heap-types.cpp +++ b/src/tools/fuzzing/heap-types.cpp @@ -1027,8 +1027,7 @@ void Inhabitator::markBottomRefsNullable() { auto children = type.getTypeChildren(); for (size_t i = 0; i < children.size(); ++i) { auto child = children[i]; - if (child.isRef() && child.getHeapType().isBottom() && - child.isNonNullable()) { + if (child.isNonNullableRef() && child.getHeapType().isBottom()) { markNullable({type, i}); } } @@ -1049,8 +1048,8 @@ void Inhabitator::markExternRefsNullable() { auto children = type.getTypeChildren(); for (size_t i = 0; i < children.size(); ++i) { auto child = children[i]; - if (child.isRef() && child.getHeapType().isMaybeShared(HeapType::ext) && - child.isNonNullable()) { + if (child.isNonNullableRef() && + child.getHeapType().isMaybeShared(HeapType::ext)) { markNullable({type, i}); } } @@ -1131,7 +1130,7 @@ void Inhabitator::breakNonNullableCycles() { } // Skip nullable references because they don't cause uninhabitable // cycles. - if (children[index].isNullable()) { + if (children[index].isNullableRef()) { ++index; continue; } @@ -1180,7 +1179,7 @@ void Inhabitator::breakNonNullableCycles() { } // Otherwise we have a non-nullable reference we need to search. - assert(children[index].isRef() && children[index].isNonNullable()); + assert(children[index].isNonNullableRef()); auto next = children[index++].getHeapType(); visitType(next); } @@ -1401,7 +1400,7 @@ bool isUninhabitable(HeapType type, bool isUninhabitable(Type type, std::unordered_set& visited, std::unordered_set& visiting) { - if (type.isRef() && type.isNonNullable()) { + if (type.isNonNullableRef()) { if (type.getHeapType().isBottom() || type.getHeapType().isMaybeShared(HeapType::ext)) { return true; diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index a948f258c65..534b0fa63f1 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -59,7 +59,7 @@ bool isNullableAndMutable(Expression* ref, Index fieldIndex) { // Find the field for the given reference, and check its properties. auto field = GCTypeUtils::getField(ref->type, fieldIndex); assert(field); - return field->type.isNullable() && field->mutable_ == Mutable; + return field->type.isNullableRef() && field->mutable_ == Mutable; } // The prefix for a recommendation, so it is aligned properly with the rest of diff --git a/src/tools/wasm-reduce/wasm-reduce.cpp b/src/tools/wasm-reduce/wasm-reduce.cpp index 1ffd2699d43..4d769ed30c1 100644 --- a/src/tools/wasm-reduce/wasm-reduce.cpp +++ b/src/tools/wasm-reduce/wasm-reduce.cpp @@ -1402,7 +1402,7 @@ struct Reducer auto* curr = getCurrent(); // References. - if (curr->type.isNullable() && !curr->is()) { + if (curr->type.isNullableRef() && !curr->is()) { RefNull* n = builder->makeRefNull(curr->type.getHeapType()); return tryToReplaceCurrent(n); } diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 56db519263a..87df7725869 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -47,7 +47,7 @@ class Builder { Type type, std::vector&& vars, Expression* body = nullptr) { - assert(type.isSignature() && type.isNonNullable()); + assert(type.isSignature() && type.isNonNullableRef()); auto func = std::make_unique(); func->name = name; func->type = type; @@ -1657,7 +1657,7 @@ class Builder { if (curr->type.isTuple() && curr->type.isDefaultable()) { return maybeWrap(makeConstantExpression(Literal::makeZeros(curr->type))); } - if (curr->type.isNullable()) { + if (curr->type.isNullableRef()) { return maybeWrap( ExpressionManipulator::refNull(curr, curr->type.getHeapType())); } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d5e358a081d..e3fe2566092 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2156,7 +2156,7 @@ class ExpressionRunner : public OverriddenVisitor { auto data = val.getGCData(); if (!data) { // Check whether null is allowed. - if (curr->getCastType().isNullable()) { + if (curr->getCastType().isNullableRef()) { return typename Cast::Success{val}; } else { return typename Cast::Failure{val}; @@ -3794,7 +3794,7 @@ class ModuleRunnerBase : public ExpressionRunner { initVal = ExpressionRunner::visit(table->init).getSingleValue(); } else { - assert(table->type.isNullable() && + assert(table->type.isNullableRef() && "Non-nullable table must have an init expressions"); initVal = Literal::makeNull(table->type.getHeapType()); } diff --git a/src/wasm-type.h b/src/wasm-type.h index 76424c27d73..a7cf42e3fdc 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -393,8 +393,8 @@ class Type { } bool isRef() const { return !isBasic() && !(id & TupleMask); } - bool isNullable() const { return isRef() && (id & NullMask); } - bool isNonNullable() const { return isRef() && !(id & NullMask); } + bool isNullableRef() const { return isRef() && (id & NullMask); } + bool isNonNullableRef() const { return isRef() && !(id & NullMask); } bool isExact() const { return isRef() && !getHeapType().isBasic() && (id & ExactMask); } @@ -427,7 +427,7 @@ class Type { // TODO: Allow this only for reference types. Nullability getNullability() const { - return isNullable() ? Nullable : NonNullable; + return isNullableRef() ? Nullable : NonNullable; } Exactness getExactness() const { assert(isRef()); diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 5c15e502198..21881a8f578 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -53,26 +53,26 @@ Literal::Literal(Type type) : type(type) { } if (type.isNull()) { - assert(type.isNullable() && !type.isExact()); + assert(type.isNullableRef() && !type.isExact()); new (&gcData) std::shared_ptr(); return; } if (type.isRef() && type.getHeapType().isMaybeShared(HeapType::i31)) { - assert(type.isNonNullable()); + assert(type.isNonNullableRef()); i32 = 0; return; } if (type.isRef() && type.getHeapType().isMaybeShared(HeapType::ext)) { - assert(type.isNonNullable()); + assert(type.isNonNullableRef()); new (&gcData) std::shared_ptr( std::make_shared(Literals{Literal(int32_t{0})})); return; } if (type.isRef() && type.getHeapType().isMaybeShared(HeapType::waitqueue)) { - assert(type.isNonNullable()); + assert(type.isNonNullableRef()); return; } @@ -165,7 +165,7 @@ Literal::Literal(const Literal& other) : type(other.type) { return; } // After handling nulls, only non-nullable Literals remain. - assert(!type.isNullable()); + assert(!type.isNullableRef()); auto heapType = type.getHeapType(); if (other.isData()) { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 6a7a95a92c1..aede8e67b0d 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2015,7 +2015,7 @@ void WasmBinaryWriter::writeType(Type type) { type = type.asWrittenGivenFeatures(wasm->features); if (type.isRef()) { auto heapType = type.getHeapType(); - if (type.isNullable() && heapType.isBasic() && !heapType.isShared()) { + if (type.isNullableRef() && heapType.isBasic() && !heapType.isShared()) { switch (heapType.getBasic(Unshared)) { case HeapType::ext: o << S32LEB(BinaryConsts::EncodedType::externref); @@ -2070,7 +2070,7 @@ void WasmBinaryWriter::writeType(Type type) { return; } } - if (type.isNullable()) { + if (type.isNullableRef()) { o << S32LEB(BinaryConsts::EncodedType::nullable); } else { o << S32LEB(BinaryConsts::EncodedType::nonnullable); diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 4edf0eba96a..587ed87db36 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -2345,7 +2345,7 @@ Result<> IRBuilder::makeBrOn(Index label, WASM_UNREACHABLE("unexpected op"); case BrOnCast: case BrOnCastDescEq: - if (out->isNullable()) { + if (out->isNullableRef()) { resultType = Type(in->getHeapType(), NonNullable); } else { resultType = *in; @@ -2353,7 +2353,7 @@ Result<> IRBuilder::makeBrOn(Index label, break; case BrOnCastFail: case BrOnCastDescEqFail: - if (in->isNonNullable()) { + if (in->isNonNullableRef()) { resultType = Type(out->getHeapType(), NonNullable); } else { resultType = *out; diff --git a/src/wasm/wasm-stack-opts.cpp b/src/wasm/wasm-stack-opts.cpp index 3c1b8a69dce..e3ec8f4ac18 100644 --- a/src/wasm/wasm-stack-opts.cpp +++ b/src/wasm/wasm-stack-opts.cpp @@ -534,7 +534,7 @@ bool StackIROptimizer::canRemoveSetGetPair(Index setIndex, Index getIndex) { // anyhow (hence we can check non-nullability instead of non- // defaultability). assert(localType.isSingle()); - if (func->isParam(set->index) || !localType.isNonNullable()) { + if (func->isParam(set->index) || !localType.isNonNullableRef()) { // This local cannot pose a problem for validation (params are always // initialized, and it is ok if nullable locals are uninitialized). return true; diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index e31f979d321..af68726e4b9 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2561,7 +2561,7 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) { void BinaryInstWriter::visitRefTest(RefTest* curr) { o << static_cast(BinaryConsts::GCPrefix); - if (curr->castType.isNullable()) { + if (curr->castType.isNullableRef()) { o << U32LEB(BinaryConsts::RefTestNull); } else { o << U32LEB(BinaryConsts::RefTest); @@ -2576,7 +2576,7 @@ void BinaryInstWriter::visitRefCast(RefCast* curr) { return; } o << static_cast(BinaryConsts::GCPrefix); - if (curr->type.isNullable()) { + if (curr->type.isNullableRef()) { if (curr->desc) { o << U32LEB(BinaryConsts::RefCastDescEqNull); } else { @@ -2636,8 +2636,8 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) { } assert(curr->ref->type.isRef()); assert(hasDesc || Type::isSubType(curr->castType, curr->ref->type)); - uint8_t flags = (curr->ref->type.isNullable() ? 1 : 0) | - (curr->castType.isNullable() ? 2 : 0); + uint8_t flags = (curr->ref->type.isNullableRef() ? 1 : 0) | + (curr->castType.isNullableRef() ? 2 : 0); o << flags; o << U32LEB(getBreakIndex(curr->name)); parent.writeHeapType(curr->ref->type.getHeapType(), diff --git a/src/wasm/wasm-type-shape.cpp b/src/wasm/wasm-type-shape.cpp index dcac43192f4..29f96622dfc 100644 --- a/src/wasm/wasm-type-shape.cpp +++ b/src/wasm/wasm-type-shape.cpp @@ -156,8 +156,8 @@ template struct RecGroupComparator { return compare(a.getTuple(), b.getTuple()); } assert(a.isRef() && b.isRef()); - if (a.isNullable() != b.isNullable()) { - return a.isNullable() < b.isNullable() ? LT : GT; + if (a.isNullableRef() != b.isNullableRef()) { + return a.isNullableRef() < b.isNullableRef() ? LT : GT; } if (a.isExact() != b.isExact()) { return a.isExact() < b.isExact() ? LT : GT; @@ -310,7 +310,7 @@ struct RecGroupHasher { return digest; } assert(type.isRef()); - wasm::rehash(digest, type.isNullable()); + wasm::rehash(digest, type.isNullableRef()); wasm::rehash(digest, type.isExact()); hash_combine(digest, hash(type.getHeapType())); return digest; diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 4d9d2a75eab..5a2970917fc 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -557,7 +557,7 @@ bool Type::isDefaultable() const { } return true; } - return isConcrete() && !isNonNullable(); + return isConcrete() && !isNonNullableRef(); } bool Type::isCastable() const { return isRef() && getHeapType().isCastable(); } @@ -681,7 +681,7 @@ bool Type::isSubType(Type a, Type b) { if (!a.isRef() || !b.isRef()) { return false; } - if (a.isNullable() && !b.isNullable()) { + if (a.isNullableRef() && !b.isNullableRef()) { return false; } auto heapTypeA = a.getHeapType(); @@ -738,7 +738,7 @@ Type Type::getLeastUpperBound(Type a, Type b) { auto heapTypeB = b.getHeapType(); if (auto heapType = HeapType::getLeastUpperBound(heapTypeA, heapTypeB)) { auto nullability = - (a.isNullable() || b.isNullable()) ? Nullable : NonNullable; + (a.isNullableRef() || b.isNullableRef()) ? Nullable : NonNullable; // If one heap type is bottom, then the exactness comes from the other // heap type. Otherwise, the LUB can only be exact if both of the inputs // are the same exact heap type. @@ -780,7 +780,7 @@ Type Type::getGreatestLowerBound(Type a, Type b) { return Type::unreachable; } auto nullability = - (a.isNonNullable() || b.isNonNullable()) ? NonNullable : Nullable; + (a.isNonNullableRef() || b.isNonNullableRef()) ? NonNullable : Nullable; auto exactness = (a.isExact() || b.isExact()) ? Exact : Inexact; HeapType heapType; if (HeapType::isSubType(heapA, heapB)) { @@ -1568,7 +1568,7 @@ std::ostream& TypePrinter::print(Type type) { print(type.getTuple()); } else if (type.isRef()) { auto heapType = type.getHeapType(); - if (type.isNullable() && heapType.isBasic() && !heapType.isShared()) { + if (type.isNullableRef() && heapType.isBasic() && !heapType.isShared()) { if (type.isExact()) { os << "(exact "; } @@ -1632,7 +1632,7 @@ std::ostream& TypePrinter::print(Type type) { return os; } os << "(ref "; - if (type.isNullable()) { + if (type.isNullableRef()) { os << "null "; } if (type.isExact()) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index c89472f16b6..5f54af90018 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2597,7 +2597,7 @@ void FunctionValidator::visitRefNull(RefNull* curr) { getStream() << getMissingFeaturesList(*getModule(), feats) << '\n'; } if (!shouldBeTrue( - curr->type.isNullable(), curr, "ref.null types must be nullable")) { + curr->type.isNullableRef(), curr, "ref.null types must be nullable")) { return; } shouldBeTrue( @@ -2667,7 +2667,7 @@ void FunctionValidator::visitRefFunc(RefFunc* curr) { shouldBeTrue(!getFunction() || getModule()->features.hasReferenceTypes(), curr, "ref.func requires reference-types [--enable-reference-types]"); - if (!shouldBeTrue(curr->type.isNonNullable(), + if (!shouldBeTrue(curr->type.isNonNullableRef(), curr, "ref.func should have a non-nullable reference type")) { return; @@ -3175,7 +3175,7 @@ void FunctionValidator::visitRefI31(RefI31* curr) { return; } - if (!shouldBeTrue(curr->type.isNonNullable(), + if (!shouldBeTrue(curr->type.isNonNullableRef(), curr, "ref.i31 should have a non-nullable reference type")) { return; @@ -3279,7 +3279,7 @@ void FunctionValidator::visitRefCast(RefCast* curr) { "ref.cast target type and ref type must have a common supertype"); // We should never have a nullable cast of a non-nullable reference, since // that unnecessarily loses type information. - shouldBeTrue(curr->ref->type.isNullable() || curr->type.isNonNullable(), + shouldBeTrue(curr->ref->type.isNullableRef() || curr->type.isNonNullableRef(), curr, "ref.cast null of non-nullable references are not allowed"); @@ -3403,8 +3403,8 @@ void FunctionValidator::visitBrOn(BrOn* curr) { curr, "br_on_cast_desc_eq* cast exactness should match " "descriptor exactness"); - shouldBeTrue(curr->ref->type.isNullable() || - curr->castType.isNonNullable(), + shouldBeTrue(curr->ref->type.isNullableRef() || + curr->castType.isNonNullableRef(), curr, "br_on_cast_desc_eq* with non-nullable ref should have " "non-nullable cast type"); @@ -3442,7 +3442,7 @@ void FunctionValidator::visitStructNew(StructNew* curr) { if (curr->type == Type::unreachable) { return; } - if (!shouldBeTrue(curr->type.isNonNullable(), + if (!shouldBeTrue(curr->type.isNonNullableRef(), curr, "struct.new should have a non-nullable reference type")) { return; @@ -3809,7 +3809,7 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) { if (curr->type == Type::unreachable) { return; } - if (!shouldBeTrue(curr->type.isNonNullable(), + if (!shouldBeTrue(curr->type.isNonNullableRef(), curr, "array.new should have a non-nullable reference type")) { return; @@ -4466,15 +4466,14 @@ void FunctionValidator::visitContNew(ContNew* curr) { return; } - if (!shouldBeTrue(curr->type.isNonNullable(), + if (!shouldBeTrue(curr->type.isNonNullableRef(), curr, "cont.new should have a non-nullable reference type")) { return; } shouldBeTrue(curr->type.isExact(), curr, "cont.new should be exact"); - if (!shouldBeTrue(curr->type.isRef() && - curr->type.getHeapType().isContinuation(), + if (!shouldBeTrue(curr->type.getHeapType().isContinuation(), curr, "cont.new must be annotated with a continuation type")) { return; @@ -4516,8 +4515,7 @@ void FunctionValidator::visitContBind(ContBind* curr) { } if (!shouldBeTrue( - curr->type.isRef() && curr->type.isNonNullable() && - curr->type.isExact(), + curr->type.isNonNullableRef() && curr->type.isExact(), curr, "the output type must be a non-nullable, exact reference")) { return; @@ -4954,7 +4952,7 @@ void FunctionValidator::visitFunction(Function* curr) { for (auto index : info.nonDominatingIndices) { auto localType = curr->getLocalType(index); for (auto type : localType) { - shouldBeTrue(!type.isNonNullable(), + shouldBeTrue(!type.isNonNullableRef(), index, "non-nullable local's sets must dominate gets"); } @@ -5354,13 +5352,13 @@ void validateTables(Module& module, ValidationInfo& info) { info.shouldBeTrue(table->initial <= table->max, "table", "size minimum must not be greater than maximum"); - if (table->type.isNonNullable()) { + if (table->type.isNonNullableRef()) { info.shouldBeTrue(module.features.hasGC(), "table", "tables must have a nullable type in MVP " "(requires --enable-gc)."); } - if (!table->imported() && table->type.isNonNullable()) { + if (!table->imported() && table->type.isNonNullableRef()) { info.shouldBeTrue(table->init, "table", "module-defined tables with non-nullable types require " diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 8c142689153..0225e3dbb56 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1124,7 +1124,7 @@ void RefCast::finalize() { assert(heapType); auto exactness = desc->type.getExactness(); type = type.with(*heapType).with(exactness); - if (ref->type.isNonNullable()) { + if (ref->type.isNonNullableRef()) { type = type.with(NonNullable); } return; @@ -1194,7 +1194,7 @@ void BrOn::finalize() { assert(heapType); auto exactness = desc->type.getExactness(); castType = castType.with(*heapType).with(exactness); - if (ref->type.isNonNullable()) { + if (ref->type.isNonNullableRef()) { castType = castType.with(NonNullable); } } @@ -1211,7 +1211,7 @@ void BrOn::finalize() { return; case BrOnCast: case BrOnCastDescEq: - if (castType.isNullable()) { + if (castType.isNullableRef()) { // Nulls take the branch, so the result is non-nullable. type = ref->type.with(NonNullable); } else if (desc && desc->type.isNull()) { @@ -1226,7 +1226,7 @@ void BrOn::finalize() { return; case BrOnCastFail: case BrOnCastDescEqFail: - if (castType.isNullable()) { + if (castType.isNullableRef()) { // Nulls do not take the branch, so the result is non-nullable only if // the input is. type = castType.with(ref->type.getNullability()); @@ -1255,7 +1255,7 @@ Type BrOn::getSentType() { case BrOnCast: case BrOnCastDescEq: // The same as the result type of br_on_cast_fail. - if (castType.isNullable()) { + if (castType.isNullableRef()) { return castType.with(ref->type.getNullability()); } else { return castType; @@ -1271,7 +1271,7 @@ Type BrOn::getSentType() { // Model this with an uninhabitable sent type. return desc->type.with(NonNullable); } - if (castType.isNullable()) { + if (castType.isNullableRef()) { return ref->type.with(NonNullable); } else { return ref->type; diff --git a/test/gtest/type-domains.cpp b/test/gtest/type-domains.cpp index 98d3ea88fa3..235143a53ed 100644 --- a/test/gtest/type-domains.cpp +++ b/test/gtest/type-domains.cpp @@ -1084,7 +1084,7 @@ void TestBuiltTypes(std::pair, TypeBuilderPlan> pair) { auto checkRefType = [&](RefPlan& plan, Type type) { ASSERT_TRUE(type.isRef()); checkHeapType(plan.type, type.getHeapType()); - EXPECT_EQ(plan.nullable, type.isNullable()); + EXPECT_EQ(plan.nullable, type.isNullableRef()); }; auto checkType = [&](TypePlan& plan, Type type) { diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast index bd4fc50c5cb..df6d2423fe1 100644 --- a/test/lit/passes/precompute-gc.wast +++ b/test/lit/passes/precompute-gc.wast @@ -1195,7 +1195,7 @@ ;; CHECK-NEXT: ) (func $get-nonnullable-in-unreachable-tuple (result anyref i32) ;; As $get-nonnullable-in-unreachable but the local is a tuple (so we need to - ;; check isDefaultable, and not just isNullable). + ;; check isDefaultable, and not just isNullableRef). (local $x (tuple (ref any) i32)) (local.set $x (unreachable)