diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc index eb77f708e2..9f4154aee9 100644 --- a/src/compiler/effect-control-linearizer.cc +++ b/src/compiler/effect-control-linearizer.cc @@ -714,6 +714,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, case IrOpcode::kCheckTaggedHole: state = LowerCheckTaggedHole(node, frame_state, *effect, *control); break; + case IrOpcode::kConvertTaggedHoleToUndefined: + state = LowerConvertTaggedHoleToUndefined(node, *effect, *control); + break; case IrOpcode::kPlainPrimitiveToNumber: state = LowerPlainPrimitiveToNumber(node, *effect, *control); break; @@ -2418,22 +2421,35 @@ EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state, EffectControlLinearizer::ValueEffectControl EffectControlLinearizer::LowerCheckTaggedHole(Node* node, Node* frame_state, Node* effect, Node* control) { - CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op()); Node* value = node->InputAt(0); Node* check = graph()->NewNode(machine()->WordEqual(), value, jsgraph()->TheHoleConstant()); - switch (mode) { - case CheckTaggedHoleMode::kConvertHoleToUndefined: - value = graph()->NewNode( - common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), - check, jsgraph()->UndefinedConstant(), value); - break; - case CheckTaggedHoleMode::kNeverReturnHole: - control = effect = - graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), - check, frame_state, effect, control); - break; - } + control = effect = + graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), check, + frame_state, effect, control); + + return ValueEffectControl(value, effect, control); +} + +EffectControlLinearizer::ValueEffectControl +EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node, + Node* effect, + Node* control) { + Node* value = node->InputAt(0); + Node* check = graph()->NewNode(machine()->WordEqual(), value, + jsgraph()->TheHoleConstant()); + Node* branch = + graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); + + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* vtrue = jsgraph()->UndefinedConstant(); + + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* vfalse = value; + + control = graph()->NewNode(common()->Merge(2), if_true, if_false); + value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), + vtrue, vfalse, control); return ValueEffectControl(value, effect, control); } diff --git a/src/compiler/effect-control-linearizer.h b/src/compiler/effect-control-linearizer.h index 1ba9051361..98f08c7b12 100644 --- a/src/compiler/effect-control-linearizer.h +++ b/src/compiler/effect-control-linearizer.h @@ -130,6 +130,8 @@ class EffectControlLinearizer { Node* effect, Node* control); ValueEffectControl LowerCheckTaggedHole(Node* node, Node* frame_state, Node* effect, Node* control); + ValueEffectControl LowerConvertTaggedHoleToUndefined(Node* node, Node* effect, + Node* control); ValueEffectControl LowerPlainPrimitiveToNumber(Node* node, Node* effect, Node* control); ValueEffectControl LowerPlainPrimitiveToWord32(Node* node, Node* effect, diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc index 0f6724ba28..28625c87f6 100644 --- a/src/compiler/js-native-context-specialization.cc +++ b/src/compiler/js-native-context-specialization.cc @@ -1158,7 +1158,7 @@ JSNativeContextSpecialization::BuildElementAccess( } // Compute the element access. - Type* element_type = Type::Any(); + Type* element_type = Type::NonInternal(); MachineType element_machine_type = MachineType::AnyTagged(); if (IsFastDoubleElementsKind(elements_kind)) { element_type = Type::Number(); @@ -1176,10 +1176,8 @@ JSNativeContextSpecialization::BuildElementAccess( // of holey backing stores. if (elements_kind == FAST_HOLEY_ELEMENTS || elements_kind == FAST_HOLEY_SMI_ELEMENTS) { - element_access.type = Type::Union( - element_type, - Type::Constant(factory()->the_hole_value(), graph()->zone()), - graph()->zone()); + element_access.type = + Type::Union(element_type, Type::Hole(), graph()->zone()); } // Perform the actual backing store access. value = effect = @@ -1189,15 +1187,16 @@ JSNativeContextSpecialization::BuildElementAccess( // the hole to undefined if possible, or deoptimizing otherwise. if (elements_kind == FAST_HOLEY_ELEMENTS || elements_kind == FAST_HOLEY_SMI_ELEMENTS) { - // Perform the hole check on the result. - CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; // Check if we are allowed to turn the hole into undefined. if (CanTreatHoleAsUndefined(receiver_maps, native_context)) { // Turn the hole into undefined. - mode = CheckTaggedHoleMode::kConvertHoleToUndefined; + value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), + value); + } else { + // Bailout if we see the hole. + value = effect = graph()->NewNode(simplified()->CheckTaggedHole(), + value, effect, control); } - value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode), - value, effect, control); } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { // Perform the hole check on the result. CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index 7f3f1eed94..3e9732dbab 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -290,6 +290,7 @@ V(CheckTaggedSigned) \ V(CheckFloat64Hole) \ V(CheckTaggedHole) \ + V(ConvertTaggedHoleToUndefined) \ V(Allocate) \ V(LoadField) \ V(LoadBuffer) \ diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index 6e560dbffc..1759a30354 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -2392,17 +2392,29 @@ class RepresentationSelector { return; } case IrOpcode::kCheckTaggedHole: { - CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op()); - if (truncation.IsUsedAsWord32() && - mode == CheckTaggedHoleMode::kConvertHoleToUndefined) { - ProcessInput(node, 0, UseInfo::CheckedSigned32AsWord32()); - ProcessRemainingInputs(node, 1); - SetOutput(node, MachineRepresentation::kWord32); + VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged); + return; + } + case IrOpcode::kConvertTaggedHoleToUndefined: { + if (InputIs(node, Type::NumberOrOddball()) && + truncation.IsUsedAsWord32()) { + // Propagate the Word32 truncation. + VisitUnop(node, UseInfo::TruncatingWord32(), + MachineRepresentation::kWord32); + if (lower()) DeferReplacement(node, node->InputAt(0)); + } else if (InputIs(node, Type::NumberOrOddball()) && + truncation.IsUsedAsFloat64()) { + // Propagate the Float64 truncation. + VisitUnop(node, UseInfo::TruncatingFloat64(), + MachineRepresentation::kFloat64); + if (lower()) DeferReplacement(node, node->InputAt(0)); + } else if (InputIs(node, Type::NonInternal())) { + VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged); if (lower()) DeferReplacement(node, node->InputAt(0)); } else { - ProcessInput(node, 0, UseInfo::AnyTagged()); - ProcessRemainingInputs(node, 1); - SetOutput(node, MachineRepresentation::kTagged); + // TODO(turbofan): Add a (Tagged) truncation that identifies hole + // and undefined, i.e. for a[i] === obj cases. + VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged); } return; } diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index f264999487..b20e5937a5 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -229,26 +229,6 @@ std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) { return os; } -size_t hash_value(CheckTaggedHoleMode mode) { - return static_cast(mode); -} - -std::ostream& operator<<(std::ostream& os, CheckTaggedHoleMode mode) { - switch (mode) { - case CheckTaggedHoleMode::kConvertHoleToUndefined: - return os << "convert-hole-to-undefined"; - case CheckTaggedHoleMode::kNeverReturnHole: - return os << "never-return-hole"; - } - UNREACHABLE(); - return os; -} - -CheckTaggedHoleMode CheckTaggedHoleModeOf(const Operator* op) { - DCHECK_EQ(IrOpcode::kCheckTaggedHole, op->opcode()); - return OpParameter(op); -} - size_t hash_value(CheckTaggedInputMode mode) { return static_cast(mode); } @@ -351,84 +331,85 @@ NumberOperationHint NumberOperationHintOf(const Operator* op) { return OpParameter(op); } -#define PURE_OP_LIST(V) \ - V(BooleanNot, Operator::kNoProperties, 1, 0) \ - V(NumberEqual, Operator::kCommutative, 2, 0) \ - V(NumberLessThan, Operator::kNoProperties, 2, 0) \ - V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \ - V(NumberAdd, Operator::kCommutative, 2, 0) \ - V(NumberSubtract, Operator::kNoProperties, 2, 0) \ - V(NumberMultiply, Operator::kCommutative, 2, 0) \ - V(NumberDivide, Operator::kNoProperties, 2, 0) \ - V(NumberModulus, Operator::kNoProperties, 2, 0) \ - V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \ - V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \ - V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \ - V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \ - V(NumberShiftRight, Operator::kNoProperties, 2, 0) \ - V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \ - V(NumberImul, Operator::kCommutative, 2, 0) \ - V(NumberAbs, Operator::kNoProperties, 1, 0) \ - V(NumberClz32, Operator::kNoProperties, 1, 0) \ - V(NumberCeil, Operator::kNoProperties, 1, 0) \ - V(NumberFloor, Operator::kNoProperties, 1, 0) \ - V(NumberFround, Operator::kNoProperties, 1, 0) \ - V(NumberAcos, Operator::kNoProperties, 1, 0) \ - V(NumberAcosh, Operator::kNoProperties, 1, 0) \ - V(NumberAsin, Operator::kNoProperties, 1, 0) \ - V(NumberAsinh, Operator::kNoProperties, 1, 0) \ - V(NumberAtan, Operator::kNoProperties, 1, 0) \ - V(NumberAtan2, Operator::kNoProperties, 2, 0) \ - V(NumberAtanh, Operator::kNoProperties, 1, 0) \ - V(NumberCbrt, Operator::kNoProperties, 1, 0) \ - V(NumberCos, Operator::kNoProperties, 1, 0) \ - V(NumberCosh, Operator::kNoProperties, 1, 0) \ - V(NumberExp, Operator::kNoProperties, 1, 0) \ - V(NumberExpm1, Operator::kNoProperties, 1, 0) \ - V(NumberLog, Operator::kNoProperties, 1, 0) \ - V(NumberLog1p, Operator::kNoProperties, 1, 0) \ - V(NumberLog10, Operator::kNoProperties, 1, 0) \ - V(NumberLog2, Operator::kNoProperties, 1, 0) \ - V(NumberMax, Operator::kNoProperties, 2, 0) \ - V(NumberMin, Operator::kNoProperties, 2, 0) \ - V(NumberPow, Operator::kNoProperties, 2, 0) \ - V(NumberRound, Operator::kNoProperties, 1, 0) \ - V(NumberSign, Operator::kNoProperties, 1, 0) \ - V(NumberSin, Operator::kNoProperties, 1, 0) \ - V(NumberSinh, Operator::kNoProperties, 1, 0) \ - V(NumberSqrt, Operator::kNoProperties, 1, 0) \ - V(NumberTan, Operator::kNoProperties, 1, 0) \ - V(NumberTanh, Operator::kNoProperties, 1, 0) \ - V(NumberTrunc, Operator::kNoProperties, 1, 0) \ - V(NumberToInt32, Operator::kNoProperties, 1, 0) \ - V(NumberToUint32, Operator::kNoProperties, 1, 0) \ - V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ - V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ - V(StringFromCharCode, Operator::kNoProperties, 1, 0) \ - V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ - V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \ - V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \ - V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \ - V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \ - V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \ - V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \ - V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \ - V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \ - V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \ - V(ChangeFloat64ToTagged, Operator::kNoProperties, 1, 0) \ - V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \ - V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \ - V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \ - V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \ - V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \ - V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \ - V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \ - V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \ - V(ObjectIsString, Operator::kNoProperties, 1, 0) \ - V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \ - V(ReferenceEqual, Operator::kCommutative, 2, 0) \ - V(StringEqual, Operator::kCommutative, 2, 0) \ - V(StringLessThan, Operator::kNoProperties, 2, 0) \ +#define PURE_OP_LIST(V) \ + V(BooleanNot, Operator::kNoProperties, 1, 0) \ + V(NumberEqual, Operator::kCommutative, 2, 0) \ + V(NumberLessThan, Operator::kNoProperties, 2, 0) \ + V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \ + V(NumberAdd, Operator::kCommutative, 2, 0) \ + V(NumberSubtract, Operator::kNoProperties, 2, 0) \ + V(NumberMultiply, Operator::kCommutative, 2, 0) \ + V(NumberDivide, Operator::kNoProperties, 2, 0) \ + V(NumberModulus, Operator::kNoProperties, 2, 0) \ + V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \ + V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \ + V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \ + V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \ + V(NumberShiftRight, Operator::kNoProperties, 2, 0) \ + V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \ + V(NumberImul, Operator::kCommutative, 2, 0) \ + V(NumberAbs, Operator::kNoProperties, 1, 0) \ + V(NumberClz32, Operator::kNoProperties, 1, 0) \ + V(NumberCeil, Operator::kNoProperties, 1, 0) \ + V(NumberFloor, Operator::kNoProperties, 1, 0) \ + V(NumberFround, Operator::kNoProperties, 1, 0) \ + V(NumberAcos, Operator::kNoProperties, 1, 0) \ + V(NumberAcosh, Operator::kNoProperties, 1, 0) \ + V(NumberAsin, Operator::kNoProperties, 1, 0) \ + V(NumberAsinh, Operator::kNoProperties, 1, 0) \ + V(NumberAtan, Operator::kNoProperties, 1, 0) \ + V(NumberAtan2, Operator::kNoProperties, 2, 0) \ + V(NumberAtanh, Operator::kNoProperties, 1, 0) \ + V(NumberCbrt, Operator::kNoProperties, 1, 0) \ + V(NumberCos, Operator::kNoProperties, 1, 0) \ + V(NumberCosh, Operator::kNoProperties, 1, 0) \ + V(NumberExp, Operator::kNoProperties, 1, 0) \ + V(NumberExpm1, Operator::kNoProperties, 1, 0) \ + V(NumberLog, Operator::kNoProperties, 1, 0) \ + V(NumberLog1p, Operator::kNoProperties, 1, 0) \ + V(NumberLog10, Operator::kNoProperties, 1, 0) \ + V(NumberLog2, Operator::kNoProperties, 1, 0) \ + V(NumberMax, Operator::kNoProperties, 2, 0) \ + V(NumberMin, Operator::kNoProperties, 2, 0) \ + V(NumberPow, Operator::kNoProperties, 2, 0) \ + V(NumberRound, Operator::kNoProperties, 1, 0) \ + V(NumberSign, Operator::kNoProperties, 1, 0) \ + V(NumberSin, Operator::kNoProperties, 1, 0) \ + V(NumberSinh, Operator::kNoProperties, 1, 0) \ + V(NumberSqrt, Operator::kNoProperties, 1, 0) \ + V(NumberTan, Operator::kNoProperties, 1, 0) \ + V(NumberTanh, Operator::kNoProperties, 1, 0) \ + V(NumberTrunc, Operator::kNoProperties, 1, 0) \ + V(NumberToInt32, Operator::kNoProperties, 1, 0) \ + V(NumberToUint32, Operator::kNoProperties, 1, 0) \ + V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ + V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ + V(StringFromCharCode, Operator::kNoProperties, 1, 0) \ + V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ + V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \ + V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \ + V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \ + V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \ + V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \ + V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \ + V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \ + V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \ + V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \ + V(ChangeFloat64ToTagged, Operator::kNoProperties, 1, 0) \ + V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \ + V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \ + V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \ + V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \ + V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \ + V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \ + V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \ + V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \ + V(ObjectIsString, Operator::kNoProperties, 1, 0) \ + V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \ + V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \ + V(ReferenceEqual, Operator::kCommutative, 2, 0) \ + V(StringEqual, Operator::kCommutative, 2, 0) \ + V(StringLessThan, Operator::kNoProperties, 2, 0) \ V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0) #define SPECULATIVE_NUMBER_BINOP_LIST(V) \ @@ -442,6 +423,7 @@ NumberOperationHint NumberOperationHintOf(const Operator* op) { V(CheckIf, 1, 0) \ V(CheckNumber, 1, 1) \ V(CheckString, 1, 1) \ + V(CheckTaggedHole, 1, 1) \ V(CheckTaggedPointer, 1, 1) \ V(CheckTaggedSigned, 1, 1) \ V(CheckedInt32Add, 2, 1) \ @@ -546,19 +528,6 @@ struct SimplifiedOperatorGlobalCache final { CheckFloat64HoleNaNOperator kCheckFloat64HoleNeverReturnHoleOperator; - template - struct CheckTaggedHoleOperator final : public Operator1 { - CheckTaggedHoleOperator() - : Operator1( - IrOpcode::kCheckTaggedHole, - Operator::kFoldable | Operator::kNoThrow, "CheckTaggedHole", 1, 1, - 1, 1, 1, 0, kMode) {} - }; - CheckTaggedHoleOperator - kCheckTaggedHoleConvertHoleToUndefinedOperator; - CheckTaggedHoleOperator - kCheckTaggedHoleNeverReturnHoleOperator; - template struct AllocateOperator final : public Operator1 { AllocateOperator() @@ -706,18 +675,6 @@ const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole( return nullptr; } -const Operator* SimplifiedOperatorBuilder::CheckTaggedHole( - CheckTaggedHoleMode mode) { - switch (mode) { - case CheckTaggedHoleMode::kConvertHoleToUndefined: - return &cache_.kCheckTaggedHoleConvertHoleToUndefinedOperator; - case CheckTaggedHoleMode::kNeverReturnHole: - return &cache_.kCheckTaggedHoleNeverReturnHoleOperator; - } - UNREACHABLE(); - return nullptr; -} - const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() { return &cache_.kEnsureWritableFastElements; } diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index 048d5becd2..6eac65880e 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -119,17 +119,6 @@ std::ostream& operator<<(std::ostream&, CheckFloat64HoleMode); CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator*) WARN_UNUSED_RESULT; -enum class CheckTaggedHoleMode : uint8_t { - kNeverReturnHole, // Never return the hole (deoptimize instead). - kConvertHoleToUndefined // Convert the hole to undefined. -}; - -size_t hash_value(CheckTaggedHoleMode); - -std::ostream& operator<<(std::ostream&, CheckTaggedHoleMode); - -CheckTaggedHoleMode CheckTaggedHoleModeOf(const Operator*) WARN_UNUSED_RESULT; - enum class CheckTaggedInputMode : uint8_t { kNumber, kNumberOrOddball, @@ -339,7 +328,8 @@ class SimplifiedOperatorBuilder final : public ZoneObject { const Operator* CheckedTruncateTaggedToWord32(); const Operator* CheckFloat64Hole(CheckFloat64HoleMode); - const Operator* CheckTaggedHole(CheckTaggedHoleMode); + const Operator* CheckTaggedHole(); + const Operator* ConvertTaggedHoleToUndefined(); const Operator* ObjectIsCallable(); const Operator* ObjectIsNumber(); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 57643c3e1f..006029cd1a 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -1234,7 +1234,7 @@ Type* Typer::Visitor::WrapContextTypeForInput(Node* node) { if (outer->Is(Type::None())) { return Type::None(); } else { - DCHECK(outer->Maybe(Type::Internal())); + DCHECK(outer->Maybe(Type::OtherInternal())); return Type::Context(outer, zone()); } } @@ -1583,19 +1583,17 @@ Type* Typer::Visitor::TypeCheckFloat64Hole(Node* node) { } Type* Typer::Visitor::TypeCheckTaggedHole(Node* node) { - CheckTaggedHoleMode mode = CheckTaggedHoleModeOf(node->op()); Type* type = Operand(node, 0); type = Type::Intersect(type, Type::NonInternal(), zone()); - switch (mode) { - case CheckTaggedHoleMode::kConvertHoleToUndefined: { - // The hole is turned into undefined. - type = Type::Union(type, Type::Undefined(), zone()); - break; - } - case CheckTaggedHoleMode::kNeverReturnHole: { - // We deoptimize in case of the hole. - break; - } + return type; +} + +Type* Typer::Visitor::TypeConvertTaggedHoleToUndefined(Node* node) { + Type* type = Operand(node, 0); + if (type->Maybe(Type::Hole())) { + // Turn "the hole" into undefined. + type = Type::Intersect(type, Type::NonInternal(), zone()); + type = Type::Union(type, Type::Undefined(), zone()); } return type; } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index eabd99dcf4..770c97f078 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -1042,7 +1042,11 @@ void Verifier::Visitor::Check(Node* node) { break; case IrOpcode::kCheckTaggedHole: CheckValueInputIs(node, 0, Type::Any()); - CheckUpperIs(node, Type::Any()); + CheckUpperIs(node, Type::NonInternal()); + break; + case IrOpcode::kConvertTaggedHoleToUndefined: + CheckValueInputIs(node, 0, Type::Any()); + CheckUpperIs(node, Type::NonInternal()); break; case IrOpcode::kLoadField: diff --git a/src/heap/heap.cc b/src/heap/heap.cc index 46f114f11d..e7d7eedc2f 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -2609,6 +2609,8 @@ void Heap::CreateInitialObjects() { set_nan_value(*factory->NewHeapNumber( std::numeric_limits::quiet_NaN(), IMMUTABLE, TENURED)); + set_hole_nan_value(*factory->NewHeapNumber(bit_cast(kHoleNanInt64), + IMMUTABLE, TENURED)); set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, IMMUTABLE, TENURED)); set_minus_infinity_value( *factory->NewHeapNumber(-V8_INFINITY, IMMUTABLE, TENURED)); @@ -2629,7 +2631,7 @@ void Heap::CreateInitialObjects() { // Initialize the_hole_value. Oddball::Initialize(isolate(), factory->the_hole_value(), "hole", - handle(Smi::FromInt(-1), isolate()), "undefined", + factory->hole_nan_value(), "undefined", Oddball::kTheHole); // Initialize the true_value. diff --git a/src/heap/heap.h b/src/heap/heap.h index 3f1d4e42d9..8e443799ee 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -166,6 +166,7 @@ using v8::MemoryPressureLevel; V(Cell, species_protector, SpeciesProtector) \ /* Special numbers */ \ V(HeapNumber, nan_value, NanValue) \ + V(HeapNumber, hole_nan_value, HoleNanValue) \ V(HeapNumber, infinity_value, InfinityValue) \ V(HeapNumber, minus_zero_value, MinusZeroValue) \ V(HeapNumber, minus_infinity_value, MinusInfinityValue) \ diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 13342ca36a..b6ec9a2ac6 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -601,7 +601,8 @@ void Oddball::OddballVerify() { VerifyHeapPointer(to_string()); Object* number = to_number(); if (number->IsHeapObject()) { - CHECK(number == heap->nan_value()); + CHECK(number == heap->nan_value() || + number == heap->hole_nan_value()); } else { CHECK(number->IsSmi()); int value = Smi::cast(number)->value(); diff --git a/src/types.cc b/src/types.cc index a48736bb99..c978dac5c2 100644 --- a/src/types.cc +++ b/src/types.cc @@ -147,10 +147,10 @@ Type::bitset BitsetType::Lub(Type* type) { if (type->IsClass()) return type->AsClass()->Lub(); if (type->IsConstant()) return type->AsConstant()->Lub(); if (type->IsRange()) return type->AsRange()->Lub(); - if (type->IsContext()) return kInternal & kTaggedPointer; + if (type->IsContext()) return kOtherInternal & kTaggedPointer; if (type->IsArray()) return kOtherObject; if (type->IsFunction()) return kFunction; - if (type->IsTuple()) return kInternal; + if (type->IsTuple()) return kOtherInternal; UNREACHABLE(); return kNone; } @@ -187,14 +187,14 @@ Type::bitset BitsetType::Lub(i::Map* map) { if (map == heap->undefined_map()) return kUndefined; if (map == heap->null_map()) return kNull; if (map == heap->boolean_map()) return kBoolean; - DCHECK(map == heap->the_hole_map() || - map == heap->uninitialized_map() || + if (map == heap->the_hole_map()) return kHole; + DCHECK(map == heap->uninitialized_map() || map == heap->no_interceptor_result_sentinel_map() || map == heap->termination_exception_map() || map == heap->arguments_marker_map() || map == heap->optimized_out_map() || map == heap->stale_register_map()); - return kInternal & kTaggedPointer; + return kOtherInternal & kTaggedPointer; } case HEAP_NUMBER_TYPE: return kNumber & kTaggedPointer; @@ -250,10 +250,10 @@ Type::bitset BitsetType::Lub(i::Map* map) { case SCRIPT_TYPE: case CODE_TYPE: case PROPERTY_CELL_TYPE: - return kInternal & kTaggedPointer; + return kOtherInternal & kTaggedPointer; // Remaining instance types are unsupported for now. If any of them do - // require bit set types, they should get kInternal & kTaggedPointer. + // require bit set types, they should get kOtherInternal & kTaggedPointer. case MUTABLE_HEAP_NUMBER_TYPE: case FREE_SPACE_TYPE: #define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ diff --git a/src/types.h b/src/types.h index 79ed85bc6e..c3c51dc0c2 100644 --- a/src/types.h +++ b/src/types.h @@ -199,7 +199,8 @@ namespace internal { V(OtherUndetectable, 1u << 16 | REPRESENTATION(kTaggedPointer)) \ V(Proxy, 1u << 18 | REPRESENTATION(kTaggedPointer)) \ V(Function, 1u << 19 | REPRESENTATION(kTaggedPointer)) \ - V(Internal, 1u << 20 | REPRESENTATION(kTagged | kUntagged)) \ + V(Hole, 1u << 20 | REPRESENTATION(kTaggedPointer)) \ + V(OtherInternal, 1u << 21 | REPRESENTATION(kTagged | kUntagged)) \ \ V(Signed31, kUnsigned30 | kNegative31) \ V(Signed32, kSigned31 | kOtherUnsigned31 | kOtherSigned32) \ @@ -225,7 +226,7 @@ namespace internal { V(NullOrNumber, kNull | kNumber) \ V(NullOrUndefined, kNull | kUndefined) \ V(Undetectable, kNullOrUndefined | kOtherUndetectable) \ - V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean) \ + V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean | kHole) \ V(NumberOrSimdOrString, kNumber | kSimd | kString) \ V(NumberOrString, kNumber | kString) \ V(NumberOrUndefined, kNumber | kUndefined) \ @@ -237,6 +238,7 @@ namespace internal { V(StringOrReceiver, kString | kReceiver) \ V(Unique, kBoolean | kUniqueName | kNull | kUndefined | \ kReceiver) \ + V(Internal, kHole | kOtherInternal) \ V(NonInternal, kPrimitive | kReceiver) \ V(NonNumber, kUnique | kString | kInternal) \ V(Any, 0xfffffffeu)