[turbofan] Introduce proper CheckNumber operator.
We use CheckNumber to guard values as being proper numbers, i.e. if the input value is anything but a Number, we deoptimize. This follows the existing effect/control linearization magic that we already use for the other checks. R=jarin@chromium.org BUG=v8:5141 Review-Url: https://codereview.chromium.org/2109623002 Cr-Commit-Position: refs/heads/master@{#37329}
This commit is contained in:
parent
5ff508a822
commit
d5ed22808f
@ -434,6 +434,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
case IrOpcode::kCheckBounds:
|
||||
state = LowerCheckBounds(node, frame_state, *effect, *control);
|
||||
break;
|
||||
case IrOpcode::kCheckNumber:
|
||||
state = LowerCheckNumber(node, frame_state, *effect, *control);
|
||||
break;
|
||||
case IrOpcode::kCheckTaggedPointer:
|
||||
state = LowerCheckTaggedPointer(node, frame_state, *effect, *control);
|
||||
break;
|
||||
@ -809,6 +812,39 @@ EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state,
|
||||
return ValueEffectControl(index, effect, control);
|
||||
}
|
||||
|
||||
EffectControlLinearizer::ValueEffectControl
|
||||
EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state,
|
||||
Node* effect, Node* control) {
|
||||
Node* value = node->InputAt(0);
|
||||
|
||||
Node* check0 = ObjectIsSmi(value);
|
||||
Node* branch0 =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
|
||||
|
||||
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
||||
Node* etrue0 = effect;
|
||||
|
||||
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
||||
Node* efalse0 = effect;
|
||||
{
|
||||
Node* value_map = efalse0 =
|
||||
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
|
||||
value, efalse0, if_false0);
|
||||
Node* check1 = graph()->NewNode(machine()->WordEqual(), value_map,
|
||||
jsgraph()->HeapNumberMapConstant());
|
||||
if_false0 = efalse0 = graph()->NewNode(common()->DeoptimizeUnless(), check1,
|
||||
frame_state, efalse0, if_false0);
|
||||
}
|
||||
|
||||
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
|
||||
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
|
||||
|
||||
// Make sure the lowered node does not appear in any use lists.
|
||||
node->TrimInputCount(0);
|
||||
|
||||
return ValueEffectControl(value, effect, control);
|
||||
}
|
||||
|
||||
EffectControlLinearizer::ValueEffectControl
|
||||
EffectControlLinearizer::LowerCheckTaggedPointer(Node* node, Node* frame_state,
|
||||
Node* effect, Node* control) {
|
||||
|
@ -64,6 +64,8 @@ class EffectControlLinearizer {
|
||||
Node* control);
|
||||
ValueEffectControl LowerCheckBounds(Node* node, Node* frame_state,
|
||||
Node* effect, Node* control);
|
||||
ValueEffectControl LowerCheckNumber(Node* node, Node* frame_state,
|
||||
Node* effect, Node* control);
|
||||
ValueEffectControl LowerCheckTaggedPointer(Node* node, Node* frame_state,
|
||||
Node* effect, Node* control);
|
||||
ValueEffectControl LowerCheckTaggedSigned(Node* node, Node* frame_state,
|
||||
|
@ -276,13 +276,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
} else {
|
||||
DCHECK_EQ(AccessMode::kStore, access_mode);
|
||||
if (field_type->Is(Type::UntaggedFloat64())) {
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
|
||||
this_control = this_effect =
|
||||
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
|
||||
this_value = this_effect =
|
||||
graph()->NewNode(simplified()->CheckNumber(), this_value,
|
||||
this_effect, this_control);
|
||||
this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
|
||||
this_value, this_control);
|
||||
|
||||
if (!field_index.is_inobject() || field_index.is_hidden_field() ||
|
||||
!FLAG_unbox_double_fields) {
|
||||
@ -784,13 +780,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
|
||||
this_effect, this_control);
|
||||
} else if (IsFastDoubleElementsKind(elements_kind)) {
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
|
||||
this_control = this_effect =
|
||||
graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
|
||||
this_effect, this_control);
|
||||
this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
|
||||
this_value, this_control);
|
||||
this_value = this_effect = graph()->NewNode(
|
||||
simplified()->CheckNumber(), this_value, this_effect, this_control);
|
||||
// Make sure we do not store signalling NaNs into holey double arrays.
|
||||
if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
|
||||
this_value =
|
||||
|
@ -237,6 +237,7 @@
|
||||
V(ChangeTaggedToBit) \
|
||||
V(ChangeBitToTagged) \
|
||||
V(CheckBounds) \
|
||||
V(CheckNumber) \
|
||||
V(CheckTaggedPointer) \
|
||||
V(CheckTaggedSigned) \
|
||||
V(CheckedInt32Add) \
|
||||
|
@ -17,7 +17,9 @@ RedundancyElimination::~RedundancyElimination() {}
|
||||
|
||||
Reduction RedundancyElimination::Reduce(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kCheckBounds:
|
||||
case IrOpcode::kCheckFloat64Hole:
|
||||
case IrOpcode::kCheckNumber:
|
||||
case IrOpcode::kCheckTaggedHole:
|
||||
case IrOpcode::kCheckTaggedPointer:
|
||||
case IrOpcode::kCheckTaggedSigned:
|
||||
|
@ -1687,6 +1687,21 @@ class RepresentationSelector {
|
||||
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kCheckNumber: {
|
||||
if (InputIs(node, Type::Number())) {
|
||||
if (truncation.TruncatesToWord32()) {
|
||||
VisitUnop(node, UseInfo::TruncatingWord32(),
|
||||
MachineRepresentation::kWord32);
|
||||
} else {
|
||||
VisitUnop(node, UseInfo::TruncatingFloat64(),
|
||||
MachineRepresentation::kFloat64);
|
||||
}
|
||||
if (lower()) DeferReplacement(node, node->InputAt(0));
|
||||
} else {
|
||||
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kCheckTaggedPointer: {
|
||||
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
|
||||
if (lower()) {
|
||||
|
@ -311,6 +311,7 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
|
||||
V(SpeculativeNumberModulus)
|
||||
|
||||
#define CHECKED_OP_LIST(V) \
|
||||
V(CheckNumber, 1) \
|
||||
V(CheckTaggedPointer, 1) \
|
||||
V(CheckTaggedSigned, 1) \
|
||||
V(CheckedInt32Add, 2) \
|
||||
|
@ -239,6 +239,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
|
||||
const Operator* TruncateTaggedToFloat64();
|
||||
|
||||
const Operator* CheckBounds();
|
||||
const Operator* CheckNumber();
|
||||
const Operator* CheckTaggedPointer();
|
||||
const Operator* CheckTaggedSigned();
|
||||
|
||||
|
@ -1828,6 +1828,11 @@ Type* Typer::Visitor::TypeCheckBounds(Node* node) {
|
||||
return Type::Unsigned31();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeCheckNumber(Node* node) {
|
||||
Type* arg = Operand(node, 0);
|
||||
return Type::Intersect(arg, Type::Number(), zone());
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeCheckTaggedPointer(Node* node) {
|
||||
Type* arg = Operand(node, 0);
|
||||
return Type::Intersect(arg, Type::TaggedPointer(), zone());
|
||||
|
@ -947,6 +947,10 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
CheckValueInputIs(node, 1, Type::Unsigned31());
|
||||
CheckUpperIs(node, Type::Unsigned31());
|
||||
break;
|
||||
case IrOpcode::kCheckNumber:
|
||||
CheckValueInputIs(node, 0, Type::Any());
|
||||
CheckUpperIs(node, Type::Number());
|
||||
break;
|
||||
case IrOpcode::kCheckTaggedSigned:
|
||||
CheckValueInputIs(node, 0, Type::Any());
|
||||
CheckUpperIs(node, Type::TaggedSigned());
|
||||
|
Loading…
Reference in New Issue
Block a user