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

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

Issue 25411004: Polymorphic inlining for []= operators. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: fixed checked mode Created 7 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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/dart_entry.h" 9 #include "vm/dart_entry.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
(...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after
680 // Remove the original push arguments. 680 // Remove the original push arguments.
681 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 681 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
682 PushArgumentInstr* push = call->PushArgumentAt(i); 682 PushArgumentInstr* push = call->PushArgumentAt(i);
683 push->ReplaceUsesWith(push->value()->definition()); 683 push->ReplaceUsesWith(push->value()->definition());
684 push->RemoveFromGraph(); 684 push->RemoveFromGraph();
685 } 685 }
686 call->ReplaceWith(replacement, current_iterator()); 686 call->ReplaceWith(replacement, current_iterator());
687 } 687 }
688 688
689 689
690 static intptr_t ReceiverClassId(InstanceCallInstr* call) {
691 if (!call->HasICData()) return kIllegalCid;
692
693 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks());
694
695 if (ic_data.NumberOfChecks() != 1) return kIllegalCid;
696 ASSERT(ic_data.HasOneTarget());
697
698 Function& target = Function::Handle();
699 intptr_t class_id;
700 ic_data.GetOneClassCheckAt(0, &class_id, &target);
701 return class_id;
702 }
703
704
705 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, 690 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
706 intptr_t deopt_id, 691 intptr_t deopt_id,
707 Environment* deopt_environment, 692 Environment* deopt_environment,
708 Instruction* insert_before) { 693 Instruction* insert_before) {
709 if (to_check->Type()->ToCid() != kSmiCid) { 694 if (to_check->Type()->ToCid() != kSmiCid) {
710 InsertBefore(insert_before, 695 InsertBefore(insert_before,
711 new CheckSmiInstr(new Value(to_check), deopt_id), 696 new CheckSmiInstr(new Value(to_check), deopt_id),
712 deopt_environment, 697 deopt_environment,
713 Definition::kEffect); 698 Definition::kEffect);
714 } 699 }
715 } 700 }
716 701
717 702
703 Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
704 const ICData& unary_checks,
705 intptr_t deopt_id) {
706 if ((unary_checks.NumberOfChecks() == 1) &&
707 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
708 return new CheckSmiInstr(new Value(to_check), deopt_id);
709 }
710 return new CheckClassInstr(new Value(to_check), deopt_id, unary_checks);
711 }
712
713
718 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, 714 void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
719 const ICData& unary_checks, 715 const ICData& unary_checks,
720 intptr_t deopt_id, 716 intptr_t deopt_id,
721 Environment* deopt_environment, 717 Environment* deopt_environment,
722 Instruction* insert_before) { 718 Instruction* insert_before) {
723 // Type propagation has not run yet, we cannot eliminate the check. 719 // Type propagation has not run yet, we cannot eliminate the check.
724 Instruction* check = NULL; 720 Instruction* check = GetCheckClass(to_check, unary_checks, deopt_id);
725 if ((unary_checks.NumberOfChecks() == 1) &&
726 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
727 check = new CheckSmiInstr(new Value(to_check), deopt_id);
728 } else {
729 check = new CheckClassInstr(new Value(to_check), deopt_id, unary_checks);
730 }
731 InsertBefore(insert_before, check, deopt_environment, Definition::kEffect); 721 InsertBefore(insert_before, check, deopt_environment, Definition::kEffect);
732 } 722 }
733 723
734 724
735 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { 725 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
736 AddCheckClass(call->ArgumentAt(0), 726 AddCheckClass(call->ArgumentAt(0),
737 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()), 727 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()),
738 call->deopt_id(), 728 call->deopt_id(),
739 call->env(), 729 call->env(),
740 call); 730 call);
741 } 731 }
742 732
743 733
744 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { 734 static bool ArgIsAlways(intptr_t cid,
745 ASSERT(ic_data.num_args_tested() > arg_n); 735 const ICData& ic_data,
746 if (ic_data.NumberOfChecks() == 0) return false; 736 intptr_t arg_number) {
747 GrowableArray<intptr_t> class_ids; 737 ASSERT(ic_data.num_args_tested() > arg_number);
748 Function& target = Function::Handle(); 738 const intptr_t num_checks = ic_data.NumberOfChecks();
749 const intptr_t len = ic_data.NumberOfChecks(); 739 if (num_checks == 0) return false;
750 for (intptr_t i = 0; i < len; i++) { 740 for (intptr_t i = 0; i < num_checks; i++) {
751 ic_data.GetCheckAt(i, &class_ids, &target); 741 if (ic_data.GetClassIdAt(i, arg_number) != cid) return false;
752 if (class_ids[arg_n] != kSmiCid) return false;
753 } 742 }
754 return true; 743 return true;
755 } 744 }
756 745
757 746
758 // Returns array classid to load from, array and index value
759
760 intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call,
761 intptr_t class_id,
762 Definition** array,
763 Definition** index) {
764 // Insert class check and index smi checks and attach a copy of the
765 // original environment because the operation can still deoptimize.
766 AddReceiverCheck(call);
767 InsertBefore(call,
768 new CheckSmiInstr(new Value(*index), call->deopt_id()),
769 call->env(),
770 Definition::kEffect);
771
772 // Insert array length load and bounds check.
773 const bool is_immutable =
774 CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
775 LoadFieldInstr* length =
776 new LoadFieldInstr(new Value(*array),
777 CheckArrayBoundInstr::LengthOffsetFor(class_id),
778 Type::ZoneHandle(Type::SmiType()),
779 is_immutable);
780 length->set_result_cid(kSmiCid);
781 length->set_recognized_kind(
782 LoadFieldInstr::RecognizedKindFromArrayCid(class_id));
783 InsertBefore(call, length, NULL, Definition::kValue);
784 InsertBefore(call,
785 new CheckArrayBoundInstr(new Value(length),
786 new Value(*index),
787 call->deopt_id()),
788 call->env(),
789 Definition::kEffect);
790
791 if (class_id == kGrowableObjectArrayCid) {
792 // Insert data elements load.
793 LoadFieldInstr* elements =
794 new LoadFieldInstr(new Value(*array),
795 GrowableObjectArray::data_offset(),
796 Type::ZoneHandle(Type::DynamicType()));
797 elements->set_result_cid(kArrayCid);
798 InsertBefore(call, elements, NULL, Definition::kValue);
799 *array = elements;
800 return kArrayCid;
801 }
802 if (RawObject::IsExternalTypedDataClassId(class_id)) {
803 LoadUntaggedInstr* elements =
804 new LoadUntaggedInstr(new Value(*array),
805 ExternalTypedData::data_offset());
806 InsertBefore(call, elements, NULL, Definition::kValue);
807 *array = elements;
808 }
809 return class_id;
810 }
811
812
813 static bool CanUnboxInt32() { 747 static bool CanUnboxInt32() {
814 // Int32/Uint32 can be unboxed if it fits into a smi or the platform 748 // Int32/Uint32 can be unboxed if it fits into a smi or the platform
815 // supports unboxed mints. 749 // supports unboxed mints.
816 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints(); 750 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints();
817 } 751 }
818 752
819 753
754 static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) {
755 switch (kind) {
756 case MethodRecognizer::kImmutableArrayGetIndexed:
757 return kImmutableArrayCid;
758
759 case MethodRecognizer::kObjectArrayGetIndexed:
760 case MethodRecognizer::kObjectArraySetIndexed:
761 return kArrayCid;
762
763 case MethodRecognizer::kGrowableArrayGetIndexed:
764 case MethodRecognizer::kGrowableArraySetIndexed:
765 return kGrowableObjectArrayCid;
766
767 case MethodRecognizer::kFloat32ArrayGetIndexed:
768 case MethodRecognizer::kFloat32ArraySetIndexed:
769 return kTypedDataFloat32ArrayCid;
770
771 case MethodRecognizer::kFloat64ArrayGetIndexed:
772 case MethodRecognizer::kFloat64ArraySetIndexed:
773 return kTypedDataFloat64ArrayCid;
774
775 case MethodRecognizer::kInt8ArrayGetIndexed:
776 case MethodRecognizer::kInt8ArraySetIndexed:
777 return kTypedDataInt8ArrayCid;
778
779 case MethodRecognizer::kUint8ArrayGetIndexed:
780 case MethodRecognizer::kUint8ArraySetIndexed:
781 return kTypedDataUint8ArrayCid;
782
783 case MethodRecognizer::kUint8ClampedArrayGetIndexed:
784 case MethodRecognizer::kUint8ClampedArraySetIndexed:
785 return kTypedDataUint8ClampedArrayCid;
786
787 case MethodRecognizer::kExternalUint8ArrayGetIndexed:
788 case MethodRecognizer::kExternalUint8ArraySetIndexed:
789 return kExternalTypedDataUint8ArrayCid;
790
791 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
792 case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
793 return kExternalTypedDataUint8ClampedArrayCid;
794
795 case MethodRecognizer::kInt16ArrayGetIndexed:
796 case MethodRecognizer::kInt16ArraySetIndexed:
797 return kTypedDataInt16ArrayCid;
798
799 case MethodRecognizer::kUint16ArrayGetIndexed:
800 case MethodRecognizer::kUint16ArraySetIndexed:
801 return kTypedDataUint16ArrayCid;
802
803 case MethodRecognizer::kInt32ArrayGetIndexed:
804 case MethodRecognizer::kInt32ArraySetIndexed:
805 return kTypedDataInt32ArrayCid;
806
807 case MethodRecognizer::kUint32ArrayGetIndexed:
808 case MethodRecognizer::kUint32ArraySetIndexed:
809 return kTypedDataUint32ArrayCid;
810
811 case MethodRecognizer::kFloat32x4ArrayGetIndexed:
812 case MethodRecognizer::kFloat32x4ArraySetIndexed:
813 return kTypedDataFloat32x4ArrayCid;
814
815 default:
816 break;
817 }
818 return kIllegalCid;
819 }
820
821
820 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { 822 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) {
821 const intptr_t class_id = ReceiverClassId(call); 823 // Check for monomorphic IC data.
822 ICData& value_check = ICData::ZoneHandle(); 824 if (!call->HasICData()) return false;
823 switch (class_id) { 825 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks());
824 case kArrayCid: 826 if (ic_data.NumberOfChecks() != 1) return false;
825 case kGrowableObjectArrayCid: 827 ASSERT(ic_data.HasOneTarget());
826 if (ArgIsAlwaysSmi(*call->ic_data(), 2)) { 828
827 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); 829 const Function& target = Function::Handle(ic_data.GetTargetAt(0));
828 } 830 TargetEntryInstr* entry;
829 break; 831 Definition* last;
830 case kTypedDataInt8ArrayCid: 832 if (!TryInlineRecognizedMethod(target,
831 case kTypedDataUint8ArrayCid: 833 call,
832 case kTypedDataUint8ClampedArrayCid: 834 call->token_pos(),
833 case kExternalTypedDataUint8ArrayCid: 835 *call->ic_data(),
834 case kExternalTypedDataUint8ClampedArrayCid: 836 &entry, &last)) {
835 case kTypedDataInt16ArrayCid: 837 return false;
836 case kTypedDataUint16ArrayCid:
837 // Check that value is always smi.
838 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
839 if ((value_check.NumberOfChecks() != 1) ||
840 (value_check.GetReceiverClassIdAt(0) != kSmiCid)) {
841 return false;
842 }
843 break;
844 case kTypedDataInt32ArrayCid:
845 case kTypedDataUint32ArrayCid: {
846 if (!CanUnboxInt32()) return false;
847 // Check that value is always smi or mint, if the platform has unboxed
848 // mints (ia32 with at least SSE 4.1).
849 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
850 for (intptr_t i = 0; i < value_check.NumberOfChecks(); i++) {
851 intptr_t cid = value_check.GetReceiverClassIdAt(i);
852 if (FlowGraphCompiler::SupportsUnboxedMints()) {
853 if ((cid != kSmiCid) && (cid != kMintCid)) {
854 return false;
855 }
856 } else if (cid != kSmiCid) {
857 return false;
858 }
859 }
860 break;
861 }
862 case kTypedDataFloat32ArrayCid:
863 case kTypedDataFloat64ArrayCid: {
864 // Check that value is always double.
865 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
866 if ((value_check.NumberOfChecks() != 1) ||
867 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) {
868 return false;
869 }
870 break;
871 }
872 case kTypedDataFloat32x4ArrayCid: {
873 if (!ShouldInlineSimd()) {
874 return false;
875 }
876 // Check that value is always a Float32x4.
877 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2);
878 if ((value_check.NumberOfChecks() != 1) ||
879 (value_check.GetReceiverClassIdAt(0) != kFloat32x4Cid)) {
880 return false;
881 }
882 }
883 break;
884 default:
885 // TODO(fschneider): Add support for other array types.
886 return false;
887 } 838 }
888 839 // Insert receiver class check.
889 BuildStoreIndexed(call, value_check, class_id); 840 AddReceiverCheck(call);
841 // Remove the original push arguments.
842 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
843 PushArgumentInstr* push = call->PushArgumentAt(i);
844 push->ReplaceUsesWith(push->value()->definition());
845 push->RemoveFromGraph();
846 }
847 // Replace all uses of this definition with the result.
848 call->ReplaceUsesWith(last);
849 // Finally insert the sequence other definition in place of this one in the
850 // graph.
851 call->previous()->LinkTo(entry->next());
852 entry->UnuseAllInputs(); // Entry block is not in the graph.
853 last->LinkTo(call);
854 // Remove through the iterator.
855 ASSERT(current_iterator()->Current() == call);
856 current_iterator()->RemoveCurrentFromGraph();
857 call->set_previous(NULL);
858 call->set_next(NULL);
890 return true; 859 return true;
891 } 860 }
892 861
893 862
894 void FlowGraphOptimizer::BuildStoreIndexed(InstanceCallInstr* call, 863 bool FlowGraphOptimizer::BuildInlineSetIndexed(
895 const ICData& value_check, 864 MethodRecognizer::Kind kind,
896 intptr_t class_id) { 865 const Function& target,
866 Instruction* call,
867 intptr_t token_pos,
868 const ICData* ic_data,
869 const ICData& value_check,
870 TargetEntryInstr** entry,
871 Definition** last) {
872 intptr_t array_cid = MethodKindToCid(kind);
873 ASSERT(array_cid != kIllegalCid);
874
897 Definition* array = call->ArgumentAt(0); 875 Definition* array = call->ArgumentAt(0);
898 Definition* index = call->ArgumentAt(1); 876 Definition* index = call->ArgumentAt(1);
899 Definition* stored_value = call->ArgumentAt(2); 877 Definition* stored_value = call->ArgumentAt(2);
878
879 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(),
880 call->GetBlock()->try_index());
881 (*entry)->InheritDeoptTarget(call);
882 Instruction* cursor = *entry;
900 if (FLAG_enable_type_checks) { 883 if (FLAG_enable_type_checks) {
901 // Only type check for the value. A type check for the index is not 884 // Only type check for the value. A type check for the index is not
902 // needed here because we insert a deoptimizing smi-check for the case 885 // needed here because we insert a deoptimizing smi-check for the case
903 // the index is not a smi. 886 // the index is not a smi.
904 const Function& target =
905 Function::ZoneHandle(call->ic_data()->GetTargetAt(0));
906 const AbstractType& value_type = 887 const AbstractType& value_type =
907 AbstractType::ZoneHandle(target.ParameterTypeAt(2)); 888 AbstractType::ZoneHandle(target.ParameterTypeAt(2));
908 Definition* instantiator = NULL; 889 Definition* instantiator = NULL;
909 Definition* type_args = NULL; 890 Definition* type_args = NULL;
910 switch (class_id) { 891 switch (array_cid) {
911 case kArrayCid: 892 case kArrayCid:
912 case kGrowableObjectArrayCid: { 893 case kGrowableObjectArrayCid: {
913 const Class& instantiator_class = Class::Handle(target.Owner()); 894 const Class& instantiator_class = Class::Handle(target.Owner());
914 intptr_t type_arguments_field_offset = 895 intptr_t type_arguments_field_offset =
915 instantiator_class.type_arguments_field_offset(); 896 instantiator_class.type_arguments_field_offset();
916 LoadFieldInstr* load_type_args = 897 LoadFieldInstr* load_type_args =
917 new LoadFieldInstr(new Value(array), 898 new LoadFieldInstr(new Value(array),
918 type_arguments_field_offset, 899 type_arguments_field_offset,
919 Type::ZoneHandle()); // No type. 900 Type::ZoneHandle()); // No type.
920 InsertBefore(call, load_type_args, NULL, Definition::kValue); 901 cursor = flow_graph()->AppendTo(cursor,
902 load_type_args,
903 NULL,
904 Definition::kValue);
905
921 instantiator = array; 906 instantiator = array;
922 type_args = load_type_args; 907 type_args = load_type_args;
923 break; 908 break;
924 } 909 }
925 case kTypedDataInt8ArrayCid: 910 case kTypedDataInt8ArrayCid:
926 case kTypedDataUint8ArrayCid: 911 case kTypedDataUint8ArrayCid:
927 case kTypedDataUint8ClampedArrayCid: 912 case kTypedDataUint8ClampedArrayCid:
928 case kExternalTypedDataUint8ArrayCid: 913 case kExternalTypedDataUint8ArrayCid:
929 case kExternalTypedDataUint8ClampedArrayCid: 914 case kExternalTypedDataUint8ClampedArrayCid:
930 case kTypedDataInt16ArrayCid: 915 case kTypedDataInt16ArrayCid:
931 case kTypedDataUint16ArrayCid: 916 case kTypedDataUint16ArrayCid:
932 case kTypedDataInt32ArrayCid: 917 case kTypedDataInt32ArrayCid:
933 case kTypedDataUint32ArrayCid: 918 case kTypedDataUint32ArrayCid:
934 ASSERT(value_type.IsIntType()); 919 ASSERT(value_type.IsIntType());
935 // Fall through. 920 // Fall through.
936 case kTypedDataFloat32ArrayCid: 921 case kTypedDataFloat32ArrayCid:
937 case kTypedDataFloat64ArrayCid: { 922 case kTypedDataFloat64ArrayCid: {
938 type_args = instantiator = flow_graph_->constant_null(); 923 type_args = instantiator = flow_graph_->constant_null();
939 ASSERT((class_id != kTypedDataFloat32ArrayCid && 924 ASSERT((array_cid != kTypedDataFloat32ArrayCid &&
940 class_id != kTypedDataFloat64ArrayCid) || 925 array_cid != kTypedDataFloat64ArrayCid) ||
941 value_type.IsDoubleType()); 926 value_type.IsDoubleType());
942 ASSERT(value_type.IsInstantiated()); 927 ASSERT(value_type.IsInstantiated());
943 break; 928 break;
944 } 929 }
945 case kTypedDataFloat32x4ArrayCid: { 930 case kTypedDataFloat32x4ArrayCid: {
946 type_args = instantiator = flow_graph_->constant_null(); 931 type_args = instantiator = flow_graph_->constant_null();
947 ASSERT((class_id != kTypedDataFloat32x4ArrayCid) || 932 ASSERT((array_cid != kTypedDataFloat32x4ArrayCid) ||
948 value_type.IsFloat32x4Type()); 933 value_type.IsFloat32x4Type());
949 ASSERT(value_type.IsInstantiated()); 934 ASSERT(value_type.IsInstantiated());
950 break; 935 break;
951 } 936 }
952 default: 937 default:
953 // TODO(fschneider): Add support for other array types. 938 // TODO(fschneider): Add support for other array types.
954 UNREACHABLE(); 939 UNREACHABLE();
955 } 940 }
956 AssertAssignableInstr* assert_value = 941 AssertAssignableInstr* assert_value =
957 new AssertAssignableInstr(call->token_pos(), 942 new AssertAssignableInstr(token_pos,
958 new Value(stored_value), 943 new Value(stored_value),
959 new Value(instantiator), 944 new Value(instantiator),
960 new Value(type_args), 945 new Value(type_args),
961 value_type, 946 value_type,
962 Symbols::Value()); 947 Symbols::Value());
963 // Newly inserted instructions that can deoptimize or throw an exception 948 // Newly inserted instructions that can deoptimize or throw an exception
964 // must have a deoptimization id that is valid for lookup in the unoptimized 949 // must have a deoptimization id that is valid for lookup in the unoptimized
965 // code. 950 // code.
966 assert_value->deopt_id_ = call->deopt_id(); 951 assert_value->deopt_id_ = call->deopt_id();
967 InsertBefore(call, assert_value, call->env(), Definition::kValue); 952 cursor = flow_graph()->AppendTo(cursor,
953 assert_value,
954 call->env(),
955 Definition::kValue);
968 } 956 }
969 957
970 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); 958 array_cid = PrepareInlineIndexedOp(call,
959 array_cid,
960 &array,
961 index,
962 &cursor);
963
971 // Check if store barrier is needed. Byte arrays don't need a store barrier. 964 // Check if store barrier is needed. Byte arrays don't need a store barrier.
972 StoreBarrierType needs_store_barrier = 965 StoreBarrierType needs_store_barrier =
973 (RawObject::IsTypedDataClassId(array_cid) || 966 (RawObject::IsTypedDataClassId(array_cid) ||
974 RawObject::IsTypedDataViewClassId(array_cid) || 967 RawObject::IsTypedDataViewClassId(array_cid) ||
975 RawObject::IsExternalTypedDataClassId(array_cid)) ? kNoStoreBarrier 968 RawObject::IsExternalTypedDataClassId(array_cid)) ? kNoStoreBarrier
976 : kEmitStoreBarrier; 969 : kEmitStoreBarrier;
977 if (!value_check.IsNull()) { 970 if (!value_check.IsNull()) {
978 // No store barrier needed because checked value is a smi, an unboxed mint, 971 // No store barrier needed because checked value is a smi, an unboxed mint,
979 // an unboxed double, an unboxed Float32x4, or unboxed Uint32x4. 972 // an unboxed double, an unboxed Float32x4, or unboxed Uint32x4.
980 needs_store_barrier = kNoStoreBarrier; 973 needs_store_barrier = kNoStoreBarrier;
981 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), 974 Instruction* check =
982 call); 975 GetCheckClass(stored_value, value_check, call->deopt_id());
976 cursor = flow_graph()->AppendTo(cursor,
977 check,
978 call->env(),
979 Definition::kEffect);
983 } 980 }
984 981
985 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); 982 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid);
986 Definition* array_op = new StoreIndexedInstr(new Value(array), 983 *last = new StoreIndexedInstr(new Value(array),
987 new Value(index), 984 new Value(index),
988 new Value(stored_value), 985 new Value(stored_value),
989 needs_store_barrier, 986 needs_store_barrier,
990 index_scale, 987 index_scale,
991 array_cid, 988 array_cid,
992 call->deopt_id()); 989 call->deopt_id());
993 ReplaceCall(call, array_op); 990 flow_graph()->AppendTo(cursor,
994 } 991 *last,
995 992 NULL,
996 993 Definition::kEffect);
997 static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) { 994 return true;
998 switch (kind) {
999 case MethodRecognizer::kImmutableArrayGetIndexed:
1000 return kImmutableArrayCid;
1001
1002 case MethodRecognizer::kObjectArrayGetIndexed:
1003 return kArrayCid;
1004
1005 case MethodRecognizer::kGrowableArrayGetIndexed:
1006 return kGrowableObjectArrayCid;
1007
1008 case MethodRecognizer::kFloat32ArrayGetIndexed:
1009 return kTypedDataFloat32ArrayCid;
1010
1011 case MethodRecognizer::kFloat64ArrayGetIndexed:
1012 return kTypedDataFloat64ArrayCid;
1013
1014 case MethodRecognizer::kInt8ArrayGetIndexed:
1015 return kTypedDataInt8ArrayCid;
1016
1017 case MethodRecognizer::kUint8ArrayGetIndexed:
1018 return kTypedDataUint8ArrayCid;
1019
1020 case MethodRecognizer::kUint8ClampedArrayGetIndexed:
1021 return kTypedDataUint8ClampedArrayCid;
1022
1023 case MethodRecognizer::kExternalUint8ArrayGetIndexed:
1024 return kExternalTypedDataUint8ArrayCid;
1025
1026 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
1027 return kExternalTypedDataUint8ClampedArrayCid;
1028
1029 case MethodRecognizer::kInt16ArrayGetIndexed:
1030 return kTypedDataInt16ArrayCid;
1031
1032 case MethodRecognizer::kUint16ArrayGetIndexed:
1033 return kTypedDataUint16ArrayCid;
1034
1035 case MethodRecognizer::kInt32ArrayGetIndexed:
1036 return kTypedDataInt32ArrayCid;
1037
1038 case MethodRecognizer::kUint32ArrayGetIndexed:
1039 return kTypedDataUint32ArrayCid;
1040
1041 case MethodRecognizer::kFloat32x4ArrayGetIndexed:
1042 return kTypedDataFloat32x4ArrayCid;
1043
1044 default:
1045 break;
1046 }
1047 return kIllegalCid;
1048 } 995 }
1049 996
1050 997
1051 bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target, 998 bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target,
1052 Instruction* call, 999 Instruction* call,
1000 intptr_t token_pos,
1053 const ICData& ic_data, 1001 const ICData& ic_data,
1054 TargetEntryInstr** entry, 1002 TargetEntryInstr** entry,
1055 Definition** last) { 1003 Definition** last) {
1004 ICData& value_check = ICData::ZoneHandle();
1056 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); 1005 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target);
1057 switch (kind) { 1006 switch (kind) {
1007 // Recognized [] operators.
1058 case MethodRecognizer::kImmutableArrayGetIndexed: 1008 case MethodRecognizer::kImmutableArrayGetIndexed:
1059 case MethodRecognizer::kObjectArrayGetIndexed: 1009 case MethodRecognizer::kObjectArrayGetIndexed:
1060 case MethodRecognizer::kGrowableArrayGetIndexed: 1010 case MethodRecognizer::kGrowableArrayGetIndexed:
1061 case MethodRecognizer::kFloat32ArrayGetIndexed: 1011 case MethodRecognizer::kFloat32ArrayGetIndexed:
1062 case MethodRecognizer::kFloat64ArrayGetIndexed: 1012 case MethodRecognizer::kFloat64ArrayGetIndexed:
1063 case MethodRecognizer::kInt8ArrayGetIndexed: 1013 case MethodRecognizer::kInt8ArrayGetIndexed:
1064 case MethodRecognizer::kUint8ArrayGetIndexed: 1014 case MethodRecognizer::kUint8ArrayGetIndexed:
1065 case MethodRecognizer::kUint8ClampedArrayGetIndexed: 1015 case MethodRecognizer::kUint8ClampedArrayGetIndexed:
1066 case MethodRecognizer::kExternalUint8ArrayGetIndexed: 1016 case MethodRecognizer::kExternalUint8ArrayGetIndexed:
1067 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed: 1017 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
1068 case MethodRecognizer::kInt16ArrayGetIndexed: 1018 case MethodRecognizer::kInt16ArrayGetIndexed:
1069 case MethodRecognizer::kUint16ArrayGetIndexed: 1019 case MethodRecognizer::kUint16ArrayGetIndexed:
1070 return TryInlineGetIndexed(kind, call, ic_data, entry, last); 1020 return BuildInlineGetIndexed(kind, call, ic_data, entry, last);
1071 case MethodRecognizer::kFloat32x4ArrayGetIndexed: 1021 case MethodRecognizer::kFloat32x4ArrayGetIndexed:
1072 if (!ShouldInlineSimd()) return false; 1022 if (!ShouldInlineSimd()) return false;
1073 return TryInlineGetIndexed(kind, call, ic_data, entry, last); 1023 return BuildInlineGetIndexed(kind, call, ic_data, entry, last);
1074 case MethodRecognizer::kInt32ArrayGetIndexed: 1024 case MethodRecognizer::kInt32ArrayGetIndexed:
1075 case MethodRecognizer::kUint32ArrayGetIndexed: 1025 case MethodRecognizer::kUint32ArrayGetIndexed:
1076 if (!CanUnboxInt32()) return false; 1026 if (!CanUnboxInt32()) return false;
1077 return TryInlineGetIndexed(kind, call, ic_data, entry, last); 1027 return BuildInlineGetIndexed(kind, call, ic_data, entry, last);
1028
1029 // Recognized []= operators.
1030 case MethodRecognizer::kObjectArraySetIndexed:
1031 case MethodRecognizer::kGrowableArraySetIndexed:
1032 if (ArgIsAlways(kSmiCid, ic_data, 2)) {
1033 value_check = ic_data.AsUnaryClassChecksForArgNr(2);
1034 }
1035 return BuildInlineSetIndexed(kind, target, call, token_pos,
1036 &ic_data, value_check, entry, last);
1037 case MethodRecognizer::kInt8ArraySetIndexed:
1038 case MethodRecognizer::kUint8ArraySetIndexed:
1039 case MethodRecognizer::kUint8ClampedArraySetIndexed:
1040 case MethodRecognizer::kExternalUint8ArraySetIndexed:
1041 case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
1042 case MethodRecognizer::kInt16ArraySetIndexed:
1043 case MethodRecognizer::kUint16ArraySetIndexed:
1044 if (!ArgIsAlways(kSmiCid, ic_data, 2)) return false;
1045 value_check = ic_data.AsUnaryClassChecksForArgNr(2);
1046 return BuildInlineSetIndexed(kind, target, call, token_pos,
1047 &ic_data, value_check, entry, last);
1048 case MethodRecognizer::kInt32ArraySetIndexed:
1049 case MethodRecognizer::kUint32ArraySetIndexed:
1050 if (!CanUnboxInt32()) return false;
1051 // Check that value is always smi or mint, if the platform has unboxed
1052 // mints (ia32 with at least SSE 4.1).
1053 value_check = ic_data.AsUnaryClassChecksForArgNr(2);
1054 if (FlowGraphCompiler::SupportsUnboxedMints()) {
1055 if (!HasOnlySmiOrMint(value_check)) {
1056 return false;
1057 }
1058 } else if (!HasOnlyOneSmi(value_check)) {
1059 return false;
1060 }
1061 return BuildInlineSetIndexed(kind, target, call, token_pos,
1062 &ic_data, value_check, entry, last);
1063 case MethodRecognizer::kFloat32ArraySetIndexed:
1064 case MethodRecognizer::kFloat64ArraySetIndexed:
1065 // Check that value is always double.
1066 if (!ArgIsAlways(kDoubleCid, ic_data, 2)) return false;
1067 value_check = ic_data.AsUnaryClassChecksForArgNr(2);
1068 return BuildInlineSetIndexed(kind, target, call, token_pos,
1069 &ic_data, value_check, entry, last);
1070 case MethodRecognizer::kFloat32x4ArraySetIndexed:
1071 if (!ShouldInlineSimd()) return false;
1072 // Check that value is always a Float32x4.
1073 if (!ArgIsAlways(kFloat32x4Cid, ic_data, 2)) return false;
1074 value_check = ic_data.AsUnaryClassChecksForArgNr(2);
1075 return BuildInlineSetIndexed(kind, target, call, token_pos,
1076 &ic_data, value_check, entry, last);
1078 default: 1077 default:
1079 return false; 1078 return false;
1080 } 1079 }
1081 } 1080 }
1082 1081
1083 1082
1084 bool FlowGraphOptimizer::TryInlineGetIndexed(MethodRecognizer::Kind kind, 1083 intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call,
1085 Instruction* call, 1084 intptr_t array_cid,
1086 const ICData& ic_data, 1085 Definition** array,
1087 TargetEntryInstr** entry, 1086 Definition* index,
1088 Definition** last) { 1087 Instruction** cursor) {
1089 intptr_t array_cid = MethodKindToCid(kind); 1088 // Insert index smi check.
1090 ASSERT(array_cid != kIllegalCid); 1089 *cursor = flow_graph()->AppendTo(*cursor,
1091 1090 new CheckSmiInstr(new Value(index),
1092 // Insert index smi checks and attach a copy of the 1091 call->deopt_id()),
1093 // original environment because the operation can still deoptimize. 1092 call->env(),
1094 Definition* array = call->ArgumentAt(0); 1093 Definition::kEffect);
1095 Definition* index = call->ArgumentAt(1);
1096 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(),
1097 call->GetBlock()->try_index());
1098 (*entry)->InheritDeoptTarget(call);
1099
1100 Instruction* cursor = *entry;
1101 cursor = flow_graph()->AppendTo(cursor,
1102 new CheckSmiInstr(new Value(index),
1103 call->deopt_id()),
1104 call->env(),
1105 Definition::kEffect);
1106 1094
1107 // Insert array length load and bounds check. 1095 // Insert array length load and bounds check.
1108 const bool is_immutable = 1096 const bool is_immutable =
1109 CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid); 1097 CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid);
1110 LoadFieldInstr* length = 1098 LoadFieldInstr* length =
1111 new LoadFieldInstr(new Value(array), 1099 new LoadFieldInstr(new Value(*array),
1112 CheckArrayBoundInstr::LengthOffsetFor(array_cid), 1100 CheckArrayBoundInstr::LengthOffsetFor(array_cid),
1113 Type::ZoneHandle(Type::SmiType()), 1101 Type::ZoneHandle(Type::SmiType()),
1114 is_immutable); 1102 is_immutable);
1115 length->set_result_cid(kSmiCid); 1103 length->set_result_cid(kSmiCid);
1116 length->set_recognized_kind( 1104 length->set_recognized_kind(
1117 LoadFieldInstr::RecognizedKindFromArrayCid(array_cid)); 1105 LoadFieldInstr::RecognizedKindFromArrayCid(array_cid));
1118 cursor = flow_graph()->AppendTo(cursor, 1106 *cursor = flow_graph()->AppendTo(*cursor,
1119 length, 1107 length,
1120 NULL, 1108 NULL,
1121 Definition::kValue); 1109 Definition::kValue);
1122 1110
1123 cursor = flow_graph()->AppendTo(cursor, 1111 *cursor = flow_graph()->AppendTo(*cursor,
1124 new CheckArrayBoundInstr( 1112 new CheckArrayBoundInstr(
1125 new Value(length), 1113 new Value(length),
1126 new Value(index), 1114 new Value(index),
1127 call->deopt_id()), 1115 call->deopt_id()),
1128 call->env(), 1116 call->env(),
1129 Definition::kEffect); 1117 Definition::kEffect);
1130 1118
1131 if (array_cid == kGrowableObjectArrayCid) { 1119 if (array_cid == kGrowableObjectArrayCid) {
1132 // Insert data elements load. 1120 // Insert data elements load.
1133 LoadFieldInstr* elements = 1121 LoadFieldInstr* elements =
1134 new LoadFieldInstr(new Value(array), 1122 new LoadFieldInstr(new Value(*array),
1135 GrowableObjectArray::data_offset(), 1123 GrowableObjectArray::data_offset(),
1136 Type::ZoneHandle(Type::DynamicType())); 1124 Type::ZoneHandle(Type::DynamicType()));
1137 elements->set_result_cid(kArrayCid); 1125 elements->set_result_cid(kArrayCid);
1138 cursor = flow_graph()->AppendTo(cursor, 1126 *cursor = flow_graph()->AppendTo(*cursor,
1139 elements, 1127 elements,
1140 NULL, 1128 NULL,
1141 Definition::kValue); 1129 Definition::kValue);
1142 // Load from the data from backing store which is a fixed-length array. 1130 // Load from the data from backing store which is a fixed-length array.
1143 array = elements; 1131 *array = elements;
1144 array_cid = kArrayCid; 1132 array_cid = kArrayCid;
1145 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { 1133 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) {
1146 LoadUntaggedInstr* elements = 1134 LoadUntaggedInstr* elements =
1147 new LoadUntaggedInstr(new Value(array), 1135 new LoadUntaggedInstr(new Value(*array),
1148 ExternalTypedData::data_offset()); 1136 ExternalTypedData::data_offset());
1149 cursor = flow_graph()->AppendTo(cursor, 1137 *cursor = flow_graph()->AppendTo(*cursor,
1150 elements, 1138 elements,
1151 NULL, 1139 NULL,
1152 Definition::kValue); 1140 Definition::kValue);
1153 array = elements; 1141 *array = elements;
1154 } 1142 }
1143 return array_cid;
1144 }
1145
1146 bool FlowGraphOptimizer::BuildInlineGetIndexed(MethodRecognizer::Kind kind,
1147 Instruction* call,
1148 const ICData& ic_data,
1149 TargetEntryInstr** entry,
1150 Definition** last) {
1151 intptr_t array_cid = MethodKindToCid(kind);
1152 ASSERT(array_cid != kIllegalCid);
1153
1154 Definition* array = call->ArgumentAt(0);
1155 Definition* index = call->ArgumentAt(1);
1156 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(),
1157 call->GetBlock()->try_index());
1158 (*entry)->InheritDeoptTarget(call);
1159 Instruction* cursor = *entry;
1160
1161 array_cid = PrepareInlineIndexedOp(call,
1162 array_cid,
1163 &array,
1164 index,
1165 &cursor);
1155 1166
1156 intptr_t deopt_id = Isolate::kNoDeoptId; 1167 intptr_t deopt_id = Isolate::kNoDeoptId;
1157 if ((array_cid == kTypedDataInt32ArrayCid) || 1168 if ((array_cid == kTypedDataInt32ArrayCid) ||
1158 (array_cid == kTypedDataUint32ArrayCid)) { 1169 (array_cid == kTypedDataUint32ArrayCid)) {
1159 // Set deopt_id if we can optimistically assume that the result is Smi. 1170 // Set deopt_id if we can optimistically assume that the result is Smi.
1160 // Assume mixed Mint/Smi if this instruction caused deoptimization once. 1171 // Assume mixed Mint/Smi if this instruction caused deoptimization once.
1161 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? 1172 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ?
1162 call->deopt_id() : Isolate::kNoDeoptId; 1173 call->deopt_id() : Isolate::kNoDeoptId;
1163 } 1174 }
1164 1175
(...skipping 17 matching lines...) Expand all
1182 if (!call->HasICData()) return false; 1193 if (!call->HasICData()) return false;
1183 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks()); 1194 const ICData& ic_data = ICData::Handle(call->ic_data()->AsUnaryClassChecks());
1184 if (ic_data.NumberOfChecks() != 1) return false; 1195 if (ic_data.NumberOfChecks() != 1) return false;
1185 ASSERT(ic_data.HasOneTarget()); 1196 ASSERT(ic_data.HasOneTarget());
1186 1197
1187 const Function& target = Function::Handle(ic_data.GetTargetAt(0)); 1198 const Function& target = Function::Handle(ic_data.GetTargetAt(0));
1188 TargetEntryInstr* entry; 1199 TargetEntryInstr* entry;
1189 Definition* last; 1200 Definition* last;
1190 if (!TryInlineRecognizedMethod(target, 1201 if (!TryInlineRecognizedMethod(target,
1191 call, 1202 call,
1203 call->token_pos(),
1192 *call->ic_data(), 1204 *call->ic_data(),
1193 &entry, &last)) { 1205 &entry, &last)) {
1194 return false; 1206 return false;
1195 } 1207 }
1196 1208
1197 // Insert receiver class check. 1209 // Insert receiver class check.
1198 AddReceiverCheck(call); 1210 AddReceiverCheck(call);
1199 // Remove the original push arguments. 1211 // Remove the original push arguments.
1200 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 1212 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
1201 PushArgumentInstr* push = call->PushArgumentAt(i); 1213 PushArgumentInstr* push = call->PushArgumentAt(i);
(...skipping 1754 matching lines...) Expand 10 before | Expand all | Expand 10 after
2956 // Inline implicit instance setter. 2968 // Inline implicit instance setter.
2957 const String& field_name = 2969 const String& field_name =
2958 String::Handle(Field::NameFromSetter(instr->function_name())); 2970 String::Handle(Field::NameFromSetter(instr->function_name()));
2959 const Field& field = Field::Handle(GetField(class_id, field_name)); 2971 const Field& field = Field::Handle(GetField(class_id, field_name));
2960 ASSERT(!field.IsNull()); 2972 ASSERT(!field.IsNull());
2961 2973
2962 if (InstanceCallNeedsClassCheck(instr)) { 2974 if (InstanceCallNeedsClassCheck(instr)) {
2963 AddReceiverCheck(instr); 2975 AddReceiverCheck(instr);
2964 } 2976 }
2965 StoreBarrierType needs_store_barrier = kEmitStoreBarrier; 2977 StoreBarrierType needs_store_barrier = kEmitStoreBarrier;
2966 if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) { 2978 if (ArgIsAlways(kSmiCid, *instr->ic_data(), 1)) {
2967 InsertBefore(instr, 2979 InsertBefore(instr,
2968 new CheckSmiInstr(new Value(instr->ArgumentAt(1)), 2980 new CheckSmiInstr(new Value(instr->ArgumentAt(1)),
2969 instr->deopt_id()), 2981 instr->deopt_id()),
2970 instr->env(), 2982 instr->env(),
2971 Definition::kEffect); 2983 Definition::kEffect);
2972 needs_store_barrier = kNoStoreBarrier; 2984 needs_store_barrier = kNoStoreBarrier;
2973 } 2985 }
2974 2986
2975 if (field.guarded_cid() != kDynamicCid) { 2987 if (field.guarded_cid() != kDynamicCid) {
2976 InsertBefore(instr, 2988 InsertBefore(instr,
(...skipping 4676 matching lines...) Expand 10 before | Expand all | Expand 10 after
7653 } 7665 }
7654 7666
7655 // Insert materializations at environment uses. 7667 // Insert materializations at environment uses.
7656 for (intptr_t i = 0; i < exits.length(); i++) { 7668 for (intptr_t i = 0; i < exits.length(); i++) {
7657 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); 7669 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields);
7658 } 7670 }
7659 } 7671 }
7660 7672
7661 7673
7662 } // namespace dart 7674 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698