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

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

Issue 10993023: Inline String isEmpty, refactor inlining of intrinsics. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 2 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 608 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 ZoneGrowableArray<Function*>* overriding_functions = 619 ZoneGrowableArray<Function*>* overriding_functions =
620 CHA::GetNamedInstanceFunctionsOf(*subclass_cids, call->function_name()); 620 CHA::GetNamedInstanceFunctionsOf(*subclass_cids, call->function_name());
621 if (overriding_functions->is_empty()) { 621 if (overriding_functions->is_empty()) {
622 // No overriding functions. 622 // No overriding functions.
623 return false; 623 return false;
624 } 624 }
625 } 625 }
626 return true; 626 return true;
627 } 627 }
628 628
629
630 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
631 ASSERT(call->HasICData());
632 const ICData& ic_data = *call->ic_data();
633 Function& target = Function::Handle();
634 GrowableArray<intptr_t> class_ids;
635 ic_data.GetCheckAt(0, &class_ids, &target);
636 ASSERT(class_ids.length() == 1);
637 // Inline implicit instance getter.
638 const String& field_name =
639 String::Handle(Field::NameFromGetter(call->function_name()));
640 const Field& field = Field::Handle(GetField(class_ids[0], field_name));
641 ASSERT(!field.IsNull());
642
643 if (InstanceCallNeedsClassCheck(call)) {
644 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
645 }
646 // Detach environment from the original instruction because it can't
647 // deoptimize.
648 call->set_env(NULL);
649 LoadFieldInstr* load = new LoadFieldInstr(
650 call->ArgumentAt(0)->value(),
651 field.Offset(),
652 AbstractType::ZoneHandle(field.type()));
653 call->ReplaceWith(load, current_iterator());
654 RemovePushArguments(call);
655 }
656
657
658 void FlowGraphOptimizer::InlineArrayLengthGetter(InstanceCallInstr* call,
659 intptr_t length_offset,
660 bool is_immutable) {
661 // Check receiver class.
662 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
663
664 LoadFieldInstr* load = new LoadFieldInstr(
665 call->ArgumentAt(0)->value(),
666 length_offset,
667 Type::ZoneHandle(Type::SmiType()),
668 is_immutable);
669 load->set_result_cid(kSmiCid);
670 call->ReplaceWith(load, current_iterator());
671 RemovePushArguments(call);
672 }
673
674
675 void FlowGraphOptimizer::InlineGArrayCapacityGetter(InstanceCallInstr* call) {
676 // Check receiver class.
677 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
678
679 // TODO(srdjan): type of load should be GrowableObjectArrayType.
680 LoadFieldInstr* data_load = new LoadFieldInstr(
681 call->ArgumentAt(0)->value(),
682 Array::data_offset(),
683 Type::ZoneHandle(Type::DynamicType()));
684 data_load->set_result_cid(kArrayCid);
685 InsertBefore(call, data_load, NULL, Definition::kValue);
686
687 LoadFieldInstr* length_load = new LoadFieldInstr(
688 new Value(data_load),
689 Array::length_offset(),
690 Type::ZoneHandle(Type::SmiType()));
691 length_load->set_result_cid(kSmiCid);
692
693 call->ReplaceWith(length_load, current_iterator());
694 RemovePushArguments(call);
695 }
696
697
698 void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) {
699 // Check receiver class.
700 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
701
702 const bool is_immutable = true; // String length is immutable.
703 LoadFieldInstr* load = new LoadFieldInstr(
704 call->ArgumentAt(0)->value(),
705 String::length_offset(),
706 Type::ZoneHandle(Type::SmiType()),
707 is_immutable);
708 load->set_result_cid(kSmiCid);
709 call->ReplaceWith(load, current_iterator());
710 RemovePushArguments(call);
711 }
712
713
714 void FlowGraphOptimizer::InlineStringIsEmptyTester(InstanceCallInstr* call) {
715 // Check receiver class.
716 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
717 // Get string length.
718 const bool is_immutable = true; // String length is immutable.
719 LoadFieldInstr* load = new LoadFieldInstr(
720 call->ArgumentAt(0)->value(),
721 String::length_offset(),
722 Type::ZoneHandle(Type::SmiType()),
723 is_immutable);
724 load->set_result_cid(kSmiCid);
Florian Schneider 2012/09/26 08:36:12 Maybe you can even share the code for building the
srdjan 2012/09/28 16:56:56 Done.
725 InsertBefore(call, load, NULL, Definition::kValue);
726
727 ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0)));
728 InsertBefore(call, zero, NULL, Definition::kValue);
729
730 StrictCompareInstr* compare =
731 new StrictCompareInstr(Token::kEQ_STRICT,
732 new Value(load),
733 new Value(zero));
734 call->ReplaceWith(compare, current_iterator());
735 RemovePushArguments(call);
736 }
737
738
629 // Only unique implicit instance getters can be currently handled. 739 // Only unique implicit instance getters can be currently handled.
630 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { 740 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
631 ASSERT(call->HasICData()); 741 ASSERT(call->HasICData());
632 const ICData& ic_data = *call->ic_data(); 742 const ICData& ic_data = *call->ic_data();
633 if (ic_data.NumberOfChecks() == 0) { 743 if (ic_data.NumberOfChecks() == 0) {
634 // No type feedback collected. 744 // No type feedback collected.
635 return false; 745 return false;
636 } 746 }
637 Function& target = Function::Handle(); 747 Function& target = Function::Handle(ic_data.GetTargetAt(0));
638 GrowableArray<intptr_t> class_ids;
639 ic_data.GetCheckAt(0, &class_ids, &target);
640 ASSERT(class_ids.length() == 1);
641
642 if (target.kind() == RawFunction::kImplicitGetter) { 748 if (target.kind() == RawFunction::kImplicitGetter) {
643 if (!ic_data.HasOneTarget()) { 749 if (!ic_data.HasOneTarget()) {
644 // TODO(srdjan): Implement for mutiple targets. 750 // TODO(srdjan): Implement for mutiple targets.
645 return false; 751 return false;
646 } 752 }
647 // Inline implicit instance getter. 753 InlineImplicitInstanceGetter(call);
648 const String& field_name =
649 String::Handle(Field::NameFromGetter(call->function_name()));
650 const Field& field = Field::Handle(GetField(class_ids[0], field_name));
651 ASSERT(!field.IsNull());
652
653 if (InstanceCallNeedsClassCheck(call)) {
654 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
655 }
656 // Detach environment from the original instruction because it can't
657 // deoptimize.
658 call->set_env(NULL);
659 LoadFieldInstr* load = new LoadFieldInstr(
660 call->ArgumentAt(0)->value(),
661 field.Offset(),
662 AbstractType::ZoneHandle(field.type()));
663 call->ReplaceWith(load, current_iterator());
664 RemovePushArguments(call);
665 return true; 754 return true;
666 } 755 }
667 756
668 // Not an implicit getter. 757 // Not an implicit getter.
669 MethodRecognizer::Kind recognized_kind = 758 MethodRecognizer::Kind recognized_kind =
670 MethodRecognizer::RecognizeKind(target); 759 MethodRecognizer::RecognizeKind(target);
671 760
672 // VM objects length getter. 761 // VM objects length getter.
673 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || 762 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) ||
674 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || 763 (recognized_kind == MethodRecognizer::kImmutableArrayLength) ||
675 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { 764 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) {
676 if (!ic_data.HasOneTarget()) { 765 if (!ic_data.HasOneTarget()) {
677 // TODO(srdjan): Implement for mutiple targets. 766 // TODO(srdjan): Implement for mutiple targets.
678 return false; 767 return false;
679 } 768 }
680 intptr_t length_offset = -1;
681 bool is_immutable = false;
682 switch (recognized_kind) { 769 switch (recognized_kind) {
683 case MethodRecognizer::kObjectArrayLength: 770 case MethodRecognizer::kObjectArrayLength:
684 case MethodRecognizer::kImmutableArrayLength: 771 case MethodRecognizer::kImmutableArrayLength:
685 length_offset = Array::length_offset(); 772 InlineArrayLengthGetter(call, Array::length_offset(), true);
686 is_immutable = true;
687 break; 773 break;
688 case MethodRecognizer::kGrowableArrayLength: 774 case MethodRecognizer::kGrowableArrayLength:
689 length_offset = GrowableObjectArray::length_offset(); 775 InlineArrayLengthGetter(call,
776 GrowableObjectArray::length_offset(),
777 false);
690 break; 778 break;
691 default: 779 default:
692 UNREACHABLE(); 780 UNREACHABLE();
693 } 781 }
694 // Check receiver class.
695 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
696
697 LoadFieldInstr* load = new LoadFieldInstr(
698 call->ArgumentAt(0)->value(),
699 length_offset,
700 Type::ZoneHandle(Type::SmiType()),
701 is_immutable);
702 load->set_result_cid(kSmiCid);
703 call->ReplaceWith(load, current_iterator());
704 RemovePushArguments(call);
705 return true; 782 return true;
706 } 783 }
707 784
708 if (recognized_kind == MethodRecognizer::kGrowableArrayCapacity) { 785 if (recognized_kind == MethodRecognizer::kGrowableArrayCapacity) {
709 // Check receiver class. 786 InlineGArrayCapacityGetter(call);
710 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
711
712 // TODO(srdjan): type of load should be GrowableObjectArrayType.
713 LoadFieldInstr* data_load = new LoadFieldInstr(
714 call->ArgumentAt(0)->value(),
715 Array::data_offset(),
716 Type::ZoneHandle(Type::DynamicType()));
717 data_load->set_result_cid(kArrayCid);
718 InsertBefore(call, data_load, NULL, Definition::kValue);
719
720 LoadFieldInstr* length_load = new LoadFieldInstr(
721 new Value(data_load),
722 Array::length_offset(),
723 Type::ZoneHandle(Type::SmiType()));
724 length_load->set_result_cid(kSmiCid);
725
726 call->ReplaceWith(length_load, current_iterator());
727 RemovePushArguments(call);
728 return true; 787 return true;
729 } 788 }
730 789
731 if (recognized_kind == MethodRecognizer::kStringBaseLength) { 790 if (recognized_kind == MethodRecognizer::kStringBaseLength) {
732 if (!ic_data.HasOneTarget()) { 791 if (!ic_data.HasOneTarget()) {
733 // Target is not only StringBase_get_length. 792 // Target is not only StringBase_get_length.
734 return false; 793 return false;
735 } 794 }
736 // Check receiver class. 795 InlineStringLengthGetter(call);
737 AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
738
739 const bool is_immutable = true; // String length is immutable.
740 LoadFieldInstr* load = new LoadFieldInstr(
741 call->ArgumentAt(0)->value(),
742 String::length_offset(),
743 Type::ZoneHandle(Type::SmiType()),
744 is_immutable);
745 load->set_result_cid(kSmiCid);
746 call->ReplaceWith(load, current_iterator());
747 RemovePushArguments(call);
748 return true; 796 return true;
749 } 797 }
798
750 return false; 799 return false;
751 } 800 }
752 801
753 802
754 // Inline only simple, frequently called core library methods. 803 // Inline only simple, frequently called core library methods.
755 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 804 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
756 ASSERT(call->HasICData()); 805 ASSERT(call->HasICData());
757 const ICData& ic_data = *call->ic_data(); 806 const ICData& ic_data = *call->ic_data();
758 if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) { 807 if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) {
759 // No type feedback collected. 808 // No type feedback collected.
760 return false; 809 return false;
761 } 810 }
762 Function& target = Function::Handle(); 811 Function& target = Function::Handle();
763 GrowableArray<intptr_t> class_ids; 812 GrowableArray<intptr_t> class_ids;
764 ic_data.GetCheckAt(0, &class_ids, &target); 813 ic_data.GetCheckAt(0, &class_ids, &target);
765 MethodRecognizer::Kind recognized_kind = 814 MethodRecognizer::Kind recognized_kind =
766 MethodRecognizer::RecognizeKind(target); 815 MethodRecognizer::RecognizeKind(target);
767 816
768 if ((recognized_kind == MethodRecognizer::kDoubleToDouble) && 817 if ((recognized_kind == MethodRecognizer::kDoubleToDouble) &&
769 (class_ids[0] == kDoubleCid)) { 818 (class_ids[0] == kDoubleCid)) {
770 DoubleToDoubleInstr* d2d_instr = 819 DoubleToDoubleInstr* d2d_instr =
771 new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), call); 820 new DoubleToDoubleInstr(call->ArgumentAt(0)->value(), call);
772 call->ReplaceWith(d2d_instr, current_iterator()); 821 call->ReplaceWith(d2d_instr, current_iterator());
773 RemovePushArguments(call); 822 RemovePushArguments(call);
774 return true; 823 return true;
775 } 824 }
825
776 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) && 826 if ((recognized_kind == MethodRecognizer::kIntegerToDouble) &&
777 (class_ids[0] == kSmiCid)) { 827 (class_ids[0] == kSmiCid)) {
778 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call); 828 SmiToDoubleInstr* s2d_instr = new SmiToDoubleInstr(call);
779 call->ReplaceWith(s2d_instr, current_iterator()); 829 call->ReplaceWith(s2d_instr, current_iterator());
780 // Pushed arguments are not removed because SmiToDouble is implemented 830 // Pushed arguments are not removed because SmiToDouble is implemented
781 // as a call. 831 // as a call.
782 return true; 832 return true;
783 } 833 }
834
835 if (recognized_kind == MethodRecognizer::kStringBaseIsEmpty) {
836 if (!ic_data.HasOneTarget()) {
837 // Target is not only StringBase_get_length.
838 return false;
839 }
840 InlineStringIsEmptyTester(call);
841 return true;
842 }
843
784 return false; 844 return false;
785 } 845 }
786 846
787 847
788 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 848 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
789 if (instr->HasICData() && (instr->ic_data()->NumberOfChecks() > 0)) { 849 if (instr->HasICData() && (instr->ic_data()->NumberOfChecks() > 0)) {
790 const Token::Kind op_kind = instr->token_kind(); 850 const Token::Kind op_kind = instr->token_kind();
791 if (Token::IsIndexOperator(op_kind) && 851 if (Token::IsIndexOperator(op_kind) &&
792 TryReplaceWithArrayOp(instr, op_kind)) { 852 TryReplaceWithArrayOp(instr, op_kind)) {
793 return; 853 return;
(...skipping 2237 matching lines...) Expand 10 before | Expand all | Expand 10 after
3031 3091
3032 if (FLAG_trace_constant_propagation) { 3092 if (FLAG_trace_constant_propagation) {
3033 OS::Print("\n==== After constant propagation ====\n"); 3093 OS::Print("\n==== After constant propagation ====\n");
3034 FlowGraphPrinter printer(*graph_); 3094 FlowGraphPrinter printer(*graph_);
3035 printer.PrintBlocks(); 3095 printer.PrintBlocks();
3036 } 3096 }
3037 } 3097 }
3038 3098
3039 3099
3040 } // namespace dart 3100 } // 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