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 |