| 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/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 | 368 |
| 369 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { | 369 void FlowGraphOptimizer::InsertConversionsFor(Definition* def) { |
| 370 const Representation from_rep = def->representation(); | 370 const Representation from_rep = def->representation(); |
| 371 | 371 |
| 372 for (Value::Iterator it(def->input_use_list()); | 372 for (Value::Iterator it(def->input_use_list()); |
| 373 !it.Done(); | 373 !it.Done(); |
| 374 it.Advance()) { | 374 it.Advance()) { |
| 375 Value* use = it.Current(); | 375 Value* use = it.Current(); |
| 376 const Representation to_rep = | 376 const Representation to_rep = |
| 377 use->instruction()->RequiredInputRepresentation(use->use_index()); | 377 use->instruction()->RequiredInputRepresentation(use->use_index()); |
| 378 if (from_rep == to_rep) { | 378 if (from_rep == to_rep || to_rep == kNoRepresentation) { |
| 379 continue; | 379 continue; |
| 380 } | 380 } |
| 381 | 381 |
| 382 Instruction* insert_before; | 382 Instruction* insert_before; |
| 383 Instruction* deopt_target; | 383 Instruction* deopt_target; |
| 384 PhiInstr* phi = use->instruction()->AsPhi(); | 384 PhiInstr* phi = use->instruction()->AsPhi(); |
| 385 if (phi != NULL) { | 385 if (phi != NULL) { |
| 386 ASSERT(phi->is_alive()); | 386 ASSERT(phi->is_alive()); |
| 387 // For phis conversions have to be inserted in the predecessor. | 387 // For phis conversions have to be inserted in the predecessor. |
| 388 insert_before = | 388 insert_before = |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 // Insert data elements load. | 681 // Insert data elements load. |
| 682 LoadFieldInstr* elements = | 682 LoadFieldInstr* elements = |
| 683 new LoadFieldInstr(new Value(*array), | 683 new LoadFieldInstr(new Value(*array), |
| 684 GrowableObjectArray::data_offset(), | 684 GrowableObjectArray::data_offset(), |
| 685 Type::ZoneHandle(Type::DynamicType())); | 685 Type::ZoneHandle(Type::DynamicType())); |
| 686 elements->set_result_cid(kArrayCid); | 686 elements->set_result_cid(kArrayCid); |
| 687 InsertBefore(call, elements, NULL, Definition::kValue); | 687 InsertBefore(call, elements, NULL, Definition::kValue); |
| 688 *array = elements; | 688 *array = elements; |
| 689 return kArrayCid; | 689 return kArrayCid; |
| 690 } | 690 } |
| 691 if (RawObject::IsExternalTypedDataClassId(class_id)) { |
| 692 LoadUntaggedInstr* elements = |
| 693 new LoadUntaggedInstr(new Value(*array), |
| 694 ExternalTypedData::data_offset()); |
| 695 InsertBefore(call, elements, NULL, Definition::kValue); |
| 696 *array = elements; |
| 697 } |
| 691 return class_id; | 698 return class_id; |
| 692 } | 699 } |
| 693 | 700 |
| 694 | 701 |
| 695 static bool CanUnboxInt32() { | 702 static bool CanUnboxInt32() { |
| 696 // Int32/Uint32 can be unboxed if it fits into a smi or the platform | 703 // Int32/Uint32 can be unboxed if it fits into a smi or the platform |
| 697 // supports unboxed mints. | 704 // supports unboxed mints. |
| 698 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints(); | 705 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints(); |
| 699 } | 706 } |
| 700 | 707 |
| 701 | 708 |
| 702 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { | 709 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
| 703 const intptr_t class_id = ReceiverClassId(call); | 710 const intptr_t class_id = ReceiverClassId(call); |
| 704 ICData& value_check = ICData::ZoneHandle(); | 711 ICData& value_check = ICData::ZoneHandle(); |
| 705 switch (class_id) { | 712 switch (class_id) { |
| 706 case kArrayCid: | 713 case kArrayCid: |
| 707 case kGrowableObjectArrayCid: | 714 case kGrowableObjectArrayCid: |
| 708 if (ArgIsAlwaysSmi(*call->ic_data(), 2)) { | 715 if (ArgIsAlwaysSmi(*call->ic_data(), 2)) { |
| 709 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 716 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 710 } | 717 } |
| 711 break; | 718 break; |
| 712 case kInt8ArrayCid: | |
| 713 case kUint8ArrayCid: | |
| 714 case kUint8ClampedArrayCid: | |
| 715 case kExternalUint8ArrayCid: | |
| 716 case kExternalUint8ClampedArrayCid: | |
| 717 case kInt16ArrayCid: | |
| 718 case kUint16ArrayCid: | |
| 719 case kTypedDataInt8ArrayCid: | 719 case kTypedDataInt8ArrayCid: |
| 720 case kTypedDataUint8ArrayCid: | 720 case kTypedDataUint8ArrayCid: |
| 721 case kTypedDataUint8ClampedArrayCid: | 721 case kTypedDataUint8ClampedArrayCid: |
| 722 case kExternalTypedDataUint8ArrayCid: | 722 case kExternalTypedDataUint8ArrayCid: |
| 723 case kExternalTypedDataUint8ClampedArrayCid: | 723 case kExternalTypedDataUint8ClampedArrayCid: |
| 724 case kTypedDataInt16ArrayCid: | 724 case kTypedDataInt16ArrayCid: |
| 725 case kTypedDataUint16ArrayCid: | 725 case kTypedDataUint16ArrayCid: |
| 726 // Check that value is always smi. | 726 // Check that value is always smi. |
| 727 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 727 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 728 if ((value_check.NumberOfChecks() != 1) || | 728 if ((value_check.NumberOfChecks() != 1) || |
| 729 (value_check.GetReceiverClassIdAt(0) != kSmiCid)) { | 729 (value_check.GetReceiverClassIdAt(0) != kSmiCid)) { |
| 730 return false; | 730 return false; |
| 731 } | 731 } |
| 732 break; | 732 break; |
| 733 case kInt32ArrayCid: | |
| 734 case kUint32ArrayCid: | |
| 735 case kTypedDataInt32ArrayCid: | 733 case kTypedDataInt32ArrayCid: |
| 736 case kTypedDataUint32ArrayCid: { | 734 case kTypedDataUint32ArrayCid: { |
| 737 if (!CanUnboxInt32()) return false; | 735 if (!CanUnboxInt32()) return false; |
| 738 // Check that value is always smi or mint, if the platform has unboxed | 736 // Check that value is always smi or mint, if the platform has unboxed |
| 739 // mints (ia32 with at least SSE 4.1). | 737 // mints (ia32 with at least SSE 4.1). |
| 740 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 738 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 741 for (intptr_t i = 0; i < value_check.NumberOfChecks(); i++) { | 739 for (intptr_t i = 0; i < value_check.NumberOfChecks(); i++) { |
| 742 intptr_t cid = value_check.GetReceiverClassIdAt(i); | 740 intptr_t cid = value_check.GetReceiverClassIdAt(i); |
| 743 if (FlowGraphCompiler::SupportsUnboxedMints()) { | 741 if (FlowGraphCompiler::SupportsUnboxedMints()) { |
| 744 if ((cid != kSmiCid) && (cid != kMintCid)) { | 742 if ((cid != kSmiCid) && (cid != kMintCid)) { |
| 745 return false; | 743 return false; |
| 746 } | 744 } |
| 747 } else if (cid != kSmiCid) { | 745 } else if (cid != kSmiCid) { |
| 748 return false; | 746 return false; |
| 749 } | 747 } |
| 750 } | 748 } |
| 751 break; | 749 break; |
| 752 } | 750 } |
| 753 case kFloat32ArrayCid: | |
| 754 case kFloat64ArrayCid: | |
| 755 case kTypedDataFloat32ArrayCid: | 751 case kTypedDataFloat32ArrayCid: |
| 756 case kTypedDataFloat64ArrayCid: { | 752 case kTypedDataFloat64ArrayCid: { |
| 757 // Check that value is always double. | 753 // Check that value is always double. |
| 758 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 754 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 759 if ((value_check.NumberOfChecks() != 1) || | 755 if ((value_check.NumberOfChecks() != 1) || |
| 760 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { | 756 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { |
| 761 return false; | 757 return false; |
| 762 } | 758 } |
| 763 break; | 759 break; |
| 764 } | 760 } |
| 765 default: | 761 default: |
| 766 // TODO(fschneider): Add support for other array types. | 762 // TODO(fschneider): Add support for other array types. |
| 767 return false; | 763 return false; |
| 768 } | 764 } |
| 769 | 765 |
| 770 BuildStoreIndexed(call, value_check, class_id); | 766 BuildStoreIndexed(call, value_check, class_id); |
| 771 return true; | 767 return true; |
| 772 } | 768 } |
| 773 | 769 |
| 774 | 770 |
| 775 bool FlowGraphOptimizer::TryInlineByteArraySetIndexed(InstanceCallInstr* call) { | |
| 776 const intptr_t class_id = ReceiverClassId(call); | |
| 777 ICData& value_check = ICData::ZoneHandle(); | |
| 778 switch (class_id) { | |
| 779 case kInt8ArrayCid: | |
| 780 case kUint8ArrayCid: | |
| 781 case kUint8ClampedArrayCid: | |
| 782 case kExternalUint8ArrayCid: | |
| 783 case kExternalUint8ClampedArrayCid: | |
| 784 case kInt16ArrayCid: | |
| 785 case kUint16ArrayCid: { | |
| 786 // Check that value is always smi. | |
| 787 value_check = ICData::New(Function::Handle(), | |
| 788 String::Handle(), | |
| 789 Isolate::kNoDeoptId, | |
| 790 1); | |
| 791 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); | |
| 792 break; | |
| 793 } | |
| 794 case kInt32ArrayCid: | |
| 795 case kUint32ArrayCid: | |
| 796 if (!CanUnboxInt32()) return false; | |
| 797 | |
| 798 // We don't have ICData for the value stored, so we optimistically assume | |
| 799 // smis first. If we ever deoptimized here, we require to unbox the value | |
| 800 // before storing to handle the mint case, too. | |
| 801 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { | |
| 802 value_check = ICData::New(Function::Handle(), | |
| 803 String::Handle(), | |
| 804 Isolate::kNoDeoptId, | |
| 805 1); | |
| 806 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); | |
| 807 } | |
| 808 break; | |
| 809 case kFloat32ArrayCid: | |
| 810 case kFloat64ArrayCid: { | |
| 811 // Check that value is always double. | |
| 812 value_check = ICData::New(Function::Handle(), | |
| 813 String::Handle(), | |
| 814 Isolate::kNoDeoptId, | |
| 815 1); | |
| 816 value_check.AddReceiverCheck(kDoubleCid, Function::Handle()); | |
| 817 break; | |
| 818 } | |
| 819 default: | |
| 820 return false; | |
| 821 } | |
| 822 BuildStoreIndexed(call, value_check, class_id); | |
| 823 return true; | |
| 824 } | |
| 825 | |
| 826 | |
| 827 void FlowGraphOptimizer::BuildStoreIndexed(InstanceCallInstr* call, | 771 void FlowGraphOptimizer::BuildStoreIndexed(InstanceCallInstr* call, |
| 828 const ICData& value_check, | 772 const ICData& value_check, |
| 829 intptr_t class_id) { | 773 intptr_t class_id) { |
| 830 Definition* array = call->ArgumentAt(0); | 774 Definition* array = call->ArgumentAt(0); |
| 831 Definition* index = call->ArgumentAt(1); | 775 Definition* index = call->ArgumentAt(1); |
| 832 Definition* stored_value = call->ArgumentAt(2); | 776 Definition* stored_value = call->ArgumentAt(2); |
| 833 if (FLAG_enable_type_checks) { | 777 if (FLAG_enable_type_checks) { |
| 834 // Only type check for the value. A type check for the index is not | 778 // Only type check for the value. A type check for the index is not |
| 835 // needed here because we insert a deoptimizing smi-check for the case | 779 // needed here because we insert a deoptimizing smi-check for the case |
| 836 // the index is not a smi. | 780 // the index is not a smi. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 848 instantiator_class.type_arguments_field_offset(); | 792 instantiator_class.type_arguments_field_offset(); |
| 849 LoadFieldInstr* load_type_args = | 793 LoadFieldInstr* load_type_args = |
| 850 new LoadFieldInstr(new Value(array), | 794 new LoadFieldInstr(new Value(array), |
| 851 type_arguments_field_offset, | 795 type_arguments_field_offset, |
| 852 Type::ZoneHandle()); // No type. | 796 Type::ZoneHandle()); // No type. |
| 853 InsertBefore(call, load_type_args, NULL, Definition::kValue); | 797 InsertBefore(call, load_type_args, NULL, Definition::kValue); |
| 854 instantiator = array; | 798 instantiator = array; |
| 855 type_args = load_type_args; | 799 type_args = load_type_args; |
| 856 break; | 800 break; |
| 857 } | 801 } |
| 858 case kInt8ArrayCid: | |
| 859 case kUint8ArrayCid: | |
| 860 case kUint8ClampedArrayCid: | |
| 861 case kExternalUint8ArrayCid: | |
| 862 case kExternalUint8ClampedArrayCid: | |
| 863 case kInt16ArrayCid: | |
| 864 case kUint16ArrayCid: | |
| 865 case kInt32ArrayCid: | |
| 866 case kUint32ArrayCid: | |
| 867 case kTypedDataInt8ArrayCid: | 802 case kTypedDataInt8ArrayCid: |
| 868 case kTypedDataUint8ArrayCid: | 803 case kTypedDataUint8ArrayCid: |
| 869 case kTypedDataUint8ClampedArrayCid: | 804 case kTypedDataUint8ClampedArrayCid: |
| 870 case kExternalTypedDataUint8ArrayCid: | 805 case kExternalTypedDataUint8ArrayCid: |
| 871 case kExternalTypedDataUint8ClampedArrayCid: | 806 case kExternalTypedDataUint8ClampedArrayCid: |
| 872 case kTypedDataInt16ArrayCid: | 807 case kTypedDataInt16ArrayCid: |
| 873 case kTypedDataUint16ArrayCid: | 808 case kTypedDataUint16ArrayCid: |
| 874 case kTypedDataInt32ArrayCid: | 809 case kTypedDataInt32ArrayCid: |
| 875 case kTypedDataUint32ArrayCid: | 810 case kTypedDataUint32ArrayCid: |
| 876 ASSERT(value_type.IsIntType()); | 811 ASSERT(value_type.IsIntType()); |
| 877 // Fall through. | 812 // Fall through. |
| 878 case kFloat32ArrayCid: | |
| 879 case kFloat64ArrayCid: | |
| 880 case kTypedDataFloat32ArrayCid: | 813 case kTypedDataFloat32ArrayCid: |
| 881 case kTypedDataFloat64ArrayCid: { | 814 case kTypedDataFloat64ArrayCid: { |
| 882 type_args = instantiator = flow_graph_->constant_null(); | 815 type_args = instantiator = flow_graph_->constant_null(); |
| 883 ASSERT((class_id != kFloat32ArrayCid && | 816 ASSERT((class_id != kFloat32ArrayCid && |
| 884 class_id != kFloat64ArrayCid && | 817 class_id != kFloat64ArrayCid && |
| 885 class_id != kTypedDataFloat32ArrayCid && | 818 class_id != kTypedDataFloat32ArrayCid && |
| 886 class_id != kTypedDataFloat64ArrayCid) || | 819 class_id != kTypedDataFloat64ArrayCid) || |
| 887 value_type.IsDoubleType()); | 820 value_type.IsDoubleType()); |
| 888 ASSERT(value_type.IsInstantiated()); | 821 ASSERT(value_type.IsInstantiated()); |
| 889 break; | 822 break; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 | 867 |
| 935 | 868 |
| 936 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 869 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 937 const intptr_t class_id = ReceiverClassId(call); | 870 const intptr_t class_id = ReceiverClassId(call); |
| 938 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. | 871 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. |
| 939 intptr_t deopt_id = Isolate::kNoDeoptId; | 872 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 940 switch (class_id) { | 873 switch (class_id) { |
| 941 case kArrayCid: | 874 case kArrayCid: |
| 942 case kImmutableArrayCid: | 875 case kImmutableArrayCid: |
| 943 case kGrowableObjectArrayCid: | 876 case kGrowableObjectArrayCid: |
| 944 case kFloat32ArrayCid: | |
| 945 case kFloat64ArrayCid: | |
| 946 case kInt8ArrayCid: | |
| 947 case kUint8ArrayCid: | |
| 948 case kUint8ClampedArrayCid: | |
| 949 case kExternalUint8ArrayCid: | |
| 950 case kExternalUint8ClampedArrayCid: | |
| 951 case kInt16ArrayCid: | |
| 952 case kUint16ArrayCid: | |
| 953 case kTypedDataFloat32ArrayCid: | 877 case kTypedDataFloat32ArrayCid: |
| 954 case kTypedDataFloat64ArrayCid: | 878 case kTypedDataFloat64ArrayCid: |
| 955 case kTypedDataInt8ArrayCid: | 879 case kTypedDataInt8ArrayCid: |
| 956 case kTypedDataUint8ArrayCid: | 880 case kTypedDataUint8ArrayCid: |
| 957 case kTypedDataUint8ClampedArrayCid: | 881 case kTypedDataUint8ClampedArrayCid: |
| 958 case kExternalTypedDataUint8ArrayCid: | 882 case kExternalTypedDataUint8ArrayCid: |
| 959 case kExternalTypedDataUint8ClampedArrayCid: | 883 case kExternalTypedDataUint8ClampedArrayCid: |
| 960 case kTypedDataInt16ArrayCid: | 884 case kTypedDataInt16ArrayCid: |
| 961 case kTypedDataUint16ArrayCid: | 885 case kTypedDataUint16ArrayCid: |
| 962 break; | 886 break; |
| 963 case kInt32ArrayCid: | |
| 964 case kUint32ArrayCid: | |
| 965 case kTypedDataInt32ArrayCid: | 887 case kTypedDataInt32ArrayCid: |
| 966 case kTypedDataUint32ArrayCid: { | 888 case kTypedDataUint32ArrayCid: { |
| 967 if (!CanUnboxInt32()) return false; | 889 if (!CanUnboxInt32()) return false; |
| 968 | 890 |
| 969 // Set deopt_id if we can optimistically assume that the result is Smi. | 891 // Set deopt_id if we can optimistically assume that the result is Smi. |
| 970 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 892 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| 971 ASSERT(call->HasICData()); | 893 ASSERT(call->HasICData()); |
| 972 const ICData& ic_data = *call->ic_data(); | 894 const ICData& ic_data = *call->ic_data(); |
| 973 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 895 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| 974 call->deopt_id() : Isolate::kNoDeoptId; | 896 call->deopt_id() : Isolate::kNoDeoptId; |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1354 new Value(zero)); | 1276 new Value(zero)); |
| 1355 ReplaceCall(call, compare); | 1277 ReplaceCall(call, compare); |
| 1356 } | 1278 } |
| 1357 | 1279 |
| 1358 | 1280 |
| 1359 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { | 1281 static intptr_t OffsetForLengthGetter(MethodRecognizer::Kind kind) { |
| 1360 switch (kind) { | 1282 switch (kind) { |
| 1361 case MethodRecognizer::kObjectArrayLength: | 1283 case MethodRecognizer::kObjectArrayLength: |
| 1362 case MethodRecognizer::kImmutableArrayLength: | 1284 case MethodRecognizer::kImmutableArrayLength: |
| 1363 return Array::length_offset(); | 1285 return Array::length_offset(); |
| 1364 case MethodRecognizer::kByteArrayBaseLength: | |
| 1365 return ByteArray::length_offset(); | |
| 1366 case MethodRecognizer::kTypedDataLength: | 1286 case MethodRecognizer::kTypedDataLength: |
| 1367 // .length is defined in _TypedList which is the base class for internal | 1287 // .length is defined in _TypedList which is the base class for internal |
| 1368 // and external typed data. | 1288 // and external typed data. |
| 1369 ASSERT(TypedData::length_offset() == ExternalTypedData::length_offset()); | 1289 ASSERT(TypedData::length_offset() == ExternalTypedData::length_offset()); |
| 1370 return TypedData::length_offset(); | 1290 return TypedData::length_offset(); |
| 1371 case MethodRecognizer::kGrowableArrayLength: | 1291 case MethodRecognizer::kGrowableArrayLength: |
| 1372 return GrowableObjectArray::length_offset(); | 1292 return GrowableObjectArray::length_offset(); |
| 1373 default: | 1293 default: |
| 1374 UNREACHABLE(); | 1294 UNREACHABLE(); |
| 1375 return 0; | 1295 return 0; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1398 } | 1318 } |
| 1399 | 1319 |
| 1400 // Not an implicit getter. | 1320 // Not an implicit getter. |
| 1401 MethodRecognizer::Kind recognized_kind = | 1321 MethodRecognizer::Kind recognized_kind = |
| 1402 MethodRecognizer::RecognizeKind(target); | 1322 MethodRecognizer::RecognizeKind(target); |
| 1403 | 1323 |
| 1404 // VM objects length getter. | 1324 // VM objects length getter. |
| 1405 switch (recognized_kind) { | 1325 switch (recognized_kind) { |
| 1406 case MethodRecognizer::kObjectArrayLength: | 1326 case MethodRecognizer::kObjectArrayLength: |
| 1407 case MethodRecognizer::kImmutableArrayLength: | 1327 case MethodRecognizer::kImmutableArrayLength: |
| 1408 case MethodRecognizer::kByteArrayBaseLength: | |
| 1409 case MethodRecognizer::kTypedDataLength: | 1328 case MethodRecognizer::kTypedDataLength: |
| 1410 case MethodRecognizer::kGrowableArrayLength: { | 1329 case MethodRecognizer::kGrowableArrayLength: { |
| 1411 if (!ic_data.HasOneTarget()) { | 1330 if (!ic_data.HasOneTarget()) { |
| 1412 // TODO(srdjan): Implement for mutiple targets. | 1331 // TODO(srdjan): Implement for mutiple targets. |
| 1413 return false; | 1332 return false; |
| 1414 } | 1333 } |
| 1415 const bool is_immutable = | 1334 const bool is_immutable = |
| 1416 (recognized_kind == MethodRecognizer::kObjectArrayLength) || | 1335 (recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| 1417 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 1336 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
| 1418 (recognized_kind == MethodRecognizer::kByteArrayBaseLength) || | |
| 1419 (recognized_kind == MethodRecognizer::kTypedDataLength); | 1337 (recognized_kind == MethodRecognizer::kTypedDataLength); |
| 1420 InlineArrayLengthGetter(call, | 1338 InlineArrayLengthGetter(call, |
| 1421 OffsetForLengthGetter(recognized_kind), | 1339 OffsetForLengthGetter(recognized_kind), |
| 1422 is_immutable, | 1340 is_immutable, |
| 1423 recognized_kind); | 1341 recognized_kind); |
| 1424 return true; | 1342 return true; |
| 1425 } | 1343 } |
| 1426 case MethodRecognizer::kGrowableArrayCapacity: | 1344 case MethodRecognizer::kGrowableArrayCapacity: |
| 1427 InlineGrowableArrayCapacityGetter(call); | 1345 InlineGrowableArrayCapacityGetter(call); |
| 1428 return true; | 1346 return true; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1497 args->Add(new Value(call->ArgumentAt(i))); | 1415 args->Add(new Value(call->ArgumentAt(i))); |
| 1498 } | 1416 } |
| 1499 InvokeMathCFunctionInstr* invoke = | 1417 InvokeMathCFunctionInstr* invoke = |
| 1500 new InvokeMathCFunctionInstr(args, call, recognized_kind); | 1418 new InvokeMathCFunctionInstr(args, call, recognized_kind); |
| 1501 ReplaceCall(call, invoke); | 1419 ReplaceCall(call, invoke); |
| 1502 } | 1420 } |
| 1503 | 1421 |
| 1504 | 1422 |
| 1505 static bool IsSupportedByteArrayViewCid(intptr_t cid) { | 1423 static bool IsSupportedByteArrayViewCid(intptr_t cid) { |
| 1506 switch (cid) { | 1424 switch (cid) { |
| 1507 case kInt8ArrayCid: | 1425 case kTypedDataInt8ArrayCid: |
| 1508 case kUint8ArrayCid: | 1426 case kTypedDataUint8ArrayCid: |
| 1509 case kUint8ClampedArrayCid: | 1427 case kExternalTypedDataUint8ArrayCid: |
| 1510 case kInt16ArrayCid: | 1428 case kTypedDataUint8ClampedArrayCid: |
| 1511 case kUint16ArrayCid: | 1429 case kExternalTypedDataUint8ClampedArrayCid: |
| 1512 case kInt32ArrayCid: | 1430 case kTypedDataInt16ArrayCid: |
| 1513 case kUint32ArrayCid: | 1431 case kTypedDataUint16ArrayCid: |
| 1514 case kFloat32ArrayCid: | 1432 case kTypedDataInt32ArrayCid: |
| 1515 case kFloat64ArrayCid: | 1433 case kTypedDataUint32ArrayCid: |
| 1434 case kTypedDataFloat32ArrayCid: |
| 1435 case kTypedDataFloat64ArrayCid: |
| 1516 return true; | 1436 return true; |
| 1517 default: | 1437 default: |
| 1518 return false; | 1438 return false; |
| 1519 } | 1439 } |
| 1520 } | 1440 } |
| 1521 | 1441 |
| 1522 | 1442 |
| 1523 // Inline only simple, frequently called core library methods. | 1443 // Inline only simple, frequently called core library methods. |
| 1524 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1444 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
| 1525 ASSERT(call->HasICData()); | 1445 ASSERT(call->HasICData()); |
| 1526 const ICData& ic_data = *call->ic_data(); | 1446 const ICData& ic_data = *call->ic_data(); |
| 1527 if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) { | 1447 if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) { |
| 1528 // No type feedback collected or multiple targets found. | 1448 // No type feedback collected or multiple targets found. |
| 1529 return false; | 1449 return false; |
| 1530 } | 1450 } |
| 1531 | 1451 |
| 1532 Function& target = Function::Handle(); | 1452 Function& target = Function::Handle(); |
| 1533 GrowableArray<intptr_t> class_ids; | 1453 GrowableArray<intptr_t> class_ids; |
| 1534 ic_data.GetCheckAt(0, &class_ids, &target); | 1454 ic_data.GetCheckAt(0, &class_ids, &target); |
| 1535 MethodRecognizer::Kind recognized_kind = | 1455 MethodRecognizer::Kind recognized_kind = |
| 1536 MethodRecognizer::RecognizeKind(target); | 1456 MethodRecognizer::RecognizeKind(target); |
| 1537 | 1457 |
| 1538 // Byte array access. | |
| 1539 switch (recognized_kind) { | |
| 1540 case MethodRecognizer::kFloat32ArrayGetIndexed: | |
| 1541 case MethodRecognizer::kFloat64ArrayGetIndexed: | |
| 1542 case MethodRecognizer::kInt8ArrayGetIndexed: | |
| 1543 case MethodRecognizer::kUint8ArrayGetIndexed: | |
| 1544 case MethodRecognizer::kUint8ClampedArrayGetIndexed: | |
| 1545 case MethodRecognizer::kExternalUint8ArrayGetIndexed: | |
| 1546 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed: | |
| 1547 case MethodRecognizer::kInt16ArrayGetIndexed: | |
| 1548 case MethodRecognizer::kUint16ArrayGetIndexed: | |
| 1549 case MethodRecognizer::kInt32ArrayGetIndexed: | |
| 1550 case MethodRecognizer::kUint32ArrayGetIndexed: | |
| 1551 return TryReplaceWithLoadIndexed(call); | |
| 1552 | |
| 1553 case MethodRecognizer::kFloat32ArraySetIndexed: | |
| 1554 case MethodRecognizer::kFloat64ArraySetIndexed: | |
| 1555 case MethodRecognizer::kInt8ArraySetIndexed: | |
| 1556 case MethodRecognizer::kUint8ArraySetIndexed: | |
| 1557 case MethodRecognizer::kUint8ClampedArraySetIndexed: | |
| 1558 case MethodRecognizer::kExternalUint8ArraySetIndexed: | |
| 1559 case MethodRecognizer::kExternalUint8ClampedArraySetIndexed: | |
| 1560 case MethodRecognizer::kInt16ArraySetIndexed: | |
| 1561 case MethodRecognizer::kUint16ArraySetIndexed: | |
| 1562 case MethodRecognizer::kInt32ArraySetIndexed: | |
| 1563 case MethodRecognizer::kUint32ArraySetIndexed: | |
| 1564 return TryInlineByteArraySetIndexed(call); | |
| 1565 | |
| 1566 default: | |
| 1567 break; | |
| 1568 } | |
| 1569 | |
| 1570 if ((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) && | 1458 if ((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) && |
| 1571 (ic_data.NumberOfChecks() == 1) && | 1459 (ic_data.NumberOfChecks() == 1) && |
| 1572 ((class_ids[0] == kOneByteStringCid) || | 1460 ((class_ids[0] == kOneByteStringCid) || |
| 1573 (class_ids[0] == kTwoByteStringCid))) { | 1461 (class_ids[0] == kTwoByteStringCid))) { |
| 1574 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); | 1462 LoadIndexedInstr* instr = BuildStringCodeUnitAt(call, class_ids[0]); |
| 1575 ReplaceCall(call, instr); | 1463 ReplaceCall(call, instr); |
| 1576 return true; | 1464 return true; |
| 1577 } | 1465 } |
| 1578 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && | 1466 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && |
| 1579 (ic_data.NumberOfChecks() == 1) && | 1467 (ic_data.NumberOfChecks() == 1) && |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1648 if ((recognized_kind == MethodRecognizer::kByteArrayBaseGetInt32) || | 1536 if ((recognized_kind == MethodRecognizer::kByteArrayBaseGetInt32) || |
| 1649 (recognized_kind == MethodRecognizer::kByteArrayBaseGetUint32) || | 1537 (recognized_kind == MethodRecognizer::kByteArrayBaseGetUint32) || |
| 1650 (recognized_kind == MethodRecognizer::kByteArrayBaseSetInt32) || | 1538 (recognized_kind == MethodRecognizer::kByteArrayBaseSetInt32) || |
| 1651 (recognized_kind == MethodRecognizer::kByteArrayBaseSetUint32)) { | 1539 (recognized_kind == MethodRecognizer::kByteArrayBaseSetUint32)) { |
| 1652 if (!CanUnboxInt32()) return false; | 1540 if (!CanUnboxInt32()) return false; |
| 1653 } | 1541 } |
| 1654 | 1542 |
| 1655 switch (recognized_kind) { | 1543 switch (recognized_kind) { |
| 1656 // ByteArray getters. | 1544 // ByteArray getters. |
| 1657 case MethodRecognizer::kByteArrayBaseGetInt8: | 1545 case MethodRecognizer::kByteArrayBaseGetInt8: |
| 1658 return BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid); | 1546 return BuildByteArrayViewLoad( |
| 1547 call, class_ids[0], kTypedDataInt8ArrayCid); |
| 1659 case MethodRecognizer::kByteArrayBaseGetUint8: | 1548 case MethodRecognizer::kByteArrayBaseGetUint8: |
| 1660 return BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid); | 1549 return BuildByteArrayViewLoad( |
| 1550 call, class_ids[0], kTypedDataUint8ArrayCid); |
| 1661 case MethodRecognizer::kByteArrayBaseGetInt16: | 1551 case MethodRecognizer::kByteArrayBaseGetInt16: |
| 1662 return BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid); | 1552 return BuildByteArrayViewLoad( |
| 1553 call, class_ids[0], kTypedDataInt16ArrayCid); |
| 1663 case MethodRecognizer::kByteArrayBaseGetUint16: | 1554 case MethodRecognizer::kByteArrayBaseGetUint16: |
| 1664 return BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid); | 1555 return BuildByteArrayViewLoad( |
| 1556 call, class_ids[0], kTypedDataUint16ArrayCid); |
| 1665 case MethodRecognizer::kByteArrayBaseGetInt32: | 1557 case MethodRecognizer::kByteArrayBaseGetInt32: |
| 1666 return BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid); | 1558 return BuildByteArrayViewLoad( |
| 1559 call, class_ids[0], kTypedDataInt32ArrayCid); |
| 1667 case MethodRecognizer::kByteArrayBaseGetUint32: | 1560 case MethodRecognizer::kByteArrayBaseGetUint32: |
| 1668 return BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid); | 1561 return BuildByteArrayViewLoad( |
| 1562 call, class_ids[0], kTypedDataUint32ArrayCid); |
| 1669 case MethodRecognizer::kByteArrayBaseGetFloat32: | 1563 case MethodRecognizer::kByteArrayBaseGetFloat32: |
| 1670 return BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); | 1564 return BuildByteArrayViewLoad( |
| 1565 call, class_ids[0], kTypedDataFloat32ArrayCid); |
| 1671 case MethodRecognizer::kByteArrayBaseGetFloat64: | 1566 case MethodRecognizer::kByteArrayBaseGetFloat64: |
| 1672 return BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); | 1567 return BuildByteArrayViewLoad( |
| 1568 call, class_ids[0], kTypedDataFloat64ArrayCid); |
| 1673 | 1569 |
| 1674 // ByteArray setters. | 1570 // ByteArray setters. |
| 1675 case MethodRecognizer::kByteArrayBaseSetInt8: | 1571 case MethodRecognizer::kByteArrayBaseSetInt8: |
| 1676 return BuildByteArrayViewStore(call, class_ids[0], kInt8ArrayCid); | 1572 return BuildByteArrayViewStore( |
| 1573 call, class_ids[0], kTypedDataInt8ArrayCid); |
| 1677 case MethodRecognizer::kByteArrayBaseSetUint8: | 1574 case MethodRecognizer::kByteArrayBaseSetUint8: |
| 1678 return BuildByteArrayViewStore(call, class_ids[0], kUint8ArrayCid); | 1575 return BuildByteArrayViewStore( |
| 1576 call, class_ids[0], kTypedDataUint8ArrayCid); |
| 1679 case MethodRecognizer::kByteArrayBaseSetInt16: | 1577 case MethodRecognizer::kByteArrayBaseSetInt16: |
| 1680 return BuildByteArrayViewStore(call, class_ids[0], kInt16ArrayCid); | 1578 return BuildByteArrayViewStore( |
| 1579 call, class_ids[0], kTypedDataInt16ArrayCid); |
| 1681 case MethodRecognizer::kByteArrayBaseSetUint16: | 1580 case MethodRecognizer::kByteArrayBaseSetUint16: |
| 1682 return BuildByteArrayViewStore(call, class_ids[0], kUint16ArrayCid); | 1581 return BuildByteArrayViewStore( |
| 1582 call, class_ids[0], kTypedDataUint16ArrayCid); |
| 1683 case MethodRecognizer::kByteArrayBaseSetInt32: | 1583 case MethodRecognizer::kByteArrayBaseSetInt32: |
| 1684 return BuildByteArrayViewStore(call, class_ids[0], kInt32ArrayCid); | 1584 return BuildByteArrayViewStore( |
| 1585 call, class_ids[0], kTypedDataInt32ArrayCid); |
| 1685 case MethodRecognizer::kByteArrayBaseSetUint32: | 1586 case MethodRecognizer::kByteArrayBaseSetUint32: |
| 1686 return BuildByteArrayViewStore(call, class_ids[0], kUint32ArrayCid); | 1587 return BuildByteArrayViewStore( |
| 1588 call, class_ids[0], kTypedDataUint32ArrayCid); |
| 1687 case MethodRecognizer::kByteArrayBaseSetFloat32: | 1589 case MethodRecognizer::kByteArrayBaseSetFloat32: |
| 1688 return BuildByteArrayViewStore(call, class_ids[0], kFloat32ArrayCid); | 1590 return BuildByteArrayViewStore( |
| 1591 call, class_ids[0], kTypedDataFloat32ArrayCid); |
| 1689 case MethodRecognizer::kByteArrayBaseSetFloat64: | 1592 case MethodRecognizer::kByteArrayBaseSetFloat64: |
| 1690 return BuildByteArrayViewStore(call, class_ids[0], kFloat64ArrayCid); | 1593 return BuildByteArrayViewStore( |
| 1594 call, class_ids[0], kTypedDataFloat64ArrayCid); |
| 1691 default: | 1595 default: |
| 1692 // Unsupported method. | 1596 // Unsupported method. |
| 1693 return false; | 1597 return false; |
| 1694 } | 1598 } |
| 1695 } | 1599 } |
| 1696 return false; | 1600 return false; |
| 1697 } | 1601 } |
| 1698 | 1602 |
| 1699 | 1603 |
| 1700 bool FlowGraphOptimizer::BuildByteArrayViewLoad( | 1604 bool FlowGraphOptimizer::BuildByteArrayViewLoad( |
| 1701 InstanceCallInstr* call, | 1605 InstanceCallInstr* call, |
| 1702 intptr_t receiver_cid, | 1606 intptr_t receiver_cid, |
| 1703 intptr_t view_cid) { | 1607 intptr_t view_cid) { |
| 1704 PrepareByteArrayViewOp(call, receiver_cid, view_cid); | |
| 1705 | |
| 1706 Definition* array = call->ArgumentAt(0); | 1608 Definition* array = call->ArgumentAt(0); |
| 1707 Definition* byte_index = call->ArgumentAt(1); | 1609 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); |
| 1708 | 1610 |
| 1709 // Optimistically build a smi-checked load for Int32 and Uint32 | 1611 // Optimistically build a smi-checked load for Int32 and Uint32 |
| 1710 // loads on ia32 like we do for normal array loads, and only revert to | 1612 // loads on ia32 like we do for normal array loads, and only revert to |
| 1711 // mint case after deoptimizing here. | 1613 // mint case after deoptimizing here. |
| 1712 intptr_t deopt_id = Isolate::kNoDeoptId; | 1614 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 1713 if ((view_cid == kInt32ArrayCid || view_cid == kUint32ArrayCid) && | 1615 if ((view_cid == kInt32ArrayCid || view_cid == kUint32ArrayCid) && |
| 1714 call->ic_data()->deopt_reason() == kDeoptUnknown) { | 1616 call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 1715 deopt_id = call->deopt_id(); | 1617 deopt_id = call->deopt_id(); |
| 1716 } | 1618 } |
| 1619 Definition* byte_index = call->ArgumentAt(1); |
| 1717 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), | 1620 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), |
| 1718 new Value(byte_index), | 1621 new Value(byte_index), |
| 1719 1, // Index scale. | 1622 1, // Index scale. |
| 1720 view_cid, | 1623 view_cid, |
| 1721 deopt_id); | 1624 deopt_id); |
| 1722 ReplaceCall(call, array_op); | 1625 ReplaceCall(call, array_op); |
| 1723 return true; | 1626 return true; |
| 1724 } | 1627 } |
| 1725 | 1628 |
| 1726 | 1629 |
| 1727 bool FlowGraphOptimizer::BuildByteArrayViewStore( | 1630 bool FlowGraphOptimizer::BuildByteArrayViewStore( |
| 1728 InstanceCallInstr* call, | 1631 InstanceCallInstr* call, |
| 1729 intptr_t receiver_cid, | 1632 intptr_t receiver_cid, |
| 1730 intptr_t view_cid) { | 1633 intptr_t view_cid) { |
| 1731 PrepareByteArrayViewOp(call, receiver_cid, view_cid); | 1634 Definition* array = call->ArgumentAt(0); |
| 1635 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); |
| 1732 ICData& value_check = ICData::ZoneHandle(); | 1636 ICData& value_check = ICData::ZoneHandle(); |
| 1733 switch (view_cid) { | 1637 switch (view_cid) { |
| 1734 case kInt8ArrayCid: | 1638 case kTypedDataInt8ArrayCid: |
| 1735 case kUint8ArrayCid: | 1639 case kTypedDataUint8ArrayCid: |
| 1736 case kUint8ClampedArrayCid: | 1640 case kTypedDataUint8ClampedArrayCid: |
| 1737 case kExternalUint8ArrayCid: | 1641 case kExternalTypedDataUint8ArrayCid: |
| 1738 case kExternalUint8ClampedArrayCid: | 1642 case kExternalTypedDataUint8ClampedArrayCid: |
| 1739 case kInt16ArrayCid: | 1643 case kTypedDataInt16ArrayCid: |
| 1740 case kUint16ArrayCid: { | 1644 case kTypedDataUint16ArrayCid: { |
| 1741 // Check that value is always smi. | 1645 // Check that value is always smi. |
| 1742 value_check = ICData::New(Function::Handle(), | 1646 value_check = ICData::New(Function::Handle(), |
| 1743 String::Handle(), | 1647 String::Handle(), |
| 1744 Isolate::kNoDeoptId, | 1648 Isolate::kNoDeoptId, |
| 1745 1); | 1649 1); |
| 1746 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); | 1650 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); |
| 1747 break; | 1651 break; |
| 1748 } | 1652 } |
| 1749 case kInt32ArrayCid: | 1653 case kTypedDataInt32ArrayCid: |
| 1750 case kUint32ArrayCid: | 1654 case kTypedDataUint32ArrayCid: |
| 1751 // We don't have ICData for the value stored, so we optimistically assume | 1655 // We don't have ICData for the value stored, so we optimistically assume |
| 1752 // smis first. If we ever deoptimized here, we require to unbox the value | 1656 // smis first. If we ever deoptimized here, we require to unbox the value |
| 1753 // before storing to handle the mint case, too. | 1657 // before storing to handle the mint case, too. |
| 1754 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { | 1658 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 1755 value_check = ICData::New(Function::Handle(), | 1659 value_check = ICData::New(Function::Handle(), |
| 1756 String::Handle(), | 1660 String::Handle(), |
| 1757 Isolate::kNoDeoptId, | 1661 Isolate::kNoDeoptId, |
| 1758 1); | 1662 1); |
| 1759 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); | 1663 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); |
| 1760 } | 1664 } |
| 1761 break; | 1665 break; |
| 1762 case kFloat32ArrayCid: | 1666 case kTypedDataFloat32ArrayCid: |
| 1763 case kFloat64ArrayCid: { | 1667 case kTypedDataFloat64ArrayCid: { |
| 1764 // Check that value is always double. | 1668 // Check that value is always double. |
| 1765 value_check = ICData::New(Function::Handle(), | 1669 value_check = ICData::New(Function::Handle(), |
| 1766 String::Handle(), | 1670 String::Handle(), |
| 1767 Isolate::kNoDeoptId, | 1671 Isolate::kNoDeoptId, |
| 1768 1); | 1672 1); |
| 1769 value_check.AddReceiverCheck(kDoubleCid, Function::Handle()); | 1673 value_check.AddReceiverCheck(kDoubleCid, Function::Handle()); |
| 1770 break; | 1674 break; |
| 1771 } | 1675 } |
| 1772 default: | 1676 default: |
| 1773 // Array cids are already checked in the caller. | 1677 // Array cids are already checked in the caller. |
| 1774 UNREACHABLE(); | 1678 UNREACHABLE(); |
| 1775 return NULL; | 1679 return NULL; |
| 1776 } | 1680 } |
| 1777 | 1681 |
| 1778 Definition* array = call->ArgumentAt(0); | |
| 1779 Definition* index = call->ArgumentAt(1); | 1682 Definition* index = call->ArgumentAt(1); |
| 1780 Definition* stored_value = call->ArgumentAt(2); | 1683 Definition* stored_value = call->ArgumentAt(2); |
| 1781 if (!value_check.IsNull()) { | 1684 if (!value_check.IsNull()) { |
| 1782 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), | 1685 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), |
| 1783 call); | 1686 call); |
| 1784 } | 1687 } |
| 1785 StoreBarrierType needs_store_barrier = kNoStoreBarrier; | 1688 StoreBarrierType needs_store_barrier = kNoStoreBarrier; |
| 1786 | |
| 1787 | |
| 1788 // result = index + bytesPerElement. | |
| 1789 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | |
| 1790 ConstantInstr* bytes_per_element = | |
| 1791 new ConstantInstr(Smi::Handle(Smi::New(element_size))); | |
| 1792 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); | |
| 1793 BinarySmiOpInstr* result = | |
| 1794 new BinarySmiOpInstr(Token::kADD, | |
| 1795 call, | |
| 1796 new Value(index), | |
| 1797 new Value(bytes_per_element)); | |
| 1798 InsertBefore(call, result, call->env(), Definition::kValue); | |
| 1799 | |
| 1800 StoreIndexedInstr* array_op = new StoreIndexedInstr(new Value(array), | 1689 StoreIndexedInstr* array_op = new StoreIndexedInstr(new Value(array), |
| 1801 new Value(index), | 1690 new Value(index), |
| 1802 new Value(stored_value), | 1691 new Value(stored_value), |
| 1803 needs_store_barrier, | 1692 needs_store_barrier, |
| 1804 1, // Index scale | 1693 1, // Index scale |
| 1805 view_cid, | 1694 view_cid, |
| 1806 call->deopt_id()); | 1695 call->deopt_id()); |
| 1807 call->ReplaceUsesWith(result); // Fix uses of the call's return value. | |
| 1808 ReplaceCall(call, array_op); | 1696 ReplaceCall(call, array_op); |
| 1809 array_op->ClearSSATempIndex(); // Store has no uses. | |
| 1810 return true; | 1697 return true; |
| 1811 } | 1698 } |
| 1812 | 1699 |
| 1813 | 1700 |
| 1814 void FlowGraphOptimizer::PrepareByteArrayViewOp( | 1701 void FlowGraphOptimizer::PrepareByteArrayViewOp( |
| 1815 InstanceCallInstr* call, | 1702 InstanceCallInstr* call, |
| 1816 intptr_t receiver_cid, | 1703 intptr_t receiver_cid, |
| 1817 intptr_t view_cid) { | 1704 intptr_t view_cid, |
| 1818 Definition* array = call->ArgumentAt(0); | 1705 Definition** array) { |
| 1819 Definition* byte_index = call->ArgumentAt(1); | 1706 Definition* byte_index = call->ArgumentAt(1); |
| 1820 | 1707 |
| 1821 AddReceiverCheck(call); | 1708 AddReceiverCheck(call); |
| 1822 const bool is_immutable = true; | 1709 const bool is_immutable = true; |
| 1823 LoadFieldInstr* length = new LoadFieldInstr( | 1710 LoadFieldInstr* length = new LoadFieldInstr( |
| 1824 new Value(array), | 1711 new Value(*array), |
| 1825 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), | 1712 CheckArrayBoundInstr::LengthOffsetFor(receiver_cid), |
| 1826 Type::ZoneHandle(Type::SmiType()), | 1713 Type::ZoneHandle(Type::SmiType()), |
| 1827 is_immutable); | 1714 is_immutable); |
| 1828 length->set_result_cid(kSmiCid); | 1715 length->set_result_cid(kSmiCid); |
| 1829 length->set_recognized_kind( | 1716 length->set_recognized_kind( |
| 1830 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); | 1717 LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid)); |
| 1831 InsertBefore(call, length, NULL, Definition::kValue); | 1718 InsertBefore(call, length, NULL, Definition::kValue); |
| 1832 | 1719 |
| 1833 // len_in_bytes = length * kBytesPerElement(receiver) | 1720 // len_in_bytes = length * kBytesPerElement(receiver) |
| 1834 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); | 1721 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); |
| 1835 ConstantInstr* bytes_per_element = | 1722 ConstantInstr* bytes_per_element = |
| 1836 new ConstantInstr(Smi::Handle(Smi::New(element_size))); | 1723 new ConstantInstr(Smi::Handle(Smi::New(element_size))); |
| 1837 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); | 1724 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); |
| 1838 BinarySmiOpInstr* len_in_bytes = | 1725 BinarySmiOpInstr* len_in_bytes = |
| 1839 new BinarySmiOpInstr(Token::kMUL, | 1726 new BinarySmiOpInstr(Token::kMUL, |
| 1840 call, | 1727 call, |
| 1841 new Value(length), | 1728 new Value(length), |
| 1842 new Value(bytes_per_element)); | 1729 new Value(bytes_per_element)); |
| 1843 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | 1730 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); |
| 1844 | 1731 |
| 1845 // Check byte_index < len_in_bytes. | 1732 // Check byte_index < len_in_bytes. |
| 1846 InsertBefore(call, | 1733 InsertBefore(call, |
| 1847 new CheckArrayBoundInstr(new Value(len_in_bytes), | 1734 new CheckArrayBoundInstr(new Value(len_in_bytes), |
| 1848 new Value(byte_index), | 1735 new Value(byte_index), |
| 1849 receiver_cid, | 1736 receiver_cid, |
| 1850 call), | 1737 call), |
| 1851 call->env(), | 1738 call->env(), |
| 1852 Definition::kEffect); | 1739 Definition::kEffect); |
| 1740 |
| 1741 // Insert load of elements for external typed arrays. |
| 1742 if (RawObject::IsExternalTypedDataClassId(receiver_cid)) { |
| 1743 LoadUntaggedInstr* elements = |
| 1744 new LoadUntaggedInstr(new Value(*array), |
| 1745 ExternalTypedData::data_offset()); |
| 1746 InsertBefore(call, elements, NULL, Definition::kValue); |
| 1747 *array = elements; |
| 1748 } |
| 1853 } | 1749 } |
| 1854 | 1750 |
| 1855 | 1751 |
| 1856 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 1752 // Returns a Boolean constant if all classes in ic_data yield the same type-test |
| 1857 // result and the type tests do not depend on type arguments. Otherwise return | 1753 // result and the type tests do not depend on type arguments. Otherwise return |
| 1858 // Bool::null(). | 1754 // Bool::null(). |
| 1859 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 1755 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, |
| 1860 const AbstractType& type) const { | 1756 const AbstractType& type) const { |
| 1861 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 1757 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 1862 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); | 1758 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); |
| (...skipping 2220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4083 SetValue(instr, non_constant_); | 3979 SetValue(instr, non_constant_); |
| 4084 } | 3980 } |
| 4085 | 3981 |
| 4086 | 3982 |
| 4087 void ConstantPropagator::VisitAllocateObjectWithBoundsCheck( | 3983 void ConstantPropagator::VisitAllocateObjectWithBoundsCheck( |
| 4088 AllocateObjectWithBoundsCheckInstr* instr) { | 3984 AllocateObjectWithBoundsCheckInstr* instr) { |
| 4089 SetValue(instr, non_constant_); | 3985 SetValue(instr, non_constant_); |
| 4090 } | 3986 } |
| 4091 | 3987 |
| 4092 | 3988 |
| 3989 void ConstantPropagator::VisitLoadUntagged(LoadUntaggedInstr* instr) { |
| 3990 SetValue(instr, non_constant_); |
| 3991 } |
| 3992 |
| 3993 |
| 4093 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) { | 3994 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) { |
| 4094 if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) && | 3995 if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) && |
| 4095 (instr->value()->definition()->IsCreateArray())) { | 3996 (instr->value()->definition()->IsCreateArray())) { |
| 4096 const intptr_t length = | 3997 const intptr_t length = |
| 4097 instr->value()->definition()->AsCreateArray()->num_elements(); | 3998 instr->value()->definition()->AsCreateArray()->num_elements(); |
| 4098 const Object& result = Smi::ZoneHandle(Smi::New(length)); | 3999 const Object& result = Smi::ZoneHandle(Smi::New(length)); |
| 4099 SetValue(instr, result); | 4000 SetValue(instr, result); |
| 4100 return; | 4001 return; |
| 4101 } | 4002 } |
| 4102 | 4003 |
| (...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4706 if (changed) { | 4607 if (changed) { |
| 4707 // We may have changed the block order and the dominator tree. | 4608 // We may have changed the block order and the dominator tree. |
| 4708 flow_graph->DiscoverBlocks(); | 4609 flow_graph->DiscoverBlocks(); |
| 4709 GrowableArray<BitVector*> dominance_frontier; | 4610 GrowableArray<BitVector*> dominance_frontier; |
| 4710 flow_graph->ComputeDominators(&dominance_frontier); | 4611 flow_graph->ComputeDominators(&dominance_frontier); |
| 4711 } | 4612 } |
| 4712 } | 4613 } |
| 4713 | 4614 |
| 4714 | 4615 |
| 4715 } // namespace dart | 4616 } // namespace dart |
| OLD | NEW |