| 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 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 return class_id; | 691 return class_id; |
| 692 } | 692 } |
| 693 | 693 |
| 694 | 694 |
| 695 static bool CanUnboxInt32() { |
| 696 // Int32/Uint32 can be unboxed if it fits into a smi or the platform |
| 697 // supports unboxed mints. |
| 698 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints(); |
| 699 } |
| 700 |
| 701 |
| 695 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { | 702 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
| 696 const intptr_t class_id = ReceiverClassId(call); | 703 const intptr_t class_id = ReceiverClassId(call); |
| 697 ICData& value_check = ICData::ZoneHandle(); | 704 ICData& value_check = ICData::ZoneHandle(); |
| 698 switch (class_id) { | 705 switch (class_id) { |
| 699 case kArrayCid: | 706 case kArrayCid: |
| 700 case kGrowableObjectArrayCid: | 707 case kGrowableObjectArrayCid: |
| 701 if (ArgIsAlwaysSmi(*call->ic_data(), 2)) { | 708 if (ArgIsAlwaysSmi(*call->ic_data(), 2)) { |
| 702 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 709 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 703 } | 710 } |
| 704 break; | 711 break; |
| 705 case kInt8ArrayCid: | 712 case kInt8ArrayCid: |
| 706 case kUint8ArrayCid: | 713 case kUint8ArrayCid: |
| 707 case kUint8ClampedArrayCid: | 714 case kUint8ClampedArrayCid: |
| 708 case kExternalUint8ArrayCid: | 715 case kExternalUint8ArrayCid: |
| 709 case kExternalUint8ClampedArrayCid: | 716 case kExternalUint8ClampedArrayCid: |
| 710 case kInt16ArrayCid: | 717 case kInt16ArrayCid: |
| 711 case kUint16ArrayCid: | 718 case kUint16ArrayCid: |
| 712 // Check that value is always smi. | 719 // Check that value is always smi. |
| 713 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 720 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 714 if ((value_check.NumberOfChecks() != 1) || | 721 if ((value_check.NumberOfChecks() != 1) || |
| 715 (value_check.GetReceiverClassIdAt(0) != kSmiCid)) { | 722 (value_check.GetReceiverClassIdAt(0) != kSmiCid)) { |
| 716 return false; | 723 return false; |
| 717 } | 724 } |
| 718 break; | 725 break; |
| 719 case kInt32ArrayCid: | 726 case kInt32ArrayCid: |
| 720 case kUint32ArrayCid: { | 727 case kUint32ArrayCid: { |
| 721 // Check if elements fit into a smi or the platform supports unboxed | 728 if (!CanUnboxInt32()) return false; |
| 722 // mints. | |
| 723 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 724 return false; | |
| 725 } | |
| 726 // Check that value is always smi or mint, if the platform has unboxed | 729 // Check that value is always smi or mint, if the platform has unboxed |
| 727 // mints (ia32 with at least SSE 4.1). | 730 // mints (ia32 with at least SSE 4.1). |
| 728 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 731 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 729 for (intptr_t i = 0; i < value_check.NumberOfChecks(); i++) { | 732 for (intptr_t i = 0; i < value_check.NumberOfChecks(); i++) { |
| 730 intptr_t cid = value_check.GetReceiverClassIdAt(i); | 733 intptr_t cid = value_check.GetReceiverClassIdAt(i); |
| 731 if (FlowGraphCompiler::SupportsUnboxedMints()) { | 734 if (FlowGraphCompiler::SupportsUnboxedMints()) { |
| 732 if ((cid != kSmiCid) && (cid != kMintCid)) { | 735 if ((cid != kSmiCid) && (cid != kMintCid)) { |
| 733 return false; | 736 return false; |
| 734 } | 737 } |
| 735 } else if (cid != kSmiCid) { | 738 } else if (cid != kSmiCid) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 // Check that value is always smi. | 775 // Check that value is always smi. |
| 773 value_check = ICData::New(Function::Handle(), | 776 value_check = ICData::New(Function::Handle(), |
| 774 String::Handle(), | 777 String::Handle(), |
| 775 Isolate::kNoDeoptId, | 778 Isolate::kNoDeoptId, |
| 776 1); | 779 1); |
| 777 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); | 780 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); |
| 778 break; | 781 break; |
| 779 } | 782 } |
| 780 case kInt32ArrayCid: | 783 case kInt32ArrayCid: |
| 781 case kUint32ArrayCid: | 784 case kUint32ArrayCid: |
| 782 // Check if elements fit into a smi or the platform supports unboxed | 785 if (!CanUnboxInt32()) return false; |
| 783 // mints. | 786 |
| 784 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 785 return false; | |
| 786 } | |
| 787 // We don't have ICData for the value stored, so we optimistically assume | 787 // We don't have ICData for the value stored, so we optimistically assume |
| 788 // smis first. If we ever deoptimized here, we require to unbox the value | 788 // smis first. If we ever deoptimized here, we require to unbox the value |
| 789 // before storing to handle the mint case, too. | 789 // before storing to handle the mint case, too. |
| 790 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { | 790 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 791 value_check = ICData::New(Function::Handle(), | 791 value_check = ICData::New(Function::Handle(), |
| 792 String::Handle(), | 792 String::Handle(), |
| 793 Isolate::kNoDeoptId, | 793 Isolate::kNoDeoptId, |
| 794 1); | 794 1); |
| 795 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); | 795 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); |
| 796 } | 796 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 ? kNoStoreBarrier | 888 ? kNoStoreBarrier |
| 889 : kEmitStoreBarrier; | 889 : kEmitStoreBarrier; |
| 890 if (!value_check.IsNull()) { | 890 if (!value_check.IsNull()) { |
| 891 // No store barrier needed because checked value is a smi, an unboxed mint | 891 // No store barrier needed because checked value is a smi, an unboxed mint |
| 892 // or unboxed double. | 892 // or unboxed double. |
| 893 needs_store_barrier = kNoStoreBarrier; | 893 needs_store_barrier = kNoStoreBarrier; |
| 894 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), | 894 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), |
| 895 call); | 895 call); |
| 896 } | 896 } |
| 897 | 897 |
| 898 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); |
| 898 Definition* array_op = new StoreIndexedInstr(new Value(array), | 899 Definition* array_op = new StoreIndexedInstr(new Value(array), |
| 899 new Value(index), | 900 new Value(index), |
| 900 new Value(stored_value), | 901 new Value(stored_value), |
| 901 needs_store_barrier, | 902 needs_store_barrier, |
| 903 index_scale, |
| 902 array_cid, | 904 array_cid, |
| 903 call->deopt_id()); | 905 call->deopt_id()); |
| 904 ReplaceCall(call, array_op); | 906 ReplaceCall(call, array_op); |
| 905 } | 907 } |
| 906 | 908 |
| 907 | 909 |
| 908 | 910 |
| 909 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 911 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 910 const intptr_t class_id = ReceiverClassId(call); | 912 const intptr_t class_id = ReceiverClassId(call); |
| 911 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. | 913 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. |
| 912 intptr_t deopt_id = Isolate::kNoDeoptId; | 914 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 913 switch (class_id) { | 915 switch (class_id) { |
| 914 case kArrayCid: | 916 case kArrayCid: |
| 915 case kImmutableArrayCid: | 917 case kImmutableArrayCid: |
| 916 case kGrowableObjectArrayCid: | 918 case kGrowableObjectArrayCid: |
| 917 case kFloat32ArrayCid: | 919 case kFloat32ArrayCid: |
| 918 case kFloat64ArrayCid: | 920 case kFloat64ArrayCid: |
| 919 case kInt8ArrayCid: | 921 case kInt8ArrayCid: |
| 920 case kUint8ArrayCid: | 922 case kUint8ArrayCid: |
| 921 case kUint8ClampedArrayCid: | 923 case kUint8ClampedArrayCid: |
| 922 case kExternalUint8ArrayCid: | 924 case kExternalUint8ArrayCid: |
| 923 case kExternalUint8ClampedArrayCid: | 925 case kExternalUint8ClampedArrayCid: |
| 924 case kInt16ArrayCid: | 926 case kInt16ArrayCid: |
| 925 case kUint16ArrayCid: | 927 case kUint16ArrayCid: |
| 926 break; | 928 break; |
| 927 case kInt32ArrayCid: | 929 case kInt32ArrayCid: |
| 928 case kUint32ArrayCid: | 930 case kUint32ArrayCid: { |
| 929 // Check if elements fit into a smi or the platform supports unboxed | 931 if (!CanUnboxInt32()) return false; |
| 930 // mints. | 932 |
| 931 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 932 return false; | |
| 933 } | |
| 934 { | |
| 935 // Set deopt_id if we can optimistically assume that the result is Smi. | 933 // Set deopt_id if we can optimistically assume that the result is Smi. |
| 936 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 934 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| 937 ASSERT(call->HasICData()); | 935 ASSERT(call->HasICData()); |
| 938 const ICData& ic_data = *call->ic_data(); | 936 const ICData& ic_data = *call->ic_data(); |
| 939 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 937 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| 940 call->deopt_id() : Isolate::kNoDeoptId; | 938 call->deopt_id() : Isolate::kNoDeoptId; |
| 941 } | 939 } |
| 942 break; | 940 break; |
| 943 default: | 941 default: |
| 944 return false; | 942 return false; |
| 945 } | 943 } |
| 946 Definition* array = call->ArgumentAt(0); | 944 Definition* array = call->ArgumentAt(0); |
| 947 Definition* index = call->ArgumentAt(1); | 945 Definition* index = call->ArgumentAt(1); |
| 948 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 946 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); |
| 947 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); |
| 949 Definition* array_op = | 948 Definition* array_op = |
| 950 new LoadIndexedInstr(new Value(array), | 949 new LoadIndexedInstr(new Value(array), |
| 951 new Value(index), | 950 new Value(index), |
| 952 FlowGraphCompiler::ElementSizeFor(array_cid), | 951 index_scale, |
| 953 array_cid, | 952 array_cid, |
| 954 deopt_id); | 953 deopt_id); |
| 955 ReplaceCall(call, array_op); | 954 ReplaceCall(call, array_op); |
| 956 return true; | 955 return true; |
| 957 } | 956 } |
| 958 | 957 |
| 959 | 958 |
| 960 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 959 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 961 Token::Kind op_kind) { | 960 Token::Kind op_kind) { |
| 962 intptr_t operands_type = kIllegalCid; | 961 intptr_t operands_type = kIllegalCid; |
| (...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 } | 1595 } |
| 1597 return true; | 1596 return true; |
| 1598 default: | 1597 default: |
| 1599 // Unsupported method. | 1598 // Unsupported method. |
| 1600 return false; | 1599 return false; |
| 1601 } | 1600 } |
| 1602 } | 1601 } |
| 1603 | 1602 |
| 1604 if (IsSupportedByteArrayCid(class_ids[0]) && | 1603 if (IsSupportedByteArrayCid(class_ids[0]) && |
| 1605 (ic_data.NumberOfChecks() == 1)) { | 1604 (ic_data.NumberOfChecks() == 1)) { |
| 1606 Definition* array_op = NULL; | 1605 // For elements that may not fit into a smi on all platforms, check if |
| 1606 // elements fit into a smi or the platform supports unboxed mints. |
| 1607 if ((recognized_kind == MethodRecognizer::kByteArrayBaseGetInt32) || |
| 1608 (recognized_kind == MethodRecognizer::kByteArrayBaseGetUint32) || |
| 1609 (recognized_kind == MethodRecognizer::kByteArrayBaseSetInt32) || |
| 1610 (recognized_kind == MethodRecognizer::kByteArrayBaseSetUint32)) { |
| 1611 if (!CanUnboxInt32()) return false; |
| 1612 } |
| 1613 |
| 1607 switch (recognized_kind) { | 1614 switch (recognized_kind) { |
| 1615 // ByteArray getters. |
| 1608 case MethodRecognizer::kByteArrayBaseGetInt8: | 1616 case MethodRecognizer::kByteArrayBaseGetInt8: |
| 1609 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid); | 1617 return BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid); |
| 1610 break; | |
| 1611 case MethodRecognizer::kByteArrayBaseGetUint8: | 1618 case MethodRecognizer::kByteArrayBaseGetUint8: |
| 1612 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid); | 1619 return BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid); |
| 1613 break; | |
| 1614 case MethodRecognizer::kByteArrayBaseGetInt16: | 1620 case MethodRecognizer::kByteArrayBaseGetInt16: |
| 1615 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid); | 1621 return BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid); |
| 1616 break; | |
| 1617 case MethodRecognizer::kByteArrayBaseGetUint16: | 1622 case MethodRecognizer::kByteArrayBaseGetUint16: |
| 1618 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid); | 1623 return BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid); |
| 1619 break; | |
| 1620 case MethodRecognizer::kByteArrayBaseGetInt32: | 1624 case MethodRecognizer::kByteArrayBaseGetInt32: |
| 1621 // Check if elements fit into a smi or the platform supports unboxed | 1625 return BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid); |
| 1622 // mints. | |
| 1623 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 1624 return false; | |
| 1625 } | |
| 1626 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid); | |
| 1627 break; | |
| 1628 case MethodRecognizer::kByteArrayBaseGetUint32: | 1626 case MethodRecognizer::kByteArrayBaseGetUint32: |
| 1629 // Check if elements fit into a smi or the platform supports unboxed | 1627 return BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid); |
| 1630 // mints. | |
| 1631 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 1632 return false; | |
| 1633 } | |
| 1634 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid); | |
| 1635 break; | |
| 1636 case MethodRecognizer::kByteArrayBaseGetFloat32: | 1628 case MethodRecognizer::kByteArrayBaseGetFloat32: |
| 1637 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); | 1629 return BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); |
| 1638 break; | |
| 1639 case MethodRecognizer::kByteArrayBaseGetFloat64: | 1630 case MethodRecognizer::kByteArrayBaseGetFloat64: |
| 1640 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); | 1631 return BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); |
| 1641 break; | 1632 |
| 1633 // ByteArray setters. |
| 1634 case MethodRecognizer::kByteArrayBaseSetInt8: |
| 1635 return BuildByteArrayViewStore(call, class_ids[0], kInt8ArrayCid); |
| 1636 case MethodRecognizer::kByteArrayBaseSetUint8: |
| 1637 return BuildByteArrayViewStore(call, class_ids[0], kUint8ArrayCid); |
| 1638 case MethodRecognizer::kByteArrayBaseSetInt16: |
| 1639 return BuildByteArrayViewStore(call, class_ids[0], kInt16ArrayCid); |
| 1640 case MethodRecognizer::kByteArrayBaseSetUint16: |
| 1641 return BuildByteArrayViewStore(call, class_ids[0], kUint16ArrayCid); |
| 1642 case MethodRecognizer::kByteArrayBaseSetInt32: |
| 1643 return BuildByteArrayViewStore(call, class_ids[0], kInt32ArrayCid); |
| 1644 case MethodRecognizer::kByteArrayBaseSetUint32: |
| 1645 return BuildByteArrayViewStore(call, class_ids[0], kUint32ArrayCid); |
| 1646 case MethodRecognizer::kByteArrayBaseSetFloat32: |
| 1647 return BuildByteArrayViewStore(call, class_ids[0], kFloat32ArrayCid); |
| 1648 case MethodRecognizer::kByteArrayBaseSetFloat64: |
| 1649 return BuildByteArrayViewStore(call, class_ids[0], kFloat64ArrayCid); |
| 1642 default: | 1650 default: |
| 1643 // Unsupported method. | 1651 // Unsupported method. |
| 1644 return false; | 1652 return false; |
| 1645 } | 1653 } |
| 1646 ASSERT(array_op != NULL); | |
| 1647 ReplaceCall(call, array_op); | |
| 1648 return true; | |
| 1649 } | 1654 } |
| 1650 return false; | 1655 return false; |
| 1651 } | 1656 } |
| 1652 | 1657 |
| 1653 | 1658 |
| 1654 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( | 1659 bool FlowGraphOptimizer::BuildByteArrayViewLoad( |
| 1660 InstanceCallInstr* call, |
| 1661 intptr_t receiver_cid, |
| 1662 intptr_t view_cid) { |
| 1663 PrepareByteArrayViewOp(call, receiver_cid, view_cid); |
| 1664 |
| 1665 Definition* array = call->ArgumentAt(0); |
| 1666 Definition* byte_index = call->ArgumentAt(1); |
| 1667 |
| 1668 // Optimistically build a smi-checked load for Int32 and Uint32 |
| 1669 // loads on ia32 like we do for normal array loads, and only revert to |
| 1670 // mint case after deoptimizing here. |
| 1671 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 1672 if ((view_cid == kInt32ArrayCid || view_cid == kUint32ArrayCid) && |
| 1673 call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 1674 deopt_id = call->deopt_id(); |
| 1675 } |
| 1676 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), |
| 1677 new Value(byte_index), |
| 1678 1, // Index scale. |
| 1679 view_cid, |
| 1680 deopt_id); |
| 1681 ReplaceCall(call, array_op); |
| 1682 return true; |
| 1683 } |
| 1684 |
| 1685 |
| 1686 bool FlowGraphOptimizer::BuildByteArrayViewStore( |
| 1687 InstanceCallInstr* call, |
| 1688 intptr_t receiver_cid, |
| 1689 intptr_t view_cid) { |
| 1690 PrepareByteArrayViewOp(call, receiver_cid, view_cid); |
| 1691 ICData& value_check = ICData::ZoneHandle(); |
| 1692 switch (view_cid) { |
| 1693 case kInt8ArrayCid: |
| 1694 case kUint8ArrayCid: |
| 1695 case kUint8ClampedArrayCid: |
| 1696 case kExternalUint8ArrayCid: |
| 1697 case kExternalUint8ClampedArrayCid: |
| 1698 case kInt16ArrayCid: |
| 1699 case kUint16ArrayCid: { |
| 1700 // Check that value is always smi. |
| 1701 value_check = ICData::New(Function::Handle(), |
| 1702 String::Handle(), |
| 1703 Isolate::kNoDeoptId, |
| 1704 1); |
| 1705 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); |
| 1706 break; |
| 1707 } |
| 1708 case kInt32ArrayCid: |
| 1709 case kUint32ArrayCid: |
| 1710 // We don't have ICData for the value stored, so we optimistically assume |
| 1711 // smis first. If we ever deoptimized here, we require to unbox the value |
| 1712 // before storing to handle the mint case, too. |
| 1713 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 1714 value_check = ICData::New(Function::Handle(), |
| 1715 String::Handle(), |
| 1716 Isolate::kNoDeoptId, |
| 1717 1); |
| 1718 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); |
| 1719 } |
| 1720 break; |
| 1721 case kFloat32ArrayCid: |
| 1722 case kFloat64ArrayCid: { |
| 1723 // Check that value is always double. |
| 1724 value_check = ICData::New(Function::Handle(), |
| 1725 String::Handle(), |
| 1726 Isolate::kNoDeoptId, |
| 1727 1); |
| 1728 value_check.AddReceiverCheck(kDoubleCid, Function::Handle()); |
| 1729 break; |
| 1730 } |
| 1731 default: |
| 1732 // Array cids are already checked in the caller. |
| 1733 UNREACHABLE(); |
| 1734 return NULL; |
| 1735 } |
| 1736 |
| 1737 Definition* array = call->ArgumentAt(0); |
| 1738 Definition* index = call->ArgumentAt(1); |
| 1739 Definition* stored_value = call->ArgumentAt(2); |
| 1740 if (!value_check.IsNull()) { |
| 1741 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), |
| 1742 call); |
| 1743 } |
| 1744 StoreBarrierType needs_store_barrier = kNoStoreBarrier; |
| 1745 |
| 1746 |
| 1747 // result = index + bytesPerElement. |
| 1748 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid); |
| 1749 ConstantInstr* bytes_per_element = |
| 1750 new ConstantInstr(Smi::Handle(Smi::New(element_size))); |
| 1751 InsertBefore(call, bytes_per_element, NULL, Definition::kValue); |
| 1752 BinarySmiOpInstr* result = |
| 1753 new BinarySmiOpInstr(Token::kADD, |
| 1754 call, |
| 1755 new Value(index), |
| 1756 new Value(bytes_per_element)); |
| 1757 InsertBefore(call, result, call->env(), Definition::kValue); |
| 1758 |
| 1759 StoreIndexedInstr* array_op = new StoreIndexedInstr(new Value(array), |
| 1760 new Value(index), |
| 1761 new Value(stored_value), |
| 1762 needs_store_barrier, |
| 1763 1, // Index scale |
| 1764 view_cid, |
| 1765 call->deopt_id()); |
| 1766 call->ReplaceUsesWith(result); // Fix uses of the call's return value. |
| 1767 ReplaceCall(call, array_op); |
| 1768 array_op->ClearSSATempIndex(); // Store has no uses. |
| 1769 return true; |
| 1770 } |
| 1771 |
| 1772 |
| 1773 void FlowGraphOptimizer::PrepareByteArrayViewOp( |
| 1655 InstanceCallInstr* call, | 1774 InstanceCallInstr* call, |
| 1656 intptr_t receiver_cid, | 1775 intptr_t receiver_cid, |
| 1657 intptr_t view_cid) { | 1776 intptr_t view_cid) { |
| 1658 Definition* array = call->ArgumentAt(0); | 1777 Definition* array = call->ArgumentAt(0); |
| 1659 Definition* byte_index = call->ArgumentAt(1); | 1778 Definition* byte_index = call->ArgumentAt(1); |
| 1660 | 1779 |
| 1661 AddReceiverCheck(call); | 1780 AddReceiverCheck(call); |
| 1662 const bool is_immutable = true; | 1781 const bool is_immutable = true; |
| 1663 LoadFieldInstr* length = new LoadFieldInstr( | 1782 LoadFieldInstr* length = new LoadFieldInstr( |
| 1664 new Value(array), | 1783 new Value(array), |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1683 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); | 1802 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); |
| 1684 | 1803 |
| 1685 // Check byte_index < len_in_bytes. | 1804 // Check byte_index < len_in_bytes. |
| 1686 InsertBefore(call, | 1805 InsertBefore(call, |
| 1687 new CheckArrayBoundInstr(new Value(len_in_bytes), | 1806 new CheckArrayBoundInstr(new Value(len_in_bytes), |
| 1688 new Value(byte_index), | 1807 new Value(byte_index), |
| 1689 receiver_cid, | 1808 receiver_cid, |
| 1690 call), | 1809 call), |
| 1691 call->env(), | 1810 call->env(), |
| 1692 Definition::kEffect); | 1811 Definition::kEffect); |
| 1693 | |
| 1694 // TODO(fschneider): Optimistically build smi load for Int32 and Uint32 | |
| 1695 // loads on ia32 like we do for normal array loads, and only revert to | |
| 1696 // mint case after deoptimizing here. | |
| 1697 return new LoadIndexedInstr(new Value(array), | |
| 1698 new Value(byte_index), | |
| 1699 1, // Index scale. | |
| 1700 view_cid, | |
| 1701 Isolate::kNoDeoptId); // Can't deoptimize. | |
| 1702 } | 1812 } |
| 1703 | 1813 |
| 1704 | 1814 |
| 1705 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 1815 // Returns a Boolean constant if all classes in ic_data yield the same type-test |
| 1706 // result and the type tests do not depend on type arguments. Otherwise return | 1816 // result and the type tests do not depend on type arguments. Otherwise return |
| 1707 // Bool::null(). | 1817 // Bool::null(). |
| 1708 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 1818 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, |
| 1709 const AbstractType& type) const { | 1819 const AbstractType& type) const { |
| 1710 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 1820 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 1711 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); | 1821 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); |
| (...skipping 2837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4549 if (changed) { | 4659 if (changed) { |
| 4550 // We may have changed the block order and the dominator tree. | 4660 // We may have changed the block order and the dominator tree. |
| 4551 flow_graph->DiscoverBlocks(); | 4661 flow_graph->DiscoverBlocks(); |
| 4552 GrowableArray<BitVector*> dominance_frontier; | 4662 GrowableArray<BitVector*> dominance_frontier; |
| 4553 flow_graph->ComputeDominators(&dominance_frontier); | 4663 flow_graph->ComputeDominators(&dominance_frontier); |
| 4554 } | 4664 } |
| 4555 } | 4665 } |
| 4556 | 4666 |
| 4557 | 4667 |
| 4558 } // namespace dart | 4668 } // namespace dart |
| OLD | NEW |