[turbofan] Introduce a dedicated ConvertTaggedHoleToUndefined operator.
Separate ConvertTaggedHoleToUndefined and CheckTaggedHole into two separate operators, where the former is pure and just turns into trivial control flow in the EffectControlLinearizer. R=jarin@chromium.org Review-Url: https://codereview.chromium.org/2236443004 Cr-Commit-Position: refs/heads/master@{#38559}
This commit is contained in:
parent
73b0f15714
commit
e61bd68ede
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -290,6 +290,7 @@
|
||||
V(CheckTaggedSigned) \
|
||||
V(CheckFloat64Hole) \
|
||||
V(CheckTaggedHole) \
|
||||
V(ConvertTaggedHoleToUndefined) \
|
||||
V(Allocate) \
|
||||
V(LoadField) \
|
||||
V(LoadBuffer) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -229,26 +229,6 @@ std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) {
|
||||
return os;
|
||||
}
|
||||
|
||||
size_t hash_value(CheckTaggedHoleMode mode) {
|
||||
return static_cast<size_t>(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<CheckTaggedHoleMode>(op);
|
||||
}
|
||||
|
||||
size_t hash_value(CheckTaggedInputMode mode) {
|
||||
return static_cast<size_t>(mode);
|
||||
}
|
||||
@ -351,84 +331,85 @@ NumberOperationHint NumberOperationHintOf(const Operator* op) {
|
||||
return OpParameter<NumberOperationHint>(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<CheckFloat64HoleMode::kNeverReturnHole>
|
||||
kCheckFloat64HoleNeverReturnHoleOperator;
|
||||
|
||||
template <CheckTaggedHoleMode kMode>
|
||||
struct CheckTaggedHoleOperator final : public Operator1<CheckTaggedHoleMode> {
|
||||
CheckTaggedHoleOperator()
|
||||
: Operator1<CheckTaggedHoleMode>(
|
||||
IrOpcode::kCheckTaggedHole,
|
||||
Operator::kFoldable | Operator::kNoThrow, "CheckTaggedHole", 1, 1,
|
||||
1, 1, 1, 0, kMode) {}
|
||||
};
|
||||
CheckTaggedHoleOperator<CheckTaggedHoleMode::kConvertHoleToUndefined>
|
||||
kCheckTaggedHoleConvertHoleToUndefinedOperator;
|
||||
CheckTaggedHoleOperator<CheckTaggedHoleMode::kNeverReturnHole>
|
||||
kCheckTaggedHoleNeverReturnHoleOperator;
|
||||
|
||||
template <PretenureFlag kPretenure>
|
||||
struct AllocateOperator final : public Operator1<PretenureFlag> {
|
||||
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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -2609,6 +2609,8 @@ void Heap::CreateInitialObjects() {
|
||||
|
||||
set_nan_value(*factory->NewHeapNumber(
|
||||
std::numeric_limits<double>::quiet_NaN(), IMMUTABLE, TENURED));
|
||||
set_hole_nan_value(*factory->NewHeapNumber(bit_cast<double>(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.
|
||||
|
@ -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) \
|
||||
|
@ -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();
|
||||
|
14
src/types.cc
14
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) \
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user