| 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 |