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 482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 AccessMode::kStore, p.language_mode()); | 493 AccessMode::kStore, p.language_mode()); |
494 } | 494 } |
495 | 495 |
496 | 496 |
497 Reduction JSNativeContextSpecialization::ReduceElementAccess( | 497 Reduction JSNativeContextSpecialization::ReduceElementAccess( |
498 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, | 498 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, |
499 AccessMode access_mode, LanguageMode language_mode) { | 499 AccessMode access_mode, LanguageMode language_mode) { |
500 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || | 500 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
501 node->opcode() == IrOpcode::kJSStoreProperty); | 501 node->opcode() == IrOpcode::kJSStoreProperty); |
502 Node* receiver = NodeProperties::GetValueInput(node, 0); | 502 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 503 Node* context = NodeProperties::GetContextInput(node); |
503 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 504 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
504 Node* effect = NodeProperties::GetEffectInput(node); | 505 Node* effect = NodeProperties::GetEffectInput(node); |
505 Node* control = NodeProperties::GetControlInput(node); | 506 Node* control = NodeProperties::GetControlInput(node); |
506 | 507 |
507 // Not much we can do if deoptimization support is disabled. | 508 // Not much we can do if deoptimization support is disabled. |
508 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 509 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
509 | 510 |
510 // Compute element access infos for the receiver maps. | 511 // Compute element access infos for the receiver maps. |
511 ZoneVector<ElementAccessInfo> access_infos(zone()); | 512 ZoneVector<ElementAccessInfo> access_infos(zone()); |
512 if (!access_info_factory().ComputeElementAccessInfos( | 513 if (!access_info_factory().ComputeElementAccessInfos( |
(...skipping 27 matching lines...) Expand all Loading... |
540 Node* receiver_map = effect = | 541 Node* receiver_map = effect = |
541 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 542 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
542 receiver, effect, control); | 543 receiver, effect, control); |
543 | 544 |
544 // Generate code for the various different element access patterns. | 545 // Generate code for the various different element access patterns. |
545 Node* fallthrough_control = control; | 546 Node* fallthrough_control = control; |
546 for (ElementAccessInfo const& access_info : access_infos) { | 547 for (ElementAccessInfo const& access_info : access_infos) { |
547 Node* this_receiver = receiver; | 548 Node* this_receiver = receiver; |
548 Node* this_value = value; | 549 Node* this_value = value; |
549 Node* this_index = index; | 550 Node* this_index = index; |
550 Node* this_effect = effect; | 551 Node* this_effect; |
551 Node* this_control; | 552 Node* this_control; |
552 | 553 |
553 // Perform map check on {receiver}. | 554 // Perform map check on {receiver}. |
554 Type* receiver_type = access_info.receiver_type(); | 555 Type* receiver_type = access_info.receiver_type(); |
555 bool receiver_is_jsarray = true; | 556 bool receiver_is_jsarray = true; |
556 { | 557 { |
557 ZoneVector<Node*> this_controls(zone()); | 558 ZoneVector<Node*> this_controls(zone()); |
| 559 ZoneVector<Node*> this_effects(zone()); |
558 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | 560 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
559 i.Advance()) { | 561 i.Advance()) { |
560 Handle<Map> map = i.Current(); | 562 Handle<Map> map = i.Current(); |
561 Node* check = | 563 Node* check = |
562 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), | 564 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
563 receiver_map, jsgraph()->Constant(map)); | 565 receiver_map, jsgraph()->Constant(map)); |
564 Node* branch = | 566 Node* branch = |
565 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 567 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
566 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 568 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
| 569 this_effects.push_back(effect); |
567 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 570 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
568 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; | 571 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; |
569 } | 572 } |
| 573 |
| 574 // Generate possible elements kind transitions. |
| 575 for (auto transition : access_info.transitions()) { |
| 576 Handle<Map> transition_source = transition.first; |
| 577 Handle<Map> transition_target = transition.second; |
| 578 |
| 579 // Check if {receiver} has the specified {transition_source} map. |
| 580 Node* check = graph()->NewNode( |
| 581 simplified()->ReferenceEqual(Type::Any()), receiver_map, |
| 582 jsgraph()->HeapConstant(transition_source)); |
| 583 Node* branch = |
| 584 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
| 585 |
| 586 // Migrate {receiver} from {transition_source} to {transition_target}. |
| 587 Node* transition_control = graph()->NewNode(common()->IfTrue(), branch); |
| 588 Node* transition_effect = effect; |
| 589 if (IsSimpleMapChangeTransition(transition_source->elements_kind(), |
| 590 transition_target->elements_kind())) { |
| 591 // In-place migration, just store the {transition_target} map. |
| 592 transition_effect = graph()->NewNode( |
| 593 simplified()->StoreField(AccessBuilder::ForMap()), receiver, |
| 594 jsgraph()->HeapConstant(transition_target), transition_effect, |
| 595 transition_control); |
| 596 } else { |
| 597 // Instance migration, let the stub deal with the {receiver}. |
| 598 TransitionElementsKindStub stub(isolate(), |
| 599 transition_source->elements_kind(), |
| 600 transition_target->elements_kind(), |
| 601 transition_source->IsJSArrayMap()); |
| 602 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor( |
| 603 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0, |
| 604 CallDescriptor::kNeedsFrameState, node->op()->properties()); |
| 605 transition_effect = graph()->NewNode( |
| 606 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()), |
| 607 receiver, jsgraph()->HeapConstant(transition_target), context, |
| 608 frame_state, transition_effect, transition_control); |
| 609 } |
| 610 this_controls.push_back(transition_control); |
| 611 this_effects.push_back(transition_effect); |
| 612 |
| 613 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
| 614 } |
| 615 |
| 616 // Create single chokepoint for the control. |
570 int const this_control_count = static_cast<int>(this_controls.size()); | 617 int const this_control_count = static_cast<int>(this_controls.size()); |
571 this_control = | 618 if (this_control_count == 1) { |
572 (this_control_count == 1) | 619 this_control = this_controls.front(); |
573 ? this_controls.front() | 620 this_effect = this_effects.front(); |
574 : graph()->NewNode(common()->Merge(this_control_count), | 621 } else { |
575 this_control_count, &this_controls.front()); | 622 this_control = |
| 623 graph()->NewNode(common()->Merge(this_control_count), |
| 624 this_control_count, &this_controls.front()); |
| 625 this_effects.push_back(this_control); |
| 626 this_effect = |
| 627 graph()->NewNode(common()->EffectPhi(this_control_count), |
| 628 this_control_count + 1, &this_effects.front()); |
| 629 } |
576 } | 630 } |
577 | 631 |
578 // Certain stores need a prototype chain check because shape changes | 632 // Certain stores need a prototype chain check because shape changes |
579 // could allow callbacks on elements in the prototype chain that are | 633 // could allow callbacks on elements in the prototype chain that are |
580 // not compatible with (monomorphic) keyed stores. | 634 // not compatible with (monomorphic) keyed stores. |
581 Handle<JSObject> holder; | 635 Handle<JSObject> holder; |
582 if (access_info.holder().ToHandle(&holder)) { | 636 if (access_info.holder().ToHandle(&holder)) { |
583 AssumePrototypesStable(receiver_type, holder); | 637 AssumePrototypesStable(receiver_type, holder); |
584 } | 638 } |
585 | 639 |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 } | 952 } |
899 | 953 |
900 | 954 |
901 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 955 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
902 return jsgraph()->simplified(); | 956 return jsgraph()->simplified(); |
903 } | 957 } |
904 | 958 |
905 } // namespace compiler | 959 } // namespace compiler |
906 } // namespace internal | 960 } // namespace internal |
907 } // namespace v8 | 961 } // namespace v8 |
OLD | NEW |