| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |