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 |