| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/js-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 Node* node, Node* value, MapHandleList const& receiver_maps, | 73 Node* node, Node* value, MapHandleList const& receiver_maps, |
| 74 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, | 74 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, |
| 75 Node* index) { | 75 Node* index) { |
| 76 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || | 76 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || |
| 77 node->opcode() == IrOpcode::kJSStoreNamed || | 77 node->opcode() == IrOpcode::kJSStoreNamed || |
| 78 node->opcode() == IrOpcode::kJSLoadProperty || | 78 node->opcode() == IrOpcode::kJSLoadProperty || |
| 79 node->opcode() == IrOpcode::kJSStoreProperty); | 79 node->opcode() == IrOpcode::kJSStoreProperty); |
| 80 Node* receiver = NodeProperties::GetValueInput(node, 0); | 80 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 81 Node* effect = NodeProperties::GetEffectInput(node); | 81 Node* effect = NodeProperties::GetEffectInput(node); |
| 82 Node* control = NodeProperties::GetControlInput(node); | 82 Node* control = NodeProperties::GetControlInput(node); |
| 83 Node* frame_state = NodeProperties::FindFrameStateBefore(node); | |
| 84 | 83 |
| 85 // Not much we can do if deoptimization support is disabled. | 84 // Not much we can do if deoptimization support is disabled. |
| 86 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 85 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 87 | 86 |
| 88 // Retrieve the native context from the given {node}. | 87 // Retrieve the native context from the given {node}. |
| 89 Handle<Context> native_context; | 88 Handle<Context> native_context; |
| 90 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); | 89 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); |
| 91 | 90 |
| 92 // Compute property access infos for the receiver maps. | 91 // Compute property access infos for the receiver maps. |
| 93 AccessInfoFactory access_info_factory(dependencies(), native_context, | 92 AccessInfoFactory access_info_factory(dependencies(), native_context, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 104 // The final states for every polymorphic branch. We join them with | 103 // The final states for every polymorphic branch. We join them with |
| 105 // Merge++Phi+EffectPhi at the bottom. | 104 // Merge++Phi+EffectPhi at the bottom. |
| 106 ZoneVector<Node*> values(zone()); | 105 ZoneVector<Node*> values(zone()); |
| 107 ZoneVector<Node*> effects(zone()); | 106 ZoneVector<Node*> effects(zone()); |
| 108 ZoneVector<Node*> controls(zone()); | 107 ZoneVector<Node*> controls(zone()); |
| 109 | 108 |
| 110 // Ensure that {index} matches the specified {name} (if {index} is given). | 109 // Ensure that {index} matches the specified {name} (if {index} is given). |
| 111 if (index != nullptr) { | 110 if (index != nullptr) { |
| 112 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), | 111 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
| 113 index, jsgraph()->HeapConstant(name)); | 112 index, jsgraph()->HeapConstant(name)); |
| 114 control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check, | 113 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
| 115 frame_state, effect, control); | |
| 116 } | 114 } |
| 117 | 115 |
| 118 // Check if {receiver} may be a number. | 116 // Check if {receiver} may be a number. |
| 119 bool receiverissmi_possible = false; | 117 bool receiverissmi_possible = false; |
| 120 for (PropertyAccessInfo const& access_info : access_infos) { | 118 for (PropertyAccessInfo const& access_info : access_infos) { |
| 121 if (access_info.receiver_type()->Is(Type::Number())) { | 119 if (access_info.receiver_type()->Is(Type::Number())) { |
| 122 receiverissmi_possible = true; | 120 receiverissmi_possible = true; |
| 123 break; | 121 break; |
| 124 } | 122 } |
| 125 } | 123 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 151 Node* this_value = value; | 149 Node* this_value = value; |
| 152 Node* this_receiver = receiver; | 150 Node* this_receiver = receiver; |
| 153 Node* this_effect = effect; | 151 Node* this_effect = effect; |
| 154 Node* this_control; | 152 Node* this_control; |
| 155 | 153 |
| 156 // Perform map check on {receiver}. | 154 // Perform map check on {receiver}. |
| 157 Type* receiver_type = access_info.receiver_type(); | 155 Type* receiver_type = access_info.receiver_type(); |
| 158 if (receiver_type->Is(Type::String())) { | 156 if (receiver_type->Is(Type::String())) { |
| 159 Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver); | 157 Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver); |
| 160 if (j == access_infos.size() - 1) { | 158 if (j == access_infos.size() - 1) { |
| 161 this_control = this_effect = | 159 this_effect = graph()->NewNode(simplified()->CheckIf(), check, |
| 162 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 160 this_effect, fallthrough_control); |
| 163 this_effect, fallthrough_control); | 161 this_control = fallthrough_control; |
| 164 fallthrough_control = nullptr; | 162 fallthrough_control = nullptr; |
| 165 } else { | 163 } else { |
| 166 Node* branch = | 164 Node* branch = |
| 167 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 165 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
| 168 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 166 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
| 169 this_control = graph()->NewNode(common()->IfTrue(), branch); | 167 this_control = graph()->NewNode(common()->IfTrue(), branch); |
| 170 } | 168 } |
| 171 } else { | 169 } else { |
| 172 // Emit a (sequence of) map checks for other {receiver}s. | 170 // Emit a (sequence of) map checks for other {receiver}s. |
| 173 ZoneVector<Node*> this_controls(zone()); | 171 ZoneVector<Node*> this_controls(zone()); |
| 174 ZoneVector<Node*> this_effects(zone()); | 172 ZoneVector<Node*> this_effects(zone()); |
| 175 int num_classes = access_info.receiver_type()->NumClasses(); | 173 int num_classes = access_info.receiver_type()->NumClasses(); |
| 176 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | 174 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
| 177 i.Advance()) { | 175 i.Advance()) { |
| 178 DCHECK_LT(0, num_classes); | 176 DCHECK_LT(0, num_classes); |
| 179 Handle<Map> map = i.Current(); | 177 Handle<Map> map = i.Current(); |
| 180 Node* check = | 178 Node* check = |
| 181 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), | 179 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), |
| 182 receiver_map, jsgraph()->Constant(map)); | 180 receiver_map, jsgraph()->Constant(map)); |
| 183 if (--num_classes == 0 && j == access_infos.size() - 1) { | 181 if (--num_classes == 0 && j == access_infos.size() - 1) { |
| 184 Node* deoptimize = | 182 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect, |
| 185 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 183 fallthrough_control); |
| 186 this_effect, fallthrough_control); | 184 this_controls.push_back(fallthrough_control); |
| 187 this_controls.push_back(deoptimize); | 185 this_effects.push_back(check); |
| 188 this_effects.push_back(deoptimize); | |
| 189 fallthrough_control = nullptr; | 186 fallthrough_control = nullptr; |
| 190 } else { | 187 } else { |
| 191 Node* branch = | 188 Node* branch = |
| 192 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 189 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
| 193 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 190 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
| 194 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 191 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
| 195 this_effects.push_back(this_effect); | 192 this_effects.push_back(this_effect); |
| 196 } | 193 } |
| 197 } | 194 } |
| 198 | 195 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 | 227 |
| 231 // Generate the actual property access. | 228 // Generate the actual property access. |
| 232 if (access_info.IsNotFound()) { | 229 if (access_info.IsNotFound()) { |
| 233 DCHECK_EQ(AccessMode::kLoad, access_mode); | 230 DCHECK_EQ(AccessMode::kLoad, access_mode); |
| 234 this_value = jsgraph()->UndefinedConstant(); | 231 this_value = jsgraph()->UndefinedConstant(); |
| 235 } else if (access_info.IsDataConstant()) { | 232 } else if (access_info.IsDataConstant()) { |
| 236 this_value = jsgraph()->Constant(access_info.constant()); | 233 this_value = jsgraph()->Constant(access_info.constant()); |
| 237 if (access_mode == AccessMode::kStore) { | 234 if (access_mode == AccessMode::kStore) { |
| 238 Node* check = graph()->NewNode( | 235 Node* check = graph()->NewNode( |
| 239 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); | 236 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); |
| 240 this_control = this_effect = | 237 this_effect = graph()->NewNode(simplified()->CheckIf(), check, |
| 241 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 238 this_effect, this_control); |
| 242 this_effect, this_control); | |
| 243 } | 239 } |
| 244 } else { | 240 } else { |
| 245 DCHECK(access_info.IsDataField()); | 241 DCHECK(access_info.IsDataField()); |
| 246 FieldIndex const field_index = access_info.field_index(); | 242 FieldIndex const field_index = access_info.field_index(); |
| 247 Type* const field_type = access_info.field_type(); | 243 Type* const field_type = access_info.field_type(); |
| 248 if (access_mode == AccessMode::kLoad && | 244 if (access_mode == AccessMode::kLoad && |
| 249 access_info.holder().ToHandle(&holder)) { | 245 access_info.holder().ToHandle(&holder)) { |
| 250 this_receiver = jsgraph()->Constant(holder); | 246 this_receiver = jsgraph()->Constant(holder); |
| 251 } | 247 } |
| 252 Node* this_storage = this_receiver; | 248 Node* this_storage = this_receiver; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 graph()->NewNode(simplified()->CheckTaggedPointer(), this_value, | 320 graph()->NewNode(simplified()->CheckTaggedPointer(), this_value, |
| 325 this_effect, this_control); | 321 this_effect, this_control); |
| 326 if (field_type->NumClasses() == 1) { | 322 if (field_type->NumClasses() == 1) { |
| 327 // Emit a map check for the value. | 323 // Emit a map check for the value. |
| 328 Node* this_value_map = this_effect = graph()->NewNode( | 324 Node* this_value_map = this_effect = graph()->NewNode( |
| 329 simplified()->LoadField(AccessBuilder::ForMap()), this_value, | 325 simplified()->LoadField(AccessBuilder::ForMap()), this_value, |
| 330 this_effect, this_control); | 326 this_effect, this_control); |
| 331 Node* check = graph()->NewNode( | 327 Node* check = graph()->NewNode( |
| 332 simplified()->ReferenceEqual(Type::Internal()), this_value_map, | 328 simplified()->ReferenceEqual(Type::Internal()), this_value_map, |
| 333 jsgraph()->Constant(field_type->Classes().Current())); | 329 jsgraph()->Constant(field_type->Classes().Current())); |
| 334 this_control = this_effect = | 330 this_effect = graph()->NewNode(simplified()->CheckIf(), check, |
| 335 graph()->NewNode(common()->DeoptimizeUnless(), check, | 331 this_effect, this_control); |
| 336 frame_state, this_effect, this_control); | |
| 337 } else { | 332 } else { |
| 338 DCHECK_EQ(0, field_type->NumClasses()); | 333 DCHECK_EQ(0, field_type->NumClasses()); |
| 339 } | 334 } |
| 340 } else { | 335 } else { |
| 341 DCHECK(field_type->Is(Type::Tagged())); | 336 DCHECK(field_type->Is(Type::Tagged())); |
| 342 } | 337 } |
| 343 Handle<Map> transition_map; | 338 Handle<Map> transition_map; |
| 344 if (access_info.transition_map().ToHandle(&transition_map)) { | 339 if (access_info.transition_map().ToHandle(&transition_map)) { |
| 345 this_effect = graph()->NewNode( | 340 this_effect = graph()->NewNode( |
| 346 common()->BeginRegion(RegionObservability::kObservable), | 341 common()->BeginRegion(RegionObservability::kObservable), |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 Node* check = | 552 Node* check = |
| 558 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), | 553 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
| 559 receiver_map, jsgraph()->Constant(map)); | 554 receiver_map, jsgraph()->Constant(map)); |
| 560 if (--num_classes == 0 && num_transitions == 0 && | 555 if (--num_classes == 0 && num_transitions == 0 && |
| 561 j == access_infos.size() - 1) { | 556 j == access_infos.size() - 1) { |
| 562 // Last map check on the fallthrough control path, do a conditional | 557 // Last map check on the fallthrough control path, do a conditional |
| 563 // eager deoptimization exit here. | 558 // eager deoptimization exit here. |
| 564 // TODO(turbofan): This is ugly as hell! We should probably introduce | 559 // TODO(turbofan): This is ugly as hell! We should probably introduce |
| 565 // macro-ish operators for property access that encapsulate this whole | 560 // macro-ish operators for property access that encapsulate this whole |
| 566 // mess. | 561 // mess. |
| 567 Node* deoptimize = | 562 check = graph()->NewNode(simplified()->CheckIf(), check, effect, |
| 568 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 563 fallthrough_control); |
| 569 effect, fallthrough_control); | 564 this_controls.push_back(fallthrough_control); |
| 570 this_controls.push_back(deoptimize); | 565 this_effects.push_back(check); |
| 571 this_effects.push_back(deoptimize); | |
| 572 fallthrough_control = nullptr; | 566 fallthrough_control = nullptr; |
| 573 } else { | 567 } else { |
| 574 Node* branch = | 568 Node* branch = |
| 575 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 569 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
| 576 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 570 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
| 577 this_effects.push_back(effect); | 571 this_effects.push_back(effect); |
| 578 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 572 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
| 579 } | 573 } |
| 580 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; | 574 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; |
| 581 } | 575 } |
| 582 | 576 |
| 583 // Generate possible elements kind transitions. | 577 // Generate possible elements kind transitions. |
| 584 for (auto transition : access_info.transitions()) { | 578 for (auto transition : access_info.transitions()) { |
| 585 DCHECK_LT(0u, num_transitions); | 579 DCHECK_LT(0u, num_transitions); |
| 586 Handle<Map> transition_source = transition.first; | 580 Handle<Map> transition_source = transition.first; |
| 587 Handle<Map> transition_target = transition.second; | 581 Handle<Map> transition_target = transition.second; |
| 588 Node* transition_control; | 582 Node* transition_control; |
| 589 Node* transition_effect = effect; | 583 Node* transition_effect = effect; |
| 590 | 584 |
| 591 // Check if {receiver} has the specified {transition_source} map. | 585 // Check if {receiver} has the specified {transition_source} map. |
| 592 Node* check = graph()->NewNode( | 586 Node* check = graph()->NewNode( |
| 593 simplified()->ReferenceEqual(Type::Any()), receiver_map, | 587 simplified()->ReferenceEqual(Type::Any()), receiver_map, |
| 594 jsgraph()->HeapConstant(transition_source)); | 588 jsgraph()->HeapConstant(transition_source)); |
| 595 if (--num_transitions == 0 && j == access_infos.size() - 1) { | 589 if (--num_transitions == 0 && j == access_infos.size() - 1) { |
| 596 transition_control = transition_effect = | 590 transition_effect = |
| 597 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 591 graph()->NewNode(simplified()->CheckIf(), check, |
| 598 transition_effect, fallthrough_control); | 592 transition_effect, fallthrough_control); |
| 593 transition_control = fallthrough_control; |
| 599 fallthrough_control = nullptr; | 594 fallthrough_control = nullptr; |
| 600 } else { | 595 } else { |
| 601 Node* branch = | 596 Node* branch = |
| 602 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 597 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
| 603 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 598 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
| 604 transition_control = graph()->NewNode(common()->IfTrue(), branch); | 599 transition_control = graph()->NewNode(common()->IfTrue(), branch); |
| 605 } | 600 } |
| 606 | 601 |
| 607 // Migrate {receiver} from {transition_source} to {transition_target}. | 602 // Migrate {receiver} from {transition_source} to {transition_target}. |
| 608 if (IsSimpleMapChangeTransition(transition_source->elements_kind(), | 603 if (IsSimpleMapChangeTransition(transition_source->elements_kind(), |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 | 668 |
| 674 // Don't try to store to a copy-on-write backing store. | 669 // Don't try to store to a copy-on-write backing store. |
| 675 if (access_mode == AccessMode::kStore && | 670 if (access_mode == AccessMode::kStore && |
| 676 IsFastSmiOrObjectElementsKind(elements_kind)) { | 671 IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 677 Node* this_elements_map = this_effect = | 672 Node* this_elements_map = this_effect = |
| 678 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 673 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 679 this_elements, this_effect, this_control); | 674 this_elements, this_effect, this_control); |
| 680 Node* check = graph()->NewNode( | 675 Node* check = graph()->NewNode( |
| 681 simplified()->ReferenceEqual(Type::Any()), this_elements_map, | 676 simplified()->ReferenceEqual(Type::Any()), this_elements_map, |
| 682 jsgraph()->HeapConstant(factory()->fixed_array_map())); | 677 jsgraph()->HeapConstant(factory()->fixed_array_map())); |
| 683 this_control = this_effect = | 678 this_effect = graph()->NewNode(simplified()->CheckIf(), check, |
| 684 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 679 this_effect, this_control); |
| 685 this_effect, this_control); | |
| 686 } | 680 } |
| 687 | 681 |
| 688 // Load the length of the {receiver}. | 682 // Load the length of the {receiver}. |
| 689 Node* this_length = this_effect = | 683 Node* this_length = this_effect = |
| 690 receiver_is_jsarray | 684 receiver_is_jsarray |
| 691 ? graph()->NewNode( | 685 ? graph()->NewNode( |
| 692 simplified()->LoadField( | 686 simplified()->LoadField( |
| 693 AccessBuilder::ForJSArrayLength(elements_kind)), | 687 AccessBuilder::ForJSArrayLength(elements_kind)), |
| 694 this_receiver, this_effect, this_control) | 688 this_receiver, this_effect, this_control) |
| 695 : graph()->NewNode( | 689 : graph()->NewNode( |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1074 } | 1068 } |
| 1075 | 1069 |
| 1076 | 1070 |
| 1077 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1071 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
| 1078 return jsgraph()->simplified(); | 1072 return jsgraph()->simplified(); |
| 1079 } | 1073 } |
| 1080 | 1074 |
| 1081 } // namespace compiler | 1075 } // namespace compiler |
| 1082 } // namespace internal | 1076 } // namespace internal |
| 1083 } // namespace v8 | 1077 } // namespace v8 |
| OLD | NEW |