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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 } | 136 } |
137 | 137 |
138 // Ensure that {index} matches the specified {name} (if {index} is given). | 138 // Ensure that {index} matches the specified {name} (if {index} is given). |
139 if (index != nullptr) { | 139 if (index != nullptr) { |
140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), | 140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
141 index, jsgraph()->HeapConstant(name)); | 141 index, jsgraph()->HeapConstant(name)); |
142 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 142 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
143 } | 143 } |
144 | 144 |
145 // Check for the monomorphic cases. | 145 // Check for the monomorphic cases. |
146 if (access_infos.size() == 1 && | 146 if (access_infos.size() == 1) { |
147 HasOnlyStringMaps(access_infos[0].receiver_maps())) { | 147 PropertyAccessInfo access_info = access_infos.front(); |
148 // Monormorphic string access (ignoring the fact that there are multiple | 148 if (HasOnlyStringMaps(access_info.receiver_maps())) { |
149 // String maps). | 149 // Monormorphic string access (ignoring the fact that there are multiple |
150 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver, | 150 // String maps). |
151 effect, control); | 151 receiver = effect = graph()->NewNode(simplified()->CheckString(), |
152 receiver, effect, control); | |
153 } else if (HasOnlyNumberMaps(access_info.receiver_maps())) { | |
154 // Monomorphic number access (we also deal with Smis here). | |
155 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), | |
156 receiver, effect, control); | |
157 } else { | |
158 // Monomorphic property access. | |
159 effect = BuildCheckTaggedPointer(receiver, effect, control); | |
160 effect = BuildCheckMaps(receiver, effect, control, | |
161 access_info.receiver_maps()); | |
162 } | |
152 | 163 |
153 // Generate the actual property access. | 164 // Generate the actual property access. |
154 ValueEffectControl continuation = | 165 ValueEffectControl continuation = |
155 BuildPropertyAccess(receiver, value, effect, control, name, | 166 BuildPropertyAccess(receiver, value, effect, control, name, |
156 native_context, access_infos[0], access_mode); | 167 native_context, access_info, access_mode); |
157 value = continuation.value(); | 168 value = continuation.value(); |
158 effect = continuation.effect(); | 169 effect = continuation.effect(); |
159 control = continuation.control(); | 170 control = continuation.control(); |
160 } else if (access_infos.size() == 1 && | |
161 HasOnlyNumberMaps(access_infos[0].receiver_maps())) { | |
162 // Monomorphic number access (we also deal with Smis here). | |
163 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), receiver, | |
164 effect, control); | |
165 | |
166 // Generate the actual property access. | |
167 ValueEffectControl continuation = | |
168 BuildPropertyAccess(receiver, value, effect, control, name, | |
169 native_context, access_infos[0], access_mode); | |
170 value = continuation.value(); | |
171 effect = continuation.effect(); | |
172 control = continuation.control(); | |
173 } else { | 171 } else { |
174 // The final states for every polymorphic branch. We join them with | 172 // The final states for every polymorphic branch. We join them with |
175 // Merge+Phi+EffectPhi at the bottom. | 173 // Merge+Phi+EffectPhi at the bottom. |
176 ZoneVector<Node*> values(zone()); | 174 ZoneVector<Node*> values(zone()); |
177 ZoneVector<Node*> effects(zone()); | 175 ZoneVector<Node*> effects(zone()); |
178 ZoneVector<Node*> controls(zone()); | 176 ZoneVector<Node*> controls(zone()); |
179 | 177 |
180 // Check if {receiver} may be a number. | 178 // Check if {receiver} may be a number. |
181 bool receiverissmi_possible = false; | 179 bool receiverissmi_possible = false; |
182 for (PropertyAccessInfo const& access_info : access_infos) { | 180 for (PropertyAccessInfo const& access_info : access_infos) { |
183 if (HasNumberMaps(access_info.receiver_maps())) { | 181 if (HasNumberMaps(access_info.receiver_maps())) { |
184 receiverissmi_possible = true; | 182 receiverissmi_possible = true; |
185 break; | 183 break; |
186 } | 184 } |
187 } | 185 } |
188 | 186 |
189 // Ensure that {receiver} is a heap object. | 187 // Ensure that {receiver} is a heap object. |
190 Node* receiverissmi_control = nullptr; | 188 Node* receiverissmi_control = nullptr; |
191 Node* receiverissmi_effect = effect; | 189 Node* receiverissmi_effect = effect; |
192 if (receiverissmi_possible) { | 190 if (receiverissmi_possible) { |
193 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 191 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
194 Node* branch = graph()->NewNode(common()->Branch(), check, control); | 192 Node* branch = graph()->NewNode(common()->Branch(), check, control); |
195 control = graph()->NewNode(common()->IfFalse(), branch); | 193 control = graph()->NewNode(common()->IfFalse(), branch); |
196 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); | 194 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
197 receiverissmi_effect = effect; | 195 receiverissmi_effect = effect; |
198 } else { | 196 } else { |
199 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), | 197 effect = BuildCheckTaggedPointer(receiver, effect, control); |
200 receiver, effect, control); | |
201 } | 198 } |
202 | 199 |
203 // Load the {receiver} map. The resulting effect is the dominating effect | 200 // Load the {receiver} map. The resulting effect is the dominating effect |
204 // for all (polymorphic) branches. | 201 // for all (polymorphic) branches. |
205 Node* receiver_map = effect = | 202 Node* receiver_map = effect = |
206 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 203 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
207 receiver, effect, control); | 204 receiver, effect, control); |
208 | 205 |
209 // Generate code for the various different property access patterns. | 206 // Generate code for the various different property access patterns. |
210 Node* fallthrough_control = control; | 207 Node* fallthrough_control = control; |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
427 &access_infos)) { | 424 &access_infos)) { |
428 return NoChange(); | 425 return NoChange(); |
429 } | 426 } |
430 | 427 |
431 // Nothing to do if we have no non-deprecated maps. | 428 // Nothing to do if we have no non-deprecated maps. |
432 if (access_infos.empty()) { | 429 if (access_infos.empty()) { |
433 return ReduceSoftDeoptimize( | 430 return ReduceSoftDeoptimize( |
434 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); | 431 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); |
435 } | 432 } |
436 | 433 |
437 // The final states for every polymorphic branch. We join them with | 434 // Ensure that {receiver} is a heap object. |
438 // Merge+Phi+EffectPhi at the bottom. | 435 effect = BuildCheckTaggedPointer(receiver, effect, control); |
439 ZoneVector<Node*> values(zone()); | |
440 ZoneVector<Node*> effects(zone()); | |
441 ZoneVector<Node*> controls(zone()); | |
442 | 436 |
443 // Ensure that {receiver} is a heap object. | 437 // Check for the monomorphic case. |
444 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), | 438 if (access_infos.size() == 1) { |
445 receiver, effect, control); | 439 ElementAccessInfo access_info = access_infos.front(); |
446 | |
447 // Generate code for the various different element access patterns. | |
448 Node* fallthrough_control = control; | |
449 for (size_t j = 0; j < access_infos.size(); ++j) { | |
450 ElementAccessInfo const& access_info = access_infos[j]; | |
451 Node* this_receiver = receiver; | |
452 Node* this_value = value; | |
453 Node* this_index = index; | |
454 Node* this_effect = effect; | |
455 Node* this_control = fallthrough_control; | |
456 | 440 |
457 // Perform possible elements kind transitions. | 441 // Perform possible elements kind transitions. |
458 for (auto transition : access_info.transitions()) { | 442 for (auto transition : access_info.transitions()) { |
459 Handle<Map> const transition_source = transition.first; | 443 Handle<Map> const transition_source = transition.first; |
460 Handle<Map> const transition_target = transition.second; | 444 Handle<Map> const transition_target = transition.second; |
461 this_effect = graph()->NewNode( | 445 effect = graph()->NewNode( |
462 simplified()->TransitionElementsKind( | 446 simplified()->TransitionElementsKind( |
463 IsSimpleMapChangeTransition(transition_source->elements_kind(), | 447 IsSimpleMapChangeTransition(transition_source->elements_kind(), |
464 transition_target->elements_kind()) | 448 transition_target->elements_kind()) |
465 ? ElementsTransition::kFastTransition | 449 ? ElementsTransition::kFastTransition |
466 : ElementsTransition::kSlowTransition), | 450 : ElementsTransition::kSlowTransition), |
467 receiver, jsgraph()->HeapConstant(transition_source), | 451 receiver, jsgraph()->HeapConstant(transition_source), |
468 jsgraph()->HeapConstant(transition_target), this_effect, | 452 jsgraph()->HeapConstant(transition_target), effect, control); |
469 this_control); | |
470 } | 453 } |
471 | 454 |
472 // Load the {receiver} map. | 455 // TODO(turbofan): The effect/control linearization will not find a |
473 Node* receiver_map = this_effect = | 456 // FrameState after the StoreField or Call that is generated for the |
474 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 457 // elements kind transition above. This is because those operators |
475 receiver, this_effect, this_control); | 458 // don't have the kNoWrite flag on it, even though they are not |
459 // observable by JavaScript. | |
460 effect = | |
461 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); | |
476 | 462 |
477 // Perform map check on {receiver}. | 463 // Perform map check on the {receiver}. |
478 MapList const& receiver_maps = access_info.receiver_maps(); | 464 effect = |
479 { | 465 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); |
480 ZoneVector<Node*> this_controls(zone()); | 466 |
481 ZoneVector<Node*> this_effects(zone()); | 467 // Access the actual element. |
482 size_t num_classes = receiver_maps.size(); | 468 ValueEffectControl continuation = |
483 for (Handle<Map> map : receiver_maps) { | 469 BuildElementAccess(receiver, index, value, effect, control, |
484 DCHECK_LT(0u, num_classes); | 470 native_context, access_info, access_mode); |
485 Node* check = | 471 value = continuation.value(); |
486 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), | 472 effect = continuation.effect(); |
487 receiver_map, jsgraph()->Constant(map)); | 473 control = continuation.control(); |
488 if (--num_classes == 0 && j == access_infos.size() - 1) { | 474 } else { |
489 // Last map check on the fallthrough control path, do a conditional | 475 // The final states for every polymorphic branch. We join them with |
490 // eager deoptimization exit here. | 476 // Merge+Phi+EffectPhi at the bottom. |
491 // TODO(turbofan): This is ugly as hell! We should probably introduce | 477 ZoneVector<Node*> values(zone()); |
492 // macro-ish operators for property access that encapsulate this whole | 478 ZoneVector<Node*> effects(zone()); |
493 // mess. | 479 ZoneVector<Node*> controls(zone()); |
494 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect, | 480 |
495 this_control); | 481 // Generate code for the various different element access patterns. |
496 this_controls.push_back(this_control); | 482 Node* fallthrough_control = control; |
497 this_effects.push_back(check); | 483 for (size_t j = 0; j < access_infos.size(); ++j) { |
498 fallthrough_control = nullptr; | 484 ElementAccessInfo const& access_info = access_infos[j]; |
485 Node* this_receiver = receiver; | |
486 Node* this_value = value; | |
487 Node* this_index = index; | |
488 Node* this_effect = effect; | |
489 Node* this_control = fallthrough_control; | |
490 | |
491 // Perform possible elements kind transitions. | |
492 for (auto transition : access_info.transitions()) { | |
493 Handle<Map> const transition_source = transition.first; | |
494 Handle<Map> const transition_target = transition.second; | |
495 this_effect = graph()->NewNode( | |
496 simplified()->TransitionElementsKind( | |
497 IsSimpleMapChangeTransition(transition_source->elements_kind(), | |
498 transition_target->elements_kind()) | |
499 ? ElementsTransition::kFastTransition | |
500 : ElementsTransition::kSlowTransition), | |
501 receiver, jsgraph()->HeapConstant(transition_source), | |
502 jsgraph()->HeapConstant(transition_target), this_effect, | |
503 this_control); | |
504 } | |
505 | |
506 // Load the {receiver} map. | |
507 Node* receiver_map = this_effect = | |
508 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | |
509 receiver, this_effect, this_control); | |
510 | |
511 // Perform map check(s) on {receiver}. | |
512 MapList const& receiver_maps = access_info.receiver_maps(); | |
513 { | |
514 ZoneVector<Node*> this_controls(zone()); | |
515 ZoneVector<Node*> this_effects(zone()); | |
516 size_t num_classes = receiver_maps.size(); | |
517 for (Handle<Map> map : receiver_maps) { | |
518 DCHECK_LT(0u, num_classes); | |
519 Node* check = | |
520 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), | |
521 receiver_map, jsgraph()->Constant(map)); | |
522 if (--num_classes == 0 && j == access_infos.size() - 1) { | |
523 // Last map check on the fallthrough control path, do a conditional | |
524 // eager deoptimization exit here. | |
525 // TODO(turbofan): This is ugly as hell! We should probably | |
526 // introduce macro-ish operators for property access that | |
527 // encapsulate this whole mess. | |
528 check = graph()->NewNode(simplified()->CheckIf(), check, | |
529 this_effect, this_control); | |
530 this_controls.push_back(this_control); | |
531 this_effects.push_back(check); | |
532 fallthrough_control = nullptr; | |
533 } else { | |
534 Node* branch = graph()->NewNode(common()->Branch(), check, | |
535 fallthrough_control); | |
536 this_controls.push_back( | |
537 graph()->NewNode(common()->IfTrue(), branch)); | |
538 this_effects.push_back(effect); | |
539 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | |
540 } | |
541 } | |
542 | |
543 // Create single chokepoint for the control. | |
epertoso
2016/07/29 09:34:08
nit: do you mean checkpoint?
Benedikt Meurer
2016/07/29 09:37:48
Yes.
| |
544 int const this_control_count = static_cast<int>(this_controls.size()); | |
545 if (this_control_count == 1) { | |
546 this_control = this_controls.front(); | |
547 this_effect = this_effects.front(); | |
499 } else { | 548 } else { |
500 Node* branch = | 549 this_control = |
501 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 550 graph()->NewNode(common()->Merge(this_control_count), |
502 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 551 this_control_count, &this_controls.front()); |
503 this_effects.push_back(effect); | 552 this_effects.push_back(this_control); |
504 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 553 this_effect = |
554 graph()->NewNode(common()->EffectPhi(this_control_count), | |
555 this_control_count + 1, &this_effects.front()); | |
556 | |
557 // TODO(turbofan): The effect/control linearization will not find a | |
558 // FrameState after the StoreField or Call that is generated for the | |
559 // elements kind transition above. This is because those operators | |
560 // don't have the kNoWrite flag on it, even though they are not | |
561 // observable by JavaScript. | |
562 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | |
563 this_effect, this_control); | |
505 } | 564 } |
506 } | 565 } |
507 | 566 |
508 // Create single chokepoint for the control. | 567 // Certain stores need a prototype chain check because shape changes |
509 int const this_control_count = static_cast<int>(this_controls.size()); | 568 // could allow callbacks on elements in the prototype chain that are |
510 if (this_control_count == 1) { | 569 // not compatible with (monomorphic) keyed stores. |
511 this_control = this_controls.front(); | 570 Handle<JSObject> holder; |
512 this_effect = this_effects.front(); | 571 if (access_info.holder().ToHandle(&holder)) { |
513 } else { | 572 AssumePrototypesStable(receiver_maps, native_context, holder); |
514 this_control = | 573 } |
515 graph()->NewNode(common()->Merge(this_control_count), | |
516 this_control_count, &this_controls.front()); | |
517 this_effects.push_back(this_control); | |
518 this_effect = | |
519 graph()->NewNode(common()->EffectPhi(this_control_count), | |
520 this_control_count + 1, &this_effects.front()); | |
521 | 574 |
522 // TODO(turbofan): The effect/control linearization will not find a | 575 // Access the actual element. |
523 // FrameState after the StoreField or Call that is generated for the | 576 ValueEffectControl continuation = BuildElementAccess( |
524 // elements kind transition above. This is because those operators | 577 this_receiver, this_index, this_value, this_effect, this_control, |
525 // don't have the kNoWrite flag on it, even though they are not | 578 native_context, access_info, access_mode); |
526 // observable by JavaScript. | 579 values.push_back(continuation.value()); |
527 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | 580 effects.push_back(continuation.effect()); |
528 this_effect, this_control); | 581 controls.push_back(continuation.control()); |
529 } | |
530 } | 582 } |
531 | 583 |
532 // Certain stores need a prototype chain check because shape changes | 584 DCHECK_NULL(fallthrough_control); |
533 // could allow callbacks on elements in the prototype chain that are | 585 |
534 // not compatible with (monomorphic) keyed stores. | 586 // Generate the final merge point for all (polymorphic) branches. |
535 Handle<JSObject> holder; | 587 int const control_count = static_cast<int>(controls.size()); |
536 if (access_info.holder().ToHandle(&holder)) { | 588 if (control_count == 0) { |
537 AssumePrototypesStable(receiver_maps, native_context, holder); | 589 value = effect = control = jsgraph()->Dead(); |
590 } else if (control_count == 1) { | |
591 value = values.front(); | |
592 effect = effects.front(); | |
593 control = controls.front(); | |
594 } else { | |
595 control = graph()->NewNode(common()->Merge(control_count), control_count, | |
596 &controls.front()); | |
597 values.push_back(control); | |
598 value = graph()->NewNode( | |
599 common()->Phi(MachineRepresentation::kTagged, control_count), | |
600 control_count + 1, &values.front()); | |
601 effects.push_back(control); | |
602 effect = graph()->NewNode(common()->EffectPhi(control_count), | |
603 control_count + 1, &effects.front()); | |
538 } | 604 } |
539 | |
540 // Access the actual element. | |
541 ValueEffectControl continuation = BuildElementAccess( | |
542 this_receiver, this_index, this_value, this_effect, this_control, | |
543 native_context, access_info, access_mode); | |
544 values.push_back(continuation.value()); | |
545 effects.push_back(continuation.effect()); | |
546 controls.push_back(continuation.control()); | |
547 } | 605 } |
548 | 606 |
549 DCHECK_NULL(fallthrough_control); | |
550 | |
551 // Generate the final merge point for all (polymorphic) branches. | |
552 int const control_count = static_cast<int>(controls.size()); | |
553 if (control_count == 0) { | |
554 value = effect = control = jsgraph()->Dead(); | |
555 } else if (control_count == 1) { | |
556 value = values.front(); | |
557 effect = effects.front(); | |
558 control = controls.front(); | |
559 } else { | |
560 control = graph()->NewNode(common()->Merge(control_count), control_count, | |
561 &controls.front()); | |
562 values.push_back(control); | |
563 value = graph()->NewNode( | |
564 common()->Phi(MachineRepresentation::kTagged, control_count), | |
565 control_count + 1, &values.front()); | |
566 effects.push_back(control); | |
567 effect = graph()->NewNode(common()->EffectPhi(control_count), | |
568 control_count + 1, &effects.front()); | |
569 } | |
570 ReplaceWithValue(node, value, effect, control); | 607 ReplaceWithValue(node, value, effect, control); |
571 return Replace(value); | 608 return Replace(value); |
572 } | 609 } |
573 | 610 |
574 template <typename KeyedICNexus> | 611 template <typename KeyedICNexus> |
575 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( | 612 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( |
576 Node* node, Node* index, Node* value, KeyedICNexus const& nexus, | 613 Node* node, Node* index, Node* value, KeyedICNexus const& nexus, |
577 AccessMode access_mode, LanguageMode language_mode, | 614 AccessMode access_mode, LanguageMode language_mode, |
578 KeyedAccessStoreMode store_mode) { | 615 KeyedAccessStoreMode store_mode) { |
579 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || | 616 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
785 field_access.machine_type = MachineType::Float64(); | 822 field_access.machine_type = MachineType::Float64(); |
786 } | 823 } |
787 } else { | 824 } else { |
788 // Unboxed double field, we store directly to the field. | 825 // Unboxed double field, we store directly to the field. |
789 field_access.machine_type = MachineType::Float64(); | 826 field_access.machine_type = MachineType::Float64(); |
790 } | 827 } |
791 } else if (field_type->Is(Type::TaggedSigned())) { | 828 } else if (field_type->Is(Type::TaggedSigned())) { |
792 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), | 829 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), |
793 value, effect, control); | 830 value, effect, control); |
794 } else if (field_type->Is(Type::TaggedPointer())) { | 831 } else if (field_type->Is(Type::TaggedPointer())) { |
832 // Ensure that {value} is a HeapObject. | |
795 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), | 833 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), |
796 value, effect, control); | 834 value, effect, control); |
797 if (field_type->NumClasses() == 1) { | 835 if (field_type->NumClasses() == 1) { |
798 // Emit a map check for the value. | 836 // Emit a map check for the value. |
799 Node* value_map = effect = | 837 Node* field_map = |
800 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 838 jsgraph()->Constant(field_type->Classes().Current()); |
801 value, effect, control); | 839 effect = graph()->NewNode(simplified()->CheckMaps(1), value, |
802 Node* check = graph()->NewNode( | 840 field_map, effect, control); |
803 simplified()->ReferenceEqual(Type::Internal()), value_map, | |
804 jsgraph()->Constant(field_type->Classes().Current())); | |
805 effect = | |
806 graph()->NewNode(simplified()->CheckIf(), check, effect, control); | |
807 } else { | 841 } else { |
808 DCHECK_EQ(0, field_type->NumClasses()); | 842 DCHECK_EQ(0, field_type->NumClasses()); |
809 } | 843 } |
810 } else { | 844 } else { |
811 DCHECK(field_type->Is(Type::Tagged())); | 845 DCHECK(field_type->Is(Type::Tagged())); |
812 } | 846 } |
813 Handle<Map> transition_map; | 847 Handle<Map> transition_map; |
814 if (access_info.transition_map().ToHandle(&transition_map)) { | 848 if (access_info.transition_map().ToHandle(&transition_map)) { |
815 effect = graph()->NewNode( | 849 effect = graph()->NewNode( |
816 common()->BeginRegion(RegionObservability::kObservable), effect); | 850 common()->BeginRegion(RegionObservability::kObservable), effect); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
960 // Make sure we do not store signalling NaNs into double arrays. | 994 // Make sure we do not store signalling NaNs into double arrays. |
961 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); | 995 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); |
962 } | 996 } |
963 effect = graph()->NewNode(simplified()->StoreElement(element_access), | 997 effect = graph()->NewNode(simplified()->StoreElement(element_access), |
964 elements, index, value, effect, control); | 998 elements, index, value, effect, control); |
965 } | 999 } |
966 | 1000 |
967 return ValueEffectControl(value, effect, control); | 1001 return ValueEffectControl(value, effect, control); |
968 } | 1002 } |
969 | 1003 |
1004 Node* JSNativeContextSpecialization::BuildCheckMaps( | |
1005 Node* receiver, Node* effect, Node* control, | |
1006 std::vector<Handle<Map>> const& maps) { | |
1007 HeapObjectMatcher m(receiver); | |
1008 if (m.HasValue()) { | |
1009 Handle<Map> receiver_map(m.Value()->map(), isolate()); | |
1010 if (receiver_map->is_stable()) { | |
1011 for (Handle<Map> map : maps) { | |
1012 if (map.is_identical_to(receiver_map)) { | |
1013 dependencies()->AssumeMapStable(receiver_map); | |
1014 return effect; | |
1015 } | |
1016 } | |
1017 } | |
1018 } | |
1019 int const map_input_count = static_cast<int>(maps.size()); | |
1020 int const input_count = 1 + map_input_count + 1 + 1; | |
1021 Node** inputs = zone()->NewArray<Node*>(input_count); | |
1022 inputs[0] = receiver; | |
1023 for (int i = 0; i < map_input_count; ++i) { | |
1024 inputs[1 + i] = jsgraph()->HeapConstant(maps[i]); | |
1025 } | |
1026 inputs[input_count - 2] = effect; | |
1027 inputs[input_count - 1] = control; | |
1028 return graph()->NewNode(simplified()->CheckMaps(map_input_count), input_count, | |
1029 inputs); | |
1030 } | |
1031 | |
1032 Node* JSNativeContextSpecialization::BuildCheckTaggedPointer(Node* receiver, | |
1033 Node* effect, | |
1034 Node* control) { | |
1035 switch (receiver->opcode()) { | |
1036 case IrOpcode::kHeapConstant: | |
1037 case IrOpcode::kJSCreate: | |
1038 case IrOpcode::kJSCreateArguments: | |
1039 case IrOpcode::kJSCreateArray: | |
1040 case IrOpcode::kJSCreateClosure: | |
1041 case IrOpcode::kJSCreateIterResultObject: | |
1042 case IrOpcode::kJSCreateLiteralArray: | |
1043 case IrOpcode::kJSCreateLiteralObject: | |
1044 case IrOpcode::kJSCreateLiteralRegExp: | |
1045 case IrOpcode::kJSConvertReceiver: | |
1046 case IrOpcode::kJSToName: | |
1047 case IrOpcode::kJSToString: | |
1048 case IrOpcode::kJSToObject: | |
1049 case IrOpcode::kJSTypeOf: { | |
1050 return effect; | |
1051 } | |
1052 default: { | |
1053 return graph()->NewNode(simplified()->CheckTaggedPointer(), receiver, | |
1054 effect, control); | |
1055 } | |
1056 } | |
1057 } | |
1058 | |
970 void JSNativeContextSpecialization::AssumePrototypesStable( | 1059 void JSNativeContextSpecialization::AssumePrototypesStable( |
971 std::vector<Handle<Map>> const& receiver_maps, | 1060 std::vector<Handle<Map>> const& receiver_maps, |
972 Handle<Context> native_context, Handle<JSObject> holder) { | 1061 Handle<Context> native_context, Handle<JSObject> holder) { |
973 // Determine actual holder and perform prototype chain checks. | 1062 // Determine actual holder and perform prototype chain checks. |
974 for (auto map : receiver_maps) { | 1063 for (auto map : receiver_maps) { |
975 // Perform the implicit ToObject for primitives here. | 1064 // Perform the implicit ToObject for primitives here. |
976 // Implemented according to ES6 section 7.3.2 GetV (V, P). | 1065 // Implemented according to ES6 section 7.3.2 GetV (V, P). |
977 Handle<JSFunction> constructor; | 1066 Handle<JSFunction> constructor; |
978 if (Map::GetConstructorFunction(map, native_context) | 1067 if (Map::GetConstructorFunction(map, native_context) |
979 .ToHandle(&constructor)) { | 1068 .ToHandle(&constructor)) { |
(...skipping 24 matching lines...) Expand all Loading... | |
1004 } | 1093 } |
1005 } | 1094 } |
1006 } | 1095 } |
1007 return true; | 1096 return true; |
1008 } | 1097 } |
1009 return false; | 1098 return false; |
1010 } | 1099 } |
1011 | 1100 |
1012 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver, | 1101 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver, |
1013 Node* effect) { | 1102 Node* effect) { |
1014 NodeMatcher m(receiver); | 1103 HeapObjectMatcher m(receiver); |
1015 if (m.IsJSCreate()) { | 1104 if (m.HasValue()) { |
1105 Handle<Map> receiver_map(m.Value()->map(), isolate()); | |
1106 if (receiver_map->is_stable()) return receiver_map; | |
1107 } else if (m.IsJSCreate()) { | |
1016 HeapObjectMatcher mtarget(m.InputAt(0)); | 1108 HeapObjectMatcher mtarget(m.InputAt(0)); |
1017 HeapObjectMatcher mnewtarget(m.InputAt(1)); | 1109 HeapObjectMatcher mnewtarget(m.InputAt(1)); |
1018 if (mtarget.HasValue() && mnewtarget.HasValue()) { | 1110 if (mtarget.HasValue() && mnewtarget.HasValue()) { |
1019 Handle<JSFunction> constructor = | 1111 Handle<JSFunction> constructor = |
1020 Handle<JSFunction>::cast(mtarget.Value()); | 1112 Handle<JSFunction>::cast(mtarget.Value()); |
1021 if (constructor->has_initial_map()) { | 1113 if (constructor->has_initial_map()) { |
1022 Handle<Map> initial_map(constructor->initial_map(), isolate()); | 1114 Handle<Map> initial_map(constructor->initial_map(), isolate()); |
1023 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) { | 1115 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) { |
1024 // Walk up the {effect} chain to see if the {receiver} is the | 1116 // Walk up the {effect} chain to see if the {receiver} is the |
1025 // dominating effect and there's no other observable write in | 1117 // dominating effect and there's no other observable write in |
1026 // between. | 1118 // between. |
1027 while (true) { | 1119 while (true) { |
1028 if (receiver == effect) return initial_map; | 1120 if (receiver == effect) return initial_map; |
1029 if (!effect->op()->HasProperty(Operator::kNoWrite) || | 1121 if (!effect->op()->HasProperty(Operator::kNoWrite) || |
1030 effect->op()->EffectInputCount() != 1) { | 1122 effect->op()->EffectInputCount() != 1) { |
1031 break; | 1123 break; |
1032 } | 1124 } |
1033 effect = NodeProperties::GetEffectInput(effect); | 1125 effect = NodeProperties::GetEffectInput(effect); |
1034 } | 1126 } |
1035 } | 1127 } |
1036 } | 1128 } |
1037 } | 1129 } |
1038 } | 1130 } |
1131 // TODO(turbofan): Go hunting for CheckMaps(receiver) in the effect chain? | |
1039 return MaybeHandle<Map>(); | 1132 return MaybeHandle<Map>(); |
1040 } | 1133 } |
1041 | 1134 |
1042 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap( | 1135 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap( |
1043 Node* receiver) { | 1136 Node* receiver) { |
1044 HeapObjectMatcher m(receiver); | 1137 HeapObjectMatcher m(receiver); |
1045 if (m.HasValue()) { | 1138 if (m.HasValue()) { |
1046 return handle(m.Value()->map()->FindRootMap(), isolate()); | 1139 return handle(m.Value()->map()->FindRootMap(), isolate()); |
1047 } else if (m.IsJSCreate()) { | 1140 } else if (m.IsJSCreate()) { |
1048 HeapObjectMatcher mtarget(m.InputAt(0)); | 1141 HeapObjectMatcher mtarget(m.InputAt(0)); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1100 } | 1193 } |
1101 | 1194 |
1102 | 1195 |
1103 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1196 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1104 return jsgraph()->simplified(); | 1197 return jsgraph()->simplified(); |
1105 } | 1198 } |
1106 | 1199 |
1107 } // namespace compiler | 1200 } // namespace compiler |
1108 } // namespace internal | 1201 } // namespace internal |
1109 } // namespace v8 | 1202 } // namespace v8 |
OLD | NEW |