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

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

Issue 12378039: Inline ByteArray setters like setUint8 in the optimizer. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_optimizer.h" 5 #include "vm/flow_graph_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/cha.h" 8 #include "vm/cha.h"
9 #include "vm/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 742 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 return false; 753 return false;
754 } 754 }
755 755
756 BuildStoreIndexed(call, value_check, class_id); 756 BuildStoreIndexed(call, value_check, class_id);
757 return true; 757 return true;
758 } 758 }
759 759
760 760
761 bool FlowGraphOptimizer::TryInlineByteArraySetIndexed(InstanceCallInstr* call) { 761 bool FlowGraphOptimizer::TryInlineByteArraySetIndexed(InstanceCallInstr* call) {
762 const intptr_t class_id = ReceiverClassId(call); 762 const intptr_t class_id = ReceiverClassId(call);
763 if (class_id == kInt32ArrayCid || class_id == kUint32ArrayCid) {
764 // Check if elements fit into a smi or the platform supports unboxed mints.
765 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) {
Vyacheslav Egorov (Google) 2013/03/11 11:45:27 I think you can move it back down.
Florian Schneider 2013/03/11 12:14:12 Done.
766 return false;
767 }
768 }
763 ICData& value_check = ICData::ZoneHandle(); 769 ICData& value_check = ICData::ZoneHandle();
764 switch (class_id) { 770 switch (class_id) {
765 case kInt8ArrayCid: 771 case kInt8ArrayCid:
766 case kUint8ArrayCid: 772 case kUint8ArrayCid:
767 case kUint8ClampedArrayCid: 773 case kUint8ClampedArrayCid:
768 case kExternalUint8ArrayCid: 774 case kExternalUint8ArrayCid:
769 case kExternalUint8ClampedArrayCid: 775 case kExternalUint8ClampedArrayCid:
770 case kInt16ArrayCid: 776 case kInt16ArrayCid:
771 case kUint16ArrayCid: { 777 case kUint16ArrayCid: {
772 // Check that value is always smi. 778 // Check that value is always smi.
773 value_check = ICData::New(Function::Handle(), 779 value_check = ICData::New(Function::Handle(),
774 String::Handle(), 780 String::Handle(),
775 Isolate::kNoDeoptId, 781 Isolate::kNoDeoptId,
776 1); 782 1);
777 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); 783 value_check.AddReceiverCheck(kSmiCid, Function::Handle());
778 break; 784 break;
779 } 785 }
780 case kInt32ArrayCid: 786 case kInt32ArrayCid:
781 case kUint32ArrayCid: 787 case kUint32ArrayCid:
782 // Check if elements fit into a smi or the platform supports unboxed
783 // mints.
784 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) {
785 return false;
786 }
787 // We don't have ICData for the value stored, so we optimistically assume 788 // 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 789 // smis first. If we ever deoptimized here, we require to unbox the value
789 // before storing to handle the mint case, too. 790 // before storing to handle the mint case, too.
790 if (call->ic_data()->deopt_reason() == kDeoptUnknown) { 791 if (call->ic_data()->deopt_reason() == kDeoptUnknown) {
791 value_check = ICData::New(Function::Handle(), 792 value_check = ICData::New(Function::Handle(),
792 String::Handle(), 793 String::Handle(),
793 Isolate::kNoDeoptId, 794 Isolate::kNoDeoptId,
794 1); 795 1);
795 value_check.AddReceiverCheck(kSmiCid, Function::Handle()); 796 value_check.AddReceiverCheck(kSmiCid, Function::Handle());
796 } 797 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
888 ? kNoStoreBarrier 889 ? kNoStoreBarrier
889 : kEmitStoreBarrier; 890 : kEmitStoreBarrier;
890 if (!value_check.IsNull()) { 891 if (!value_check.IsNull()) {
891 // No store barrier needed because checked value is a smi, an unboxed mint 892 // No store barrier needed because checked value is a smi, an unboxed mint
892 // or unboxed double. 893 // or unboxed double.
893 needs_store_barrier = kNoStoreBarrier; 894 needs_store_barrier = kNoStoreBarrier;
894 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(), 895 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(),
895 call); 896 call);
896 } 897 }
897 898
899 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid);
898 Definition* array_op = new StoreIndexedInstr(new Value(array), 900 Definition* array_op = new StoreIndexedInstr(new Value(array),
899 new Value(index), 901 new Value(index),
900 new Value(stored_value), 902 new Value(stored_value),
901 needs_store_barrier, 903 needs_store_barrier,
904 index_scale,
902 array_cid, 905 array_cid,
903 call->deopt_id()); 906 call->deopt_id());
904 ReplaceCall(call, array_op); 907 ReplaceCall(call, array_op);
905 } 908 }
906 909
907 910
908 911
909 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { 912 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) {
910 const intptr_t class_id = ReceiverClassId(call); 913 const intptr_t class_id = ReceiverClassId(call);
911 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. 914 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt.
(...skipping 27 matching lines...) Expand all
939 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? 942 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ?
940 call->deopt_id() : Isolate::kNoDeoptId; 943 call->deopt_id() : Isolate::kNoDeoptId;
941 } 944 }
942 break; 945 break;
943 default: 946 default:
944 return false; 947 return false;
945 } 948 }
946 Definition* array = call->ArgumentAt(0); 949 Definition* array = call->ArgumentAt(0);
947 Definition* index = call->ArgumentAt(1); 950 Definition* index = call->ArgumentAt(1);
948 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); 951 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
952 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid);
949 Definition* array_op = 953 Definition* array_op =
950 new LoadIndexedInstr(new Value(array), 954 new LoadIndexedInstr(new Value(array),
951 new Value(index), 955 new Value(index),
952 FlowGraphCompiler::ElementSizeFor(array_cid), 956 index_scale,
953 array_cid, 957 array_cid,
954 deopt_id); 958 deopt_id);
955 ReplaceCall(call, array_op); 959 ReplaceCall(call, array_op);
956 return true; 960 return true;
957 } 961 }
958 962
959 963
960 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, 964 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
961 Token::Kind op_kind) { 965 Token::Kind op_kind) {
962 intptr_t operands_type = kIllegalCid; 966 intptr_t operands_type = kIllegalCid;
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after
1596 } 1600 }
1597 return true; 1601 return true;
1598 default: 1602 default:
1599 // Unsupported method. 1603 // Unsupported method.
1600 return false; 1604 return false;
1601 } 1605 }
1602 } 1606 }
1603 1607
1604 if (IsSupportedByteArrayCid(class_ids[0]) && 1608 if (IsSupportedByteArrayCid(class_ids[0]) &&
1605 (ic_data.NumberOfChecks() == 1)) { 1609 (ic_data.NumberOfChecks() == 1)) {
1606 Definition* array_op = NULL; 1610 // For elements that may not fit into a smi on all platforms, check if
1611 // elements fit into a smi or the platform supports unboxed mints.
1612 if ((recognized_kind == MethodRecognizer::kByteArrayBaseGetInt32) ||
1613 (recognized_kind == MethodRecognizer::kByteArrayBaseGetUint32) ||
1614 (recognized_kind == MethodRecognizer::kByteArrayBaseSetInt32) ||
1615 (recognized_kind == MethodRecognizer::kByteArrayBaseSetUint32)) {
1616 if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) {
Vyacheslav Egorov (Google) 2013/03/11 11:45:27 Maybe make a helper static bool CanLoadUnboxedIn
Florian Schneider 2013/03/11 12:14:12 Done.
1617 return false;
1618 }
1619 }
1620
1607 switch (recognized_kind) { 1621 switch (recognized_kind) {
1622 // ByteArray getters.
1608 case MethodRecognizer::kByteArrayBaseGetInt8: 1623 case MethodRecognizer::kByteArrayBaseGetInt8:
1609 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid); 1624 return BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid);
1610 break;
1611 case MethodRecognizer::kByteArrayBaseGetUint8: 1625 case MethodRecognizer::kByteArrayBaseGetUint8:
1612 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid); 1626 return BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid);
1613 break;
1614 case MethodRecognizer::kByteArrayBaseGetInt16: 1627 case MethodRecognizer::kByteArrayBaseGetInt16:
1615 array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid); 1628 return BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid);
1616 break;
1617 case MethodRecognizer::kByteArrayBaseGetUint16: 1629 case MethodRecognizer::kByteArrayBaseGetUint16:
1618 array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid); 1630 return BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid);
1619 break;
1620 case MethodRecognizer::kByteArrayBaseGetInt32: 1631 case MethodRecognizer::kByteArrayBaseGetInt32:
1621 // Check if elements fit into a smi or the platform supports unboxed 1632 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: 1633 case MethodRecognizer::kByteArrayBaseGetUint32:
1629 // Check if elements fit into a smi or the platform supports unboxed 1634 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: 1635 case MethodRecognizer::kByteArrayBaseGetFloat32:
1637 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid); 1636 return BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid);
1638 break;
1639 case MethodRecognizer::kByteArrayBaseGetFloat64: 1637 case MethodRecognizer::kByteArrayBaseGetFloat64:
1640 array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid); 1638 return BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid);
1641 break; 1639
1640 // ByteArray setters.
1641 case MethodRecognizer::kByteArrayBaseSetInt8:
1642 return BuildByteArrayViewStore(call, class_ids[0], kInt8ArrayCid);
1643 case MethodRecognizer::kByteArrayBaseSetUint8:
1644 return BuildByteArrayViewStore(call, class_ids[0], kUint8ArrayCid);
1645 case MethodRecognizer::kByteArrayBaseSetInt16:
1646 return BuildByteArrayViewStore(call, class_ids[0], kInt16ArrayCid);
1647 case MethodRecognizer::kByteArrayBaseSetUint16:
1648 return BuildByteArrayViewStore(call, class_ids[0], kUint16ArrayCid);
1649 case MethodRecognizer::kByteArrayBaseSetInt32:
1650 return BuildByteArrayViewStore(call, class_ids[0], kInt32ArrayCid);
1651 case MethodRecognizer::kByteArrayBaseSetUint32:
1652 return BuildByteArrayViewStore(call, class_ids[0], kUint32ArrayCid);
1653 case MethodRecognizer::kByteArrayBaseSetFloat32:
1654 return BuildByteArrayViewStore(call, class_ids[0], kFloat32ArrayCid);
1655 case MethodRecognizer::kByteArrayBaseSetFloat64:
1656 return BuildByteArrayViewStore(call, class_ids[0], kFloat64ArrayCid);
1642 default: 1657 default:
1643 // Unsupported method. 1658 // Unsupported method.
1644 return false; 1659 return false;
1645 } 1660 }
1646 ASSERT(array_op != NULL);
1647 ReplaceCall(call, array_op);
1648 return true;
1649 } 1661 }
1650 return false; 1662 return false;
1651 } 1663 }
1652 1664
1653 1665
1654 LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad( 1666 bool FlowGraphOptimizer::BuildByteArrayViewLoad(
1667 InstanceCallInstr* call,
1668 intptr_t receiver_cid,
1669 intptr_t view_cid) {
1670 PrepareByteArrayViewOp(call, receiver_cid, view_cid);
1671
1672 Definition* array = call->ArgumentAt(0);
1673 Definition* byte_index = call->ArgumentAt(1);
1674
1675 // Optimistically build a smi-checked load for Int32 and Uint32
1676 // loads on ia32 like we do for normal array loads, and only revert to
1677 // mint case after deoptimizing here.
1678 intptr_t deopt_id = Isolate::kNoDeoptId;
1679 if ((view_cid == kInt32ArrayCid || view_cid == kUint32ArrayCid) &&
1680 call->ic_data()->deopt_reason() == kDeoptUnknown) {
1681 deopt_id = call->deopt_id();
1682 }
1683 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array),
1684 new Value(byte_index),
1685 1, // Index scale.
1686 view_cid,
1687 deopt_id);
1688 ReplaceCall(call, array_op);
1689 return true;
1690 }
1691
1692
1693 bool FlowGraphOptimizer::BuildByteArrayViewStore(
1694 InstanceCallInstr* call,
1695 intptr_t receiver_cid,
1696 intptr_t view_cid) {
1697 PrepareByteArrayViewOp(call, receiver_cid, view_cid);
1698 ICData& value_check = ICData::ZoneHandle();
1699 switch (view_cid) {
1700 case kInt8ArrayCid:
1701 case kUint8ArrayCid:
1702 case kUint8ClampedArrayCid:
1703 case kExternalUint8ArrayCid:
1704 case kExternalUint8ClampedArrayCid:
1705 case kInt16ArrayCid:
1706 case kUint16ArrayCid: {
1707 // Check that value is always smi.
1708 value_check = ICData::New(Function::Handle(),
1709 String::Handle(),
1710 Isolate::kNoDeoptId,
1711 1);
1712 value_check.AddReceiverCheck(kSmiCid, Function::Handle());
1713 break;
1714 }
1715 case kInt32ArrayCid:
1716 case kUint32ArrayCid:
1717 // We don't have ICData for the value stored, so we optimistically assume
1718 // smis first. If we ever deoptimized here, we require to unbox the value
1719 // before storing to handle the mint case, too.
1720 if (call->ic_data()->deopt_reason() == kDeoptUnknown) {
1721 value_check = ICData::New(Function::Handle(),
1722 String::Handle(),
1723 Isolate::kNoDeoptId,
1724 1);
1725 value_check.AddReceiverCheck(kSmiCid, Function::Handle());
1726 }
1727 break;
1728 case kFloat32ArrayCid:
1729 case kFloat64ArrayCid: {
1730 // Check that value is always double.
1731 value_check = ICData::New(Function::Handle(),
1732 String::Handle(),
1733 Isolate::kNoDeoptId,
1734 1);
1735 value_check.AddReceiverCheck(kDoubleCid, Function::Handle());
1736 break;
1737 }
1738 default:
1739 // Array cids are already checked in the caller.
1740 UNREACHABLE();
1741 return NULL;
1742 }
1743
1744 Definition* array = call->ArgumentAt(0);
1745 Definition* index = call->ArgumentAt(1);
1746 Definition* stored_value = call->ArgumentAt(2);
1747 if (!value_check.IsNull()) {
1748 AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(),
1749 call);
1750 }
1751 StoreBarrierType needs_store_barrier = kNoStoreBarrier;
1752
1753
1754 // result = index + bytesPerElement.
1755 intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
1756 ConstantInstr* bytes_per_element =
1757 new ConstantInstr(Smi::Handle(Smi::New(element_size)));
1758 InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
1759 BinarySmiOpInstr* result =
1760 new BinarySmiOpInstr(Token::kADD,
Vyacheslav Egorov (Google) 2013/03/11 11:45:27 why kADD.
Florian Schneider 2013/03/11 12:14:12 This is the return value of the setter: index + el
1761 call,
1762 new Value(index),
1763 new Value(bytes_per_element));
1764 InsertBefore(call, result, call->env(), Definition::kValue);
1765
1766 StoreIndexedInstr* array_op = new StoreIndexedInstr(new Value(array),
1767 new Value(index),
1768 new Value(stored_value),
1769 needs_store_barrier,
1770 1, // Index scale
1771 view_cid,
1772 call->deopt_id());
1773 call->ReplaceUsesWith(result); // Fix uses of the call's return value.
1774 ReplaceCall(call, array_op);
1775 array_op->ClearSSATempIndex(); // Store has no uses.
1776 return true;
1777 }
1778
1779
1780 void FlowGraphOptimizer::PrepareByteArrayViewOp(
1655 InstanceCallInstr* call, 1781 InstanceCallInstr* call,
1656 intptr_t receiver_cid, 1782 intptr_t receiver_cid,
1657 intptr_t view_cid) { 1783 intptr_t view_cid) {
1658 Definition* array = call->ArgumentAt(0); 1784 Definition* array = call->ArgumentAt(0);
1659 Definition* byte_index = call->ArgumentAt(1); 1785 Definition* byte_index = call->ArgumentAt(1);
1660 1786
1661 AddReceiverCheck(call); 1787 AddReceiverCheck(call);
1662 const bool is_immutable = true; 1788 const bool is_immutable = true;
1663 LoadFieldInstr* length = new LoadFieldInstr( 1789 LoadFieldInstr* length = new LoadFieldInstr(
1664 new Value(array), 1790 new Value(array),
(...skipping 18 matching lines...) Expand all
1683 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue); 1809 InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
1684 1810
1685 // Check byte_index < len_in_bytes. 1811 // Check byte_index < len_in_bytes.
1686 InsertBefore(call, 1812 InsertBefore(call,
1687 new CheckArrayBoundInstr(new Value(len_in_bytes), 1813 new CheckArrayBoundInstr(new Value(len_in_bytes),
1688 new Value(byte_index), 1814 new Value(byte_index),
1689 receiver_cid, 1815 receiver_cid,
1690 call), 1816 call),
1691 call->env(), 1817 call->env(),
1692 Definition::kEffect); 1818 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 } 1819 }
1703 1820
1704 1821
1705 // Returns a Boolean constant if all classes in ic_data yield the same type-test 1822 // 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 1823 // result and the type tests do not depend on type arguments. Otherwise return
1707 // Bool::null(). 1824 // Bool::null().
1708 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, 1825 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data,
1709 const AbstractType& type) const { 1826 const AbstractType& type) const {
1710 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. 1827 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only.
1711 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null(); 1828 if (!type.IsInstantiated() || type.IsMalformed()) return Bool::null();
(...skipping 2837 matching lines...) Expand 10 before | Expand all | Expand 10 after
4549 if (changed) { 4666 if (changed) {
4550 // We may have changed the block order and the dominator tree. 4667 // We may have changed the block order and the dominator tree.
4551 flow_graph->DiscoverBlocks(); 4668 flow_graph->DiscoverBlocks();
4552 GrowableArray<BitVector*> dominance_frontier; 4669 GrowableArray<BitVector*> dominance_frontier;
4553 flow_graph->ComputeDominators(&dominance_frontier); 4670 flow_graph->ComputeDominators(&dominance_frontier);
4554 } 4671 }
4555 } 4672 }
4556 4673
4557 4674
4558 } // namespace dart 4675 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698