Index: src/compiler/js-native-context-specialization.cc |
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc |
index 3492af1d7f28187093239f763faad2695b50c69c..72086fa2a3a5bbfd5f4dd94d11e1060b779f3924 100644 |
--- a/src/compiler/js-native-context-specialization.cc |
+++ b/src/compiler/js-native-context-specialization.cc |
@@ -488,7 +488,6 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
node->opcode() == IrOpcode::kJSStoreProperty); |
Node* receiver = NodeProperties::GetValueInput(node, 0); |
- Node* context = NodeProperties::GetContextInput(node); |
Node* effect = NodeProperties::GetEffectInput(node); |
Node* control = NodeProperties::GetControlInput(node); |
Node* frame_state = NodeProperties::FindFrameStateBefore(node); |
@@ -525,12 +524,6 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), |
receiver, effect, control); |
- // Load the {receiver} map. The resulting effect is the dominating effect for |
- // all (polymorphic) branches. |
- Node* receiver_map = effect = |
- graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
- receiver, effect, control); |
- |
// Generate code for the various different element access patterns. |
Node* fallthrough_control = control; |
for (size_t j = 0; j < access_infos.size(); ++j) { |
@@ -538,8 +531,28 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
Node* this_receiver = receiver; |
Node* this_value = value; |
Node* this_index = index; |
- Node* this_effect; |
- Node* this_control; |
+ Node* this_effect = effect; |
+ Node* this_control = fallthrough_control; |
+ |
+ // Perform possible elements kind transitions. |
+ for (auto transition : access_info.transitions()) { |
+ Handle<Map> const transition_source = transition.first; |
+ Handle<Map> const transition_target = transition.second; |
+ this_effect = graph()->NewNode( |
+ simplified()->TransitionElementsKind( |
+ IsSimpleMapChangeTransition(transition_source->elements_kind(), |
+ transition_target->elements_kind()) |
+ ? ElementsTransition::kFastTransition |
+ : ElementsTransition::kSlowTransition), |
+ receiver, jsgraph()->HeapConstant(transition_source), |
+ jsgraph()->HeapConstant(transition_target), this_effect, |
+ this_control); |
+ } |
+ |
+ // Load the {receiver} map. |
+ Node* receiver_map = this_effect = |
+ graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
+ receiver, this_effect, this_control); |
// Perform map check on {receiver}. |
Type* receiver_type = access_info.receiver_type(); |
@@ -547,7 +560,6 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
{ |
ZoneVector<Node*> this_controls(zone()); |
ZoneVector<Node*> this_effects(zone()); |
- size_t num_transitions = access_info.transitions().size(); |
int num_classes = access_info.receiver_type()->NumClasses(); |
for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
i.Advance()) { |
@@ -556,16 +568,15 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
Node* check = |
graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
receiver_map, jsgraph()->Constant(map)); |
- if (--num_classes == 0 && num_transitions == 0 && |
- j == access_infos.size() - 1) { |
+ if (--num_classes == 0 && j == access_infos.size() - 1) { |
// Last map check on the fallthrough control path, do a conditional |
// eager deoptimization exit here. |
// TODO(turbofan): This is ugly as hell! We should probably introduce |
// macro-ish operators for property access that encapsulate this whole |
// mess. |
- check = graph()->NewNode(simplified()->CheckIf(), check, effect, |
- fallthrough_control); |
- this_controls.push_back(fallthrough_control); |
+ check = graph()->NewNode(simplified()->CheckIf(), check, this_effect, |
+ this_control); |
+ this_controls.push_back(this_control); |
this_effects.push_back(check); |
fallthrough_control = nullptr; |
} else { |
@@ -578,57 +589,6 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
if (!map->IsJSArrayMap()) receiver_is_jsarray = false; |
} |
- // Generate possible elements kind transitions. |
- for (auto transition : access_info.transitions()) { |
- DCHECK_LT(0u, num_transitions); |
- Handle<Map> transition_source = transition.first; |
- Handle<Map> transition_target = transition.second; |
- Node* transition_control; |
- Node* transition_effect = effect; |
- |
- // Check if {receiver} has the specified {transition_source} map. |
- Node* check = graph()->NewNode( |
- simplified()->ReferenceEqual(Type::Any()), receiver_map, |
- jsgraph()->HeapConstant(transition_source)); |
- if (--num_transitions == 0 && j == access_infos.size() - 1) { |
- transition_effect = |
- graph()->NewNode(simplified()->CheckIf(), check, |
- transition_effect, fallthrough_control); |
- transition_control = fallthrough_control; |
- fallthrough_control = nullptr; |
- } else { |
- Node* branch = |
- graph()->NewNode(common()->Branch(), check, fallthrough_control); |
- fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
- transition_control = graph()->NewNode(common()->IfTrue(), branch); |
- } |
- |
- // Migrate {receiver} from {transition_source} to {transition_target}. |
- if (IsSimpleMapChangeTransition(transition_source->elements_kind(), |
- transition_target->elements_kind())) { |
- // In-place migration, just store the {transition_target} map. |
- transition_effect = graph()->NewNode( |
- simplified()->StoreField(AccessBuilder::ForMap()), receiver, |
- jsgraph()->HeapConstant(transition_target), transition_effect, |
- transition_control); |
- } else { |
- // Instance migration, let the stub deal with the {receiver}. |
- TransitionElementsKindStub stub(isolate(), |
- transition_source->elements_kind(), |
- transition_target->elements_kind()); |
- CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
- isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0, |
- CallDescriptor::kNeedsFrameState, node->op()->properties()); |
- transition_effect = graph()->NewNode( |
- common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()), |
- receiver, jsgraph()->HeapConstant(transition_target), context, |
- frame_state, transition_effect, transition_control); |
- } |
- |
- this_controls.push_back(transition_control); |
- this_effects.push_back(transition_effect); |
- } |
- |
// Create single chokepoint for the control. |
int const this_control_count = static_cast<int>(this_controls.size()); |
if (this_control_count == 1) { |
@@ -642,15 +602,15 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( |
this_effect = |
graph()->NewNode(common()->EffectPhi(this_control_count), |
this_control_count + 1, &this_effects.front()); |
- } |
- // TODO(turbofan): The effect/control linearization will not find a |
- // FrameState after the StoreField or Call that is generated for the |
- // elements kind transition above. This is because those operators |
- // don't have the kNoWrite flag on it, even though they are not |
- // observable by JavaScript. |
- this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, |
- this_effect, this_control); |
+ // TODO(turbofan): The effect/control linearization will not find a |
+ // FrameState after the StoreField or Call that is generated for the |
+ // elements kind transition above. This is because those operators |
+ // don't have the kNoWrite flag on it, even though they are not |
+ // observable by JavaScript. |
+ this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, |
+ this_effect, this_control); |
+ } |
} |
// Certain stores need a prototype chain check because shape changes |