[turbofan] Finish support for holey double elements backing stores.
Also properly support loading from holey double element backing stores in JSNativeContextSpecialization. This adds a new simplified operator NumberIsHoleNaN, which checks whether a certain value is the special NaN that we use to encode "the hole" in holey double element backing stores. R=jarin@chromium.org BUG=v8:4470 LOG=n Review URL: https://codereview.chromium.org/1448343002 Cr-Commit-Position: refs/heads/master@{#32039}
This commit is contained in:
parent
401efe2173
commit
5716426b26
@ -141,11 +141,6 @@ bool AccessInfoFactory::ComputeElementAccessInfo(
|
||||
if (!CanInlineElementAccess(map)) return false;
|
||||
|
||||
ElementsKind const elements_kind = map->elements_kind();
|
||||
if (access_mode == AccessMode::kLoad &&
|
||||
elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
|
||||
// TODO(bmeurer): Add support for holey loads.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Certain (monomorphic) stores need a prototype chain check because shape
|
||||
// changes could allow callbacks on elements in the chain that are not
|
||||
|
@ -711,7 +711,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
// Check if we are allowed to turn the hole into undefined.
|
||||
Type* initial_holey_array_type = Type::Class(
|
||||
handle(isolate()->get_initial_js_array_map(FAST_HOLEY_ELEMENTS)),
|
||||
handle(isolate()->get_initial_js_array_map(elements_kind)),
|
||||
graph()->zone());
|
||||
if (receiver_type->NowIs(initial_holey_array_type) &&
|
||||
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
|
||||
@ -736,6 +736,31 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
// hole).
|
||||
this_value = graph()->NewNode(common()->Guard(element_type), this_value,
|
||||
this_control);
|
||||
} else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
|
||||
// Perform the hole check on the result.
|
||||
Node* check =
|
||||
graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value);
|
||||
// Check if we are allowed to return the hole directly.
|
||||
Type* initial_holey_array_type = Type::Class(
|
||||
handle(isolate()->get_initial_js_array_map(elements_kind)),
|
||||
graph()->zone());
|
||||
if (receiver_type->NowIs(initial_holey_array_type) &&
|
||||
isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
|
||||
// Add a code dependency on the array protector cell.
|
||||
AssumePrototypesStable(receiver_type,
|
||||
isolate()->initial_object_prototype());
|
||||
dependencies()->AssumePropertyCell(factory()->array_protector());
|
||||
// Turn the hole into undefined.
|
||||
this_value = graph()->NewNode(
|
||||
common()->Select(kMachAnyTagged, BranchHint::kFalse), check,
|
||||
jsgraph()->UndefinedConstant(), this_value);
|
||||
} else {
|
||||
// Deoptimize in case of the hole.
|
||||
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
|
||||
check, this_control);
|
||||
this_control = graph()->NewNode(common()->IfFalse(), branch);
|
||||
exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DCHECK_EQ(AccessMode::kStore, access_mode);
|
||||
|
@ -747,6 +747,21 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
|
||||
if (result.Changed()) return result;
|
||||
return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
|
||||
}
|
||||
// Check for ToNumber truncation of signaling NaN to undefined mapping.
|
||||
if (input->opcode() == IrOpcode::kSelect) {
|
||||
Node* check = NodeProperties::GetValueInput(input, 0);
|
||||
Node* vtrue = NodeProperties::GetValueInput(input, 1);
|
||||
Type* vtrue_type = NodeProperties::GetType(vtrue);
|
||||
Node* vfalse = NodeProperties::GetValueInput(input, 2);
|
||||
Type* vfalse_type = NodeProperties::GetType(vfalse);
|
||||
if (vtrue_type->Is(Type::Undefined()) && vfalse_type->Is(Type::Number())) {
|
||||
if (check->opcode() == IrOpcode::kNumberIsHoleNaN &&
|
||||
check->InputAt(0) == vfalse) {
|
||||
// JSToNumber(Select(NumberIsHoleNaN(x), y:undefined, x:number)) => x
|
||||
return Replace(vfalse);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if we have a cached conversion.
|
||||
Type* input_type = NodeProperties::GetType(input);
|
||||
if (input_type->Is(Type::Number())) {
|
||||
|
@ -183,6 +183,7 @@
|
||||
V(NumberShiftRightLogical) \
|
||||
V(NumberToInt32) \
|
||||
V(NumberToUint32) \
|
||||
V(NumberIsHoleNaN) \
|
||||
V(PlainPrimitiveToNumber) \
|
||||
V(ChangeTaggedToInt32) \
|
||||
V(ChangeTaggedToUint32) \
|
||||
|
@ -776,6 +776,21 @@ class RepresentationSelector {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kNumberIsHoleNaN: {
|
||||
VisitUnop(node, kMachFloat64, kMachBool);
|
||||
if (lower()) {
|
||||
// NumberIsHoleNaN(x) => Word32Equal(Float64ExtractLowWord32(x),
|
||||
// #HoleNaNLower32)
|
||||
node->ReplaceInput(0,
|
||||
jsgraph_->graph()->NewNode(
|
||||
lowering->machine()->Float64ExtractLowWord32(),
|
||||
node->InputAt(0)));
|
||||
node->AppendInput(jsgraph_->zone(),
|
||||
jsgraph_->Int32Constant(kHoleNanLower32));
|
||||
NodeProperties::ChangeOp(node, jsgraph_->machine()->Word32Equal());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kPlainPrimitiveToNumber: {
|
||||
VisitUnop(node, kMachAnyTagged, kTypeNumber | kRepTagged);
|
||||
if (lower()) {
|
||||
|
@ -176,6 +176,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
|
||||
V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
|
||||
V(NumberToInt32, Operator::kNoProperties, 1) \
|
||||
V(NumberToUint32, Operator::kNoProperties, 1) \
|
||||
V(NumberIsHoleNaN, Operator::kNoProperties, 1) \
|
||||
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1) \
|
||||
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
|
||||
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
|
||||
|
@ -148,6 +148,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
|
||||
const Operator* NumberShiftRightLogical();
|
||||
const Operator* NumberToInt32();
|
||||
const Operator* NumberToUint32();
|
||||
const Operator* NumberIsHoleNaN();
|
||||
|
||||
const Operator* PlainPrimitiveToNumber();
|
||||
|
||||
|
@ -1677,6 +1677,11 @@ Type* Typer::Visitor::TypeNumberToUint32(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeNumberIsHoleNaN(Node* node) {
|
||||
return Type::Boolean(zone());
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypePlainPrimitiveToNumber(Node* node) {
|
||||
return TypeUnaryOp(node, ToNumber);
|
||||
}
|
||||
|
@ -673,6 +673,11 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
CheckValueInputIs(node, 0, Type::Number());
|
||||
CheckUpperIs(node, Type::Unsigned32());
|
||||
break;
|
||||
case IrOpcode::kNumberIsHoleNaN:
|
||||
// Number -> Boolean
|
||||
CheckValueInputIs(node, 0, Type::Number());
|
||||
CheckUpperIs(node, Type::Boolean());
|
||||
break;
|
||||
case IrOpcode::kPlainPrimitiveToNumber:
|
||||
// PlainPrimitive -> Number
|
||||
CheckValueInputIs(node, 0, Type::PlainPrimitive());
|
||||
|
Loading…
Reference in New Issue
Block a user