Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 10918164: Inline GrowableObjectArray capacity getter, use CHA to eliminate load/store fields class checks. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_optimizer.h" 5 #include "vm/flow_graph_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/cha.h" 8 #include "vm/cha.h"
9 #include "vm/flow_graph_builder.h" 9 #include "vm/flow_graph_builder.h"
10 #include "vm/hash_map.h" 10 #include "vm/hash_map.h"
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 field = cls.LookupInstanceField(field_name); 528 field = cls.LookupInstanceField(field_name);
529 if (!field.IsNull()) { 529 if (!field.IsNull()) {
530 return field.raw(); 530 return field.raw();
531 } 531 }
532 cls = cls.SuperClass(); 532 cls = cls.SuperClass();
533 } 533 }
534 return Field::null(); 534 return Field::null();
535 } 535 }
536 536
537 537
538 // Use CHA to determine if the call needs a class check: if the callee's
539 // receiver is the same as the caller's receiver and there are no overriden
540 // callee functions, then no class check is needed.
541 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
542 InstanceCallInstr* call) const {
543 if (!FLAG_use_cha) return true;
544 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition();
545 ASSERT(callee_receiver != NULL);
546 const Function& function = flow_graph_->parsed_function().function();
547 if (function.IsDynamicFunction() &&
548 callee_receiver->IsParameter() &&
549 (callee_receiver->AsParameter()->index() == 0)) {
550 const intptr_t static_receiver_cid = Class::Handle(function.Owner()).id();
551 ZoneGrowableArray<intptr_t>* subclass_cids =
552 CHA::GetSubclassIdsOf(static_receiver_cid);
553 if (subclass_cids->is_empty()) {
554 // No subclasses, no check needed.
555 return false;
556 }
557 ZoneGrowableArray<Function*>* overriding_functions =
558 CHA::GetNamedInstanceFunctionsOf(*subclass_cids, call->function_name());
559 if (overriding_functions->is_empty()) {
560 // No overriding functions.
561 return false;
562 }
563 }
564 return true;
565 }
566
538 // Only unique implicit instance getters can be currently handled. 567 // Only unique implicit instance getters can be currently handled.
539 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { 568 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
540 ASSERT(call->HasICData()); 569 ASSERT(call->HasICData());
541 const ICData& ic_data = *call->ic_data(); 570 const ICData& ic_data = *call->ic_data();
542 if (ic_data.NumberOfChecks() == 0) { 571 if (ic_data.NumberOfChecks() == 0) {
543 // No type feedback collected. 572 // No type feedback collected.
544 return false; 573 return false;
545 } 574 }
546 Function& target = Function::Handle(); 575 Function& target = Function::Handle();
547 GrowableArray<intptr_t> class_ids; 576 GrowableArray<intptr_t> class_ids;
548 ic_data.GetCheckAt(0, &class_ids, &target); 577 ic_data.GetCheckAt(0, &class_ids, &target);
549 ASSERT(class_ids.length() == 1); 578 ASSERT(class_ids.length() == 1);
550 579
551 if (target.kind() == RawFunction::kImplicitGetter) { 580 if (target.kind() == RawFunction::kImplicitGetter) {
552 if (!HasOneTarget(ic_data)) { 581 if (!HasOneTarget(ic_data)) {
553 // TODO(srdjan): Implement for mutiple targets. 582 // TODO(srdjan): Implement for mutiple targets.
554 return false; 583 return false;
555 } 584 }
556 // Inline implicit instance getter. 585 // Inline implicit instance getter.
557 const String& field_name = 586 const String& field_name =
558 String::Handle(Field::NameFromGetter(call->function_name())); 587 String::Handle(Field::NameFromGetter(call->function_name()));
559 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); 588 const Field& field = Field::Handle(GetField(class_ids[0], field_name));
560 ASSERT(!field.IsNull()); 589 ASSERT(!field.IsNull());
561 590
562 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); 591 if (InstanceCallNeedsClassCheck(call)) {
592 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
593 }
563 // Detach environment from the original instruction because it can't 594 // Detach environment from the original instruction because it can't
564 // deoptimize. 595 // deoptimize.
565 call->set_env(NULL); 596 call->set_env(NULL);
566 LoadInstanceFieldInstr* load = 597 LoadInstanceFieldInstr* load =
567 new LoadInstanceFieldInstr(field, call->ArgumentAt(0)->value()); 598 new LoadInstanceFieldInstr(field, call->ArgumentAt(0)->value());
568 call->ReplaceWith(load, current_iterator()); 599 call->ReplaceWith(load, current_iterator());
569 RemovePushArguments(call); 600 RemovePushArguments(call);
570 return true; 601 return true;
571 } 602 }
572 603
(...skipping 27 matching lines...) Expand all
600 LoadVMFieldInstr* load = new LoadVMFieldInstr( 631 LoadVMFieldInstr* load = new LoadVMFieldInstr(
601 call->ArgumentAt(0)->value(), 632 call->ArgumentAt(0)->value(),
602 length_offset, 633 length_offset,
603 Type::ZoneHandle(Type::SmiType())); 634 Type::ZoneHandle(Type::SmiType()));
604 load->set_result_cid(kSmiCid); 635 load->set_result_cid(kSmiCid);
605 call->ReplaceWith(load, current_iterator()); 636 call->ReplaceWith(load, current_iterator());
606 RemovePushArguments(call); 637 RemovePushArguments(call);
607 return true; 638 return true;
608 } 639 }
609 640
641 if (recognized_kind == MethodRecognizer::kGrowableArrayCapacity) {
642 // Check receiver class.
643 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
644
645 // TODO(srdjan): type of load should be GrowableObjectArrayType.
646 LoadVMFieldInstr* data_load = new LoadVMFieldInstr(
647 call->ArgumentAt(0)->value(),
648 Array::data_offset(),
649 Type::ZoneHandle(Type::DynamicType()));
650 data_load->set_result_cid(kGrowableObjectArrayCid);
651 InsertBefore(call, data_load, NULL, Definition::kValue);
652
653 LoadVMFieldInstr* length_load = new LoadVMFieldInstr(
654 new Value(data_load),
655 Array::length_offset(),
656 Type::ZoneHandle(Type::SmiType()));
657 length_load->set_result_cid(kSmiCid);
658
659 call->ReplaceWith(length_load, current_iterator());
660 RemovePushArguments(call);
661 return true;
662 }
663
610 if (recognized_kind == MethodRecognizer::kStringBaseLength) { 664 if (recognized_kind == MethodRecognizer::kStringBaseLength) {
611 if (!HasOneTarget(ic_data)) { 665 if (!HasOneTarget(ic_data)) {
612 // Target is not only StringBase_get_length. 666 // Target is not only StringBase_get_length.
613 return false; 667 return false;
614 } 668 }
615 // Check receiver class. 669 // Check receiver class.
616 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy()); 670 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
617 671
618 LoadVMFieldInstr* load = new LoadVMFieldInstr( 672 LoadVMFieldInstr* load = new LoadVMFieldInstr(
619 call->ArgumentAt(0)->value(), 673 call->ArgumentAt(0)->value(),
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 return; 735 return;
682 } 736 }
683 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) { 737 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) {
684 return; 738 return;
685 } 739 }
686 if (TryInlineInstanceMethod(instr)) { 740 if (TryInlineInstanceMethod(instr)) {
687 return; 741 return;
688 } 742 }
689 const ICData& unary_checks = 743 const ICData& unary_checks =
690 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); 744 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks());
691 if (FLAG_use_cha) { 745 if (!InstanceCallNeedsClassCheck(instr)) {
692 // Check if receiver can have only one target, in which case 746 const bool call_with_checks = false;
693 // we emit call without class checks. 747 PolymorphicInstanceCallInstr* call =
694 Definition* receiver = instr->ArgumentAt(0)->value()->definition(); 748 new PolymorphicInstanceCallInstr(instr, unary_checks,
695 ASSERT(receiver != NULL); 749 call_with_checks);
696 const Function& function = flow_graph_->parsed_function().function(); 750 instr->ReplaceWith(call, current_iterator());
697 if (function.IsDynamicFunction() && 751 return;
698 receiver->IsParameter() &&
699 (receiver->AsParameter()->index() == 0)) {
700 intptr_t static_receiver_cid = Class::Handle(function.Owner()).id();
701 ZoneGrowableArray<intptr_t>* subclass_cids =
702 CHA::GetSubclassIdsOf(static_receiver_cid);
703 ZoneGrowableArray<Function*>* overriding_functions =
704 CHA::GetNamedInstanceFunctionsOf(*subclass_cids,
705 instr->function_name());
706 if (overriding_functions->is_empty()) {
707 const bool call_with_checks = false;
708 PolymorphicInstanceCallInstr* call =
709 new PolymorphicInstanceCallInstr(instr, unary_checks,
710 call_with_checks);
711 instr->ReplaceWith(call, current_iterator());
712 return;
713 }
714 }
715 } 752 }
716 const intptr_t kMaxChecks = 4; 753 const intptr_t kMaxChecks = 4;
717 if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) { 754 if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) {
718 bool call_with_checks; 755 bool call_with_checks;
719 // TODO(srdjan): Add check class instr for mixed smi/non-smi. 756 // TODO(srdjan): Add check class instr for mixed smi/non-smi.
720 if (HasOneTarget(unary_checks) && 757 if (HasOneTarget(unary_checks) &&
721 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { 758 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) {
722 // Type propagation has not run yet, we cannot eliminate the check. 759 // Type propagation has not run yet, we cannot eliminate the check.
723 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); 760 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
724 // Call can still deoptimize, do not detach environment from instr. 761 // Call can still deoptimize, do not detach environment from instr.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 // Not an implicit setter. 806 // Not an implicit setter.
770 // TODO(srdjan): Inline special setters. 807 // TODO(srdjan): Inline special setters.
771 return false; 808 return false;
772 } 809 }
773 // Inline implicit instance setter. 810 // Inline implicit instance setter.
774 const String& field_name = 811 const String& field_name =
775 String::Handle(Field::NameFromSetter(instr->function_name())); 812 String::Handle(Field::NameFromSetter(instr->function_name()));
776 const Field& field = Field::Handle(GetField(class_id, field_name)); 813 const Field& field = Field::Handle(GetField(class_id, field_name));
777 ASSERT(!field.IsNull()); 814 ASSERT(!field.IsNull());
778 815
779 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); 816 if (InstanceCallNeedsClassCheck(instr)) {
817 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
818 }
780 // Detach environment from the original instruction because it can't 819 // Detach environment from the original instruction because it can't
781 // deoptimize. 820 // deoptimize.
782 instr->set_env(NULL); 821 instr->set_env(NULL);
783 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr( 822 StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr(
784 field, 823 field,
785 instr->ArgumentAt(0)->value(), 824 instr->ArgumentAt(0)->value(),
786 instr->ArgumentAt(1)->value()); 825 instr->ArgumentAt(1)->value());
787 instr->ReplaceWith(store, current_iterator()); 826 instr->ReplaceWith(store, current_iterator());
788 RemovePushArguments(instr); 827 RemovePushArguments(instr);
789 return true; 828 return true;
(...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after
1327 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. 1366 DirectChainedHashMap<Definition*> child_map(*map); // Copy map.
1328 OptimizeRecursive(child, &child_map); 1367 OptimizeRecursive(child, &child_map);
1329 } else { 1368 } else {
1330 OptimizeRecursive(child, map); // Reuse map for the last child. 1369 OptimizeRecursive(child, map); // Reuse map for the last child.
1331 } 1370 }
1332 } 1371 }
1333 } 1372 }
1334 1373
1335 1374
1336 } // namespace dart 1375 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698