Commit 608ed2e2 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add support for named access to Number primitives.

Implement the missing bits for named access to Number values, which is
basically always done on the Number prototype.  Crankshaft only deals
with Number primitives in the polymorphic case, while we generally
support Numbers even for monomorphic access.

R=jarin@chromium.org
BUG=v8:4470
LOG=n

Review URL: https://codereview.chromium.org/1425293004

Cr-Commit-Position: refs/heads/master@{#31731}
parent 538197da
......@@ -28,8 +28,7 @@ bool CanInlineElementAccess(Handle<Map> map) {
bool CanInlinePropertyAccess(Handle<Map> map) {
// TODO(bmeurer): Add support for Number primitives.
// if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
return map->IsJSObjectMap() && !map->is_dictionary_map() &&
!map->has_named_interceptor() &&
......
......@@ -354,10 +354,10 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Ensure that {receiver} is a heap object.
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
Node* branch = graph()->NewNode(common()->Branch(), check, control);
control = graph()->NewNode(common()->IfFalse(), branch);
Node* receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
Node* receiverissmi_effect = effect;
// Load the {receiver} map. The resulting effect is the dominating effect for
// all (polymorphic) branches.
......@@ -388,8 +388,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
this_control = graph()->NewNode(common()->IfTrue(), branch);
} else {
// Emit a (sequence of) map checks for other properties.
// Emit a (sequence of) map checks for other {receiver}s.
ZoneVector<Node*> this_controls(zone());
ZoneVector<Node*> this_effects(zone());
for (auto i = access_info.receiver_type()->Classes(); !i.Done();
i.Advance()) {
Handle<Map> map = i.Current();
......@@ -398,15 +399,37 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
receiver_map, jsgraph()->Constant(map));
Node* branch =
graph()->NewNode(common()->Branch(), check, fallthrough_control);
this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
this_effects.push_back(this_effect);
}
// The Number case requires special treatment to also deal with Smis.
if (receiver_type->Is(Type::Number())) {
// Join this check with the "receiver is smi" check above, and mark the
// "receiver is smi" check as "consumed" so that we don't deoptimize if
// the {receiver} is actually a Smi.
if (receiverissmi_control != nullptr) {
this_controls.push_back(receiverissmi_control);
this_effects.push_back(receiverissmi_effect);
receiverissmi_control = receiverissmi_effect = nullptr;
}
}
// Create dominating Merge+EffectPhi for this {receiver} type.
int const this_control_count = static_cast<int>(this_controls.size());
this_control =
(this_control_count == 1)
? this_controls.front()
: graph()->NewNode(common()->Merge(this_control_count),
this_control_count, &this_controls.front());
this_effects.push_back(this_control);
int const this_effect_count = static_cast<int>(this_effects.size());
this_effect =
(this_control_count == 1)
? this_effects.front()
: graph()->NewNode(common()->EffectPhi(this_control_count),
this_effect_count, &this_effects.front());
}
// Determine actual holder and perform prototype chain checks.
......@@ -584,17 +607,19 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Collect the fallthrough control as final "exit" control.
if (fallthrough_control != control) {
// Mark the last fallthrough branch as deferred.
Node* branch = NodeProperties::GetControlInput(fallthrough_control);
DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
if (fallthrough_control->opcode() == IrOpcode::kIfTrue) {
NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
} else {
DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode());
NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
}
MarkAsDeferred(fallthrough_control);
}
exit_controls.push_back(fallthrough_control);
// Also collect the "receiver is smi" control if we didn't handle the case of
// Number primitives in the polymorphic branches above.
if (receiverissmi_control != nullptr) {
// Mark the "receiver is smi" case as deferred.
MarkAsDeferred(receiverissmi_control);
DCHECK_EQ(exit_effect, receiverissmi_effect);
exit_controls.push_back(receiverissmi_control);
}
// Generate the single "exit" point, where we get if either all map/instance
// type checks failed, or one of the assumptions inside one of the cases
// failes (i.e. failing prototype chain check).
......@@ -876,14 +901,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// Collect the fallthrough control as final "exit" control.
if (fallthrough_control != control) {
// Mark the last fallthrough branch as deferred.
Node* branch = NodeProperties::GetControlInput(fallthrough_control);
DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
if (fallthrough_control->opcode() == IrOpcode::kIfTrue) {
NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
} else {
DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode());
NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
}
MarkAsDeferred(fallthrough_control);
}
exit_controls.push_back(fallthrough_control);
......@@ -1053,6 +1071,18 @@ void JSNativeContextSpecialization::AssumePrototypesStable(
}
void JSNativeContextSpecialization::MarkAsDeferred(Node* if_projection) {
Node* branch = NodeProperties::GetControlInput(if_projection);
DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
if (if_projection->opcode() == IrOpcode::kIfTrue) {
NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
} else {
DCHECK_EQ(IrOpcode::kIfFalse, if_projection->opcode());
NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
}
}
Graph* JSNativeContextSpecialization::graph() const {
return jsgraph()->graph();
}
......
......@@ -87,6 +87,10 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
// {receiver_type} up to (and including) the {holder}.
void AssumePrototypesStable(Type* receiver_type, Handle<JSObject> holder);
// Assuming that {if_projection} is either IfTrue or IfFalse, adds a hint on
// the dominating Branch that {if_projection} is the unlikely (deferred) case.
void MarkAsDeferred(Node* if_projection);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment