| 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 a0a5c1b2148cc7037a47c05adb81fb3cc8fc8b2f..608f14445520532499e3300ccbc496c8ddc4defa 100644
|
| --- a/src/compiler/js-native-context-specialization.cc
|
| +++ b/src/compiler/js-native-context-specialization.cc
|
| @@ -500,6 +500,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
|
| node->opcode() == IrOpcode::kJSStoreProperty);
|
| Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| + Node* context = NodeProperties::GetContextInput(node);
|
| Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
|
| Node* effect = NodeProperties::GetEffectInput(node);
|
| Node* control = NodeProperties::GetControlInput(node);
|
| @@ -547,7 +548,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| Node* this_receiver = receiver;
|
| Node* this_value = value;
|
| Node* this_index = index;
|
| - Node* this_effect = effect;
|
| + Node* this_effect;
|
| Node* this_control;
|
|
|
| // Perform map check on {receiver}.
|
| @@ -555,24 +556,77 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| bool receiver_is_jsarray = true;
|
| {
|
| 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();
|
| Node* check =
|
| - graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
|
| + graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
|
| receiver_map, jsgraph()->Constant(map));
|
| Node* branch =
|
| graph()->NewNode(common()->Branch(), check, fallthrough_control);
|
| this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
|
| + this_effects.push_back(effect);
|
| fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
|
| if (!map->IsJSArrayMap()) receiver_is_jsarray = false;
|
| }
|
| +
|
| + // Generate possible elements kind transitions.
|
| + for (auto transition : access_info.transitions()) {
|
| + Handle<Map> transition_source = transition.first;
|
| + Handle<Map> transition_target = transition.second;
|
| +
|
| + // Check if {receiver} has the specified {transition_source} map.
|
| + Node* check = graph()->NewNode(
|
| + simplified()->ReferenceEqual(Type::Any()), receiver_map,
|
| + jsgraph()->HeapConstant(transition_source));
|
| + Node* branch =
|
| + graph()->NewNode(common()->Branch(), check, fallthrough_control);
|
| +
|
| + // Migrate {receiver} from {transition_source} to {transition_target}.
|
| + Node* transition_control = graph()->NewNode(common()->IfTrue(), branch);
|
| + Node* transition_effect = effect;
|
| + 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(),
|
| + transition_source->IsJSArrayMap());
|
| + 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);
|
| +
|
| + fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
|
| + }
|
| +
|
| + // Create single chokepoint for the control.
|
| 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());
|
| + if (this_control_count == 1) {
|
| + this_control = this_controls.front();
|
| + this_effect = this_effects.front();
|
| + } else {
|
| + this_control =
|
| + graph()->NewNode(common()->Merge(this_control_count),
|
| + this_control_count, &this_controls.front());
|
| + this_effects.push_back(this_control);
|
| + this_effect =
|
| + graph()->NewNode(common()->EffectPhi(this_control_count),
|
| + this_control_count + 1, &this_effects.front());
|
| + }
|
| }
|
|
|
| // Certain stores need a prototype chain check because shape changes
|
|
|