[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:
bmeurer 2016-06-28 06:08:26 -07:00 committed by Commit bot
parent 5ff508a822
commit d5ed22808f
10 changed files with 71 additions and 13 deletions

View File

@ -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) {

View File

@ -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,

View File

@ -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 =

View File

@ -237,6 +237,7 @@
V(ChangeTaggedToBit) \
V(ChangeBitToTagged) \
V(CheckBounds) \
V(CheckNumber) \
V(CheckTaggedPointer) \
V(CheckTaggedSigned) \
V(CheckedInt32Add) \

View File

@ -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:

View File

@ -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()) {

View File

@ -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) \

View File

@ -239,6 +239,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* TruncateTaggedToFloat64();
const Operator* CheckBounds();
const Operator* CheckNumber();
const Operator* CheckTaggedPointer();
const Operator* CheckTaggedSigned();

View File

@ -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());

View File

@ -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());