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/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 | 102 |
103 | 103 |
104 // Attempt to build ICData for call using propagated class-ids. | 104 // Attempt to build ICData for call using propagated class-ids. |
105 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 105 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
106 ASSERT(call->HasICData()); | 106 ASSERT(call->HasICData()); |
107 if (call->ic_data()->NumberOfChecks() > 0) { | 107 if (call->ic_data()->NumberOfChecks() > 0) { |
108 // This occurs when an instance call has too many checks, will be converted | 108 // This occurs when an instance call has too many checks, will be converted |
109 // to megamorphic call. | 109 // to megamorphic call. |
110 return false; | 110 return false; |
111 } | 111 } |
112 GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested()); | 112 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
113 ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount()); | 113 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); |
114 for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) { | 114 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
115 const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid(); | 115 const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid(); |
116 class_ids.Add(cid); | 116 class_ids.Add(cid); |
117 } | 117 } |
118 | 118 |
119 const Token::Kind op_kind = call->token_kind(); | 119 const Token::Kind op_kind = call->token_kind(); |
120 if (Token::IsRelationalOperator(op_kind) || | 120 if (Token::IsRelationalOperator(op_kind) || |
121 Token::IsEqualityOperator(op_kind) || | 121 Token::IsEqualityOperator(op_kind) || |
122 Token::IsBinaryOperator(op_kind)) { | 122 Token::IsBinaryOperator(op_kind)) { |
123 // Guess cid: if one of the inputs is a number assume that the other | 123 // Guess cid: if one of the inputs is a number assume that the other |
124 // is a number of same type. | 124 // is a number of same type. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 } else { | 166 } else { |
167 ASSERT(class_ids.length() == 1); | 167 ASSERT(class_ids.length() == 1); |
168 ic_data.AddReceiverCheck(class_ids[0], function); | 168 ic_data.AddReceiverCheck(class_ids[0], function); |
169 } | 169 } |
170 call->set_ic_data(&ic_data); | 170 call->set_ic_data(&ic_data); |
171 return true; | 171 return true; |
172 } | 172 } |
173 | 173 |
174 | 174 |
175 static const ICData& TrySpecializeICData(const ICData& ic_data, intptr_t cid) { | 175 static const ICData& TrySpecializeICData(const ICData& ic_data, intptr_t cid) { |
176 ASSERT(ic_data.num_args_tested() == 1); | 176 ASSERT(ic_data.NumArgsTested() == 1); |
177 | 177 |
178 if ((ic_data.NumberOfChecks() == 1) && | 178 if ((ic_data.NumberOfChecks() == 1) && |
179 (ic_data.GetReceiverClassIdAt(0) == cid)) { | 179 (ic_data.GetReceiverClassIdAt(0) == cid)) { |
180 return ic_data; // Nothing to do | 180 return ic_data; // Nothing to do |
181 } | 181 } |
182 | 182 |
183 const Function& function = | 183 const Function& function = |
184 Function::Handle(ic_data.GetTargetForReceiverClassId(cid)); | 184 Function::Handle(ic_data.GetTargetForReceiverClassId(cid)); |
185 // TODO(fschneider): Try looking up the function on the class if it is | 185 // TODO(fschneider): Try looking up the function on the class if it is |
186 // not found in the ICData. | 186 // not found in the ICData. |
187 if (!function.IsNull()) { | 187 if (!function.IsNull()) { |
188 const ICData& new_ic_data = ICData::ZoneHandle(ICData::New( | 188 const ICData& new_ic_data = ICData::ZoneHandle(ICData::New( |
189 Function::Handle(ic_data.function()), | 189 Function::Handle(ic_data.owner()), |
190 String::Handle(ic_data.target_name()), | 190 String::Handle(ic_data.target_name()), |
191 Object::empty_array(), // Dummy argument descriptor. | 191 Object::empty_array(), // Dummy argument descriptor. |
192 ic_data.deopt_id(), | 192 ic_data.deopt_id(), |
193 ic_data.num_args_tested())); | 193 ic_data.NumArgsTested())); |
194 new_ic_data.set_deopt_reason(ic_data.deopt_reason()); | 194 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); |
195 new_ic_data.AddReceiverCheck(cid, function); | 195 new_ic_data.AddReceiverCheck(cid, function); |
196 return new_ic_data; | 196 return new_ic_data; |
197 } | 197 } |
198 | 198 |
199 return ic_data; | 199 return ic_data; |
200 } | 200 } |
201 | 201 |
202 | 202 |
203 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 203 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( |
204 PolymorphicInstanceCallInstr* call) { | 204 PolymorphicInstanceCallInstr* call) { |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
810 } | 810 } |
811 } | 811 } |
812 } | 812 } |
813 | 813 |
814 | 814 |
815 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, | 815 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, |
816 intptr_t receiver_class_id, | 816 intptr_t receiver_class_id, |
817 intptr_t argument_class_id) { | 817 intptr_t argument_class_id) { |
818 ASSERT(receiver_class_id != kIllegalCid); | 818 ASSERT(receiver_class_id != kIllegalCid); |
819 ASSERT(argument_class_id != kIllegalCid); | 819 ASSERT(argument_class_id != kIllegalCid); |
820 if (ic_data.num_args_tested() != 2) return false; | 820 if (ic_data.NumArgsTested() != 2) return false; |
821 | 821 |
822 Function& target = Function::Handle(); | 822 Function& target = Function::Handle(); |
823 const intptr_t len = ic_data.NumberOfChecks(); | 823 const intptr_t len = ic_data.NumberOfChecks(); |
824 for (intptr_t i = 0; i < len; i++) { | 824 for (intptr_t i = 0; i < len; i++) { |
825 GrowableArray<intptr_t> class_ids; | 825 GrowableArray<intptr_t> class_ids; |
826 ic_data.GetCheckAt(i, &class_ids, &target); | 826 ic_data.GetCheckAt(i, &class_ids, &target); |
827 ASSERT(class_ids.length() == 2); | 827 ASSERT(class_ids.length() == 2); |
828 if ((class_ids[0] == receiver_class_id) && | 828 if ((class_ids[0] == receiver_class_id) && |
829 (class_ids[1] == argument_class_id)) { | 829 (class_ids[1] == argument_class_id)) { |
830 return true; | 830 return true; |
(...skipping 13 matching lines...) Expand all Loading... |
844 return false; | 844 return false; |
845 } | 845 } |
846 | 846 |
847 | 847 |
848 // Returns true if ICData tests two arguments and all ICData cids are in the | 848 // Returns true if ICData tests two arguments and all ICData cids are in the |
849 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. | 849 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. |
850 static bool ICDataHasOnlyReceiverArgumentClassIds( | 850 static bool ICDataHasOnlyReceiverArgumentClassIds( |
851 const ICData& ic_data, | 851 const ICData& ic_data, |
852 const GrowableArray<intptr_t>& receiver_class_ids, | 852 const GrowableArray<intptr_t>& receiver_class_ids, |
853 const GrowableArray<intptr_t>& argument_class_ids) { | 853 const GrowableArray<intptr_t>& argument_class_ids) { |
854 if (ic_data.num_args_tested() != 2) return false; | 854 if (ic_data.NumArgsTested() != 2) return false; |
855 Function& target = Function::Handle(); | 855 Function& target = Function::Handle(); |
856 const intptr_t len = ic_data.NumberOfChecks(); | 856 const intptr_t len = ic_data.NumberOfChecks(); |
857 for (intptr_t i = 0; i < len; i++) { | 857 for (intptr_t i = 0; i < len; i++) { |
858 GrowableArray<intptr_t> class_ids; | 858 GrowableArray<intptr_t> class_ids; |
859 ic_data.GetCheckAt(i, &class_ids, &target); | 859 ic_data.GetCheckAt(i, &class_ids, &target); |
860 ASSERT(class_ids.length() == 2); | 860 ASSERT(class_ids.length() == 2); |
861 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || | 861 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || |
862 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { | 862 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { |
863 return false; | 863 return false; |
864 } | 864 } |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
981 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()), | 981 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()), |
982 call->deopt_id(), | 982 call->deopt_id(), |
983 call->env(), | 983 call->env(), |
984 call); | 984 call); |
985 } | 985 } |
986 | 986 |
987 | 987 |
988 static bool ArgIsAlways(intptr_t cid, | 988 static bool ArgIsAlways(intptr_t cid, |
989 const ICData& ic_data, | 989 const ICData& ic_data, |
990 intptr_t arg_number) { | 990 intptr_t arg_number) { |
991 ASSERT(ic_data.num_args_tested() > arg_number); | 991 ASSERT(ic_data.NumArgsTested() > arg_number); |
992 const intptr_t num_checks = ic_data.NumberOfChecks(); | 992 const intptr_t num_checks = ic_data.NumberOfChecks(); |
993 if (num_checks == 0) return false; | 993 if (num_checks == 0) return false; |
994 for (intptr_t i = 0; i < num_checks; i++) { | 994 for (intptr_t i = 0; i < num_checks; i++) { |
995 if (ic_data.GetClassIdAt(i, arg_number) != cid) return false; | 995 if (ic_data.GetClassIdAt(i, arg_number) != cid) return false; |
996 } | 996 } |
997 return true; | 997 return true; |
998 } | 998 } |
999 | 999 |
1000 | 1000 |
1001 static bool CanUnboxInt32() { | 1001 static bool CanUnboxInt32() { |
(...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1578 array_cid, | 1578 array_cid, |
1579 &array, | 1579 &array, |
1580 index, | 1580 index, |
1581 &cursor); | 1581 &cursor); |
1582 | 1582 |
1583 intptr_t deopt_id = Isolate::kNoDeoptId; | 1583 intptr_t deopt_id = Isolate::kNoDeoptId; |
1584 if ((array_cid == kTypedDataInt32ArrayCid) || | 1584 if ((array_cid == kTypedDataInt32ArrayCid) || |
1585 (array_cid == kTypedDataUint32ArrayCid)) { | 1585 (array_cid == kTypedDataUint32ArrayCid)) { |
1586 // Set deopt_id if we can optimistically assume that the result is Smi. | 1586 // Set deopt_id if we can optimistically assume that the result is Smi. |
1587 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 1587 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
1588 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 1588 deopt_id = ic_data.HasDeoptReasons() ? |
1589 call->deopt_id() : Isolate::kNoDeoptId; | 1589 Isolate::kNoDeoptId : call->deopt_id(); |
1590 } | 1590 } |
1591 | 1591 |
1592 // Array load and return. | 1592 // Array load and return. |
1593 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); | 1593 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); |
1594 *last = new LoadIndexedInstr(new Value(array), | 1594 *last = new LoadIndexedInstr(new Value(array), |
1595 new Value(index), | 1595 new Value(index), |
1596 index_scale, | 1596 index_scale, |
1597 array_cid, | 1597 array_cid, |
1598 deopt_id); | 1598 deopt_id); |
1599 cursor = flow_graph()->AppendTo( | 1599 cursor = flow_graph()->AppendTo( |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1760 } | 1760 } |
1761 return false; | 1761 return false; |
1762 } | 1762 } |
1763 | 1763 |
1764 | 1764 |
1765 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1765 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
1766 | 1766 |
1767 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 1767 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
1768 Token::Kind op_kind) { | 1768 Token::Kind op_kind) { |
1769 const ICData& ic_data = *call->ic_data(); | 1769 const ICData& ic_data = *call->ic_data(); |
1770 ASSERT(ic_data.num_args_tested() == 2); | 1770 ASSERT(ic_data.NumArgsTested() == 2); |
1771 | 1771 |
1772 ASSERT(call->ArgumentCount() == 2); | 1772 ASSERT(call->ArgumentCount() == 2); |
1773 Definition* left = call->ArgumentAt(0); | 1773 Definition* left = call->ArgumentAt(0); |
1774 Definition* right = call->ArgumentAt(1); | 1774 Definition* right = call->ArgumentAt(1); |
1775 | 1775 |
1776 intptr_t cid = kIllegalCid; | 1776 intptr_t cid = kIllegalCid; |
1777 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 1777 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
1778 if (TryStringLengthOneEquality(call, op_kind)) { | 1778 if (TryStringLengthOneEquality(call, op_kind)) { |
1779 return true; | 1779 return true; |
1780 } else { | 1780 } else { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1864 cid, | 1864 cid, |
1865 call->deopt_id()); | 1865 call->deopt_id()); |
1866 ReplaceCall(call, comp); | 1866 ReplaceCall(call, comp); |
1867 return true; | 1867 return true; |
1868 } | 1868 } |
1869 | 1869 |
1870 | 1870 |
1871 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1871 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
1872 Token::Kind op_kind) { | 1872 Token::Kind op_kind) { |
1873 const ICData& ic_data = *call->ic_data(); | 1873 const ICData& ic_data = *call->ic_data(); |
1874 ASSERT(ic_data.num_args_tested() == 2); | 1874 ASSERT(ic_data.NumArgsTested() == 2); |
1875 | 1875 |
1876 ASSERT(call->ArgumentCount() == 2); | 1876 ASSERT(call->ArgumentCount() == 2); |
1877 Definition* left = call->ArgumentAt(0); | 1877 Definition* left = call->ArgumentAt(0); |
1878 Definition* right = call->ArgumentAt(1); | 1878 Definition* right = call->ArgumentAt(1); |
1879 | 1879 |
1880 intptr_t cid = kIllegalCid; | 1880 intptr_t cid = kIllegalCid; |
1881 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1881 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
1882 InsertBefore(call, | 1882 InsertBefore(call, |
1883 new CheckSmiInstr(new Value(left), call->deopt_id()), | 1883 new CheckSmiInstr(new Value(left), call->deopt_id()), |
1884 call->env(), | 1884 call->env(), |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1929 Token::Kind op_kind) { | 1929 Token::Kind op_kind) { |
1930 intptr_t operands_type = kIllegalCid; | 1930 intptr_t operands_type = kIllegalCid; |
1931 ASSERT(call->HasICData()); | 1931 ASSERT(call->HasICData()); |
1932 const ICData& ic_data = *call->ic_data(); | 1932 const ICData& ic_data = *call->ic_data(); |
1933 switch (op_kind) { | 1933 switch (op_kind) { |
1934 case Token::kADD: | 1934 case Token::kADD: |
1935 case Token::kSUB: | 1935 case Token::kSUB: |
1936 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1936 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
1937 // Don't generate smi code if the IC data is marked because | 1937 // Don't generate smi code if the IC data is marked because |
1938 // of an overflow. | 1938 // of an overflow. |
1939 operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp) | 1939 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp) |
1940 ? kMintCid | 1940 ? kMintCid |
1941 : kSmiCid; | 1941 : kSmiCid; |
1942 } else if (HasTwoMintOrSmi(ic_data) && | 1942 } else if (HasTwoMintOrSmi(ic_data) && |
1943 FlowGraphCompiler::SupportsUnboxedMints()) { | 1943 FlowGraphCompiler::SupportsUnboxedMints()) { |
1944 // Don't generate mint code if the IC data is marked because of an | 1944 // Don't generate mint code if the IC data is marked because of an |
1945 // overflow. | 1945 // overflow. |
1946 if (ic_data.deopt_reason() == kDeoptBinaryMintOp) return false; | 1946 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false; |
1947 operands_type = kMintCid; | 1947 operands_type = kMintCid; |
1948 } else if (ShouldSpecializeForDouble(ic_data)) { | 1948 } else if (ShouldSpecializeForDouble(ic_data)) { |
1949 operands_type = kDoubleCid; | 1949 operands_type = kDoubleCid; |
1950 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { | 1950 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { |
1951 operands_type = kFloat32x4Cid; | 1951 operands_type = kFloat32x4Cid; |
1952 } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) { | 1952 } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) { |
1953 operands_type = kInt32x4Cid; | 1953 operands_type = kInt32x4Cid; |
1954 } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) { | 1954 } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) { |
1955 operands_type = kFloat64x2Cid; | 1955 operands_type = kFloat64x2Cid; |
1956 } else { | 1956 } else { |
1957 return false; | 1957 return false; |
1958 } | 1958 } |
1959 break; | 1959 break; |
1960 case Token::kMUL: | 1960 case Token::kMUL: |
1961 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1961 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
1962 // Don't generate smi code if the IC data is marked because of an | 1962 // Don't generate smi code if the IC data is marked because of an |
1963 // overflow. | 1963 // overflow. |
1964 // TODO(fschneider): Add unboxed mint multiplication. | 1964 // TODO(fschneider): Add unboxed mint multiplication. |
1965 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) return false; | 1965 if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) return false; |
1966 operands_type = kSmiCid; | 1966 operands_type = kSmiCid; |
1967 } else if (ShouldSpecializeForDouble(ic_data)) { | 1967 } else if (ShouldSpecializeForDouble(ic_data)) { |
1968 operands_type = kDoubleCid; | 1968 operands_type = kDoubleCid; |
1969 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { | 1969 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { |
1970 operands_type = kFloat32x4Cid; | 1970 operands_type = kFloat32x4Cid; |
1971 } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) { | 1971 } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) { |
1972 operands_type = kFloat64x2Cid; | 1972 operands_type = kFloat64x2Cid; |
1973 } else { | 1973 } else { |
1974 return false; | 1974 return false; |
1975 } | 1975 } |
(...skipping 22 matching lines...) Expand all Loading... |
1998 } else { | 1998 } else { |
1999 return false; | 1999 return false; |
2000 } | 2000 } |
2001 break; | 2001 break; |
2002 case Token::kSHR: | 2002 case Token::kSHR: |
2003 case Token::kSHL: | 2003 case Token::kSHL: |
2004 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 2004 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
2005 // Left shift may overflow from smi into mint or big ints. | 2005 // Left shift may overflow from smi into mint or big ints. |
2006 // Don't generate smi code if the IC data is marked because | 2006 // Don't generate smi code if the IC data is marked because |
2007 // of an overflow. | 2007 // of an overflow. |
2008 if (ic_data.deopt_reason() == kDeoptShiftMintOp) { | 2008 if (ic_data.HasDeoptReason(ICData::kDeoptShiftMintOp)) { |
2009 return false; | 2009 return false; |
2010 } | 2010 } |
2011 operands_type = (ic_data.deopt_reason() == kDeoptBinarySmiOp) | 2011 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp) |
2012 ? kMintCid | 2012 ? kMintCid |
2013 : kSmiCid; | 2013 : kSmiCid; |
2014 } else if (HasTwoMintOrSmi(ic_data) && | 2014 } else if (HasTwoMintOrSmi(ic_data) && |
2015 HasOnlyOneSmi(ICData::Handle( | 2015 HasOnlyOneSmi(ICData::Handle( |
2016 ic_data.AsUnaryClassChecksForArgNr(1)))) { | 2016 ic_data.AsUnaryClassChecksForArgNr(1)))) { |
2017 // Don't generate mint code if the IC data is marked because of an | 2017 // Don't generate mint code if the IC data is marked because of an |
2018 // overflow. | 2018 // overflow. |
2019 if (ic_data.deopt_reason() == kDeoptShiftMintOp) { | 2019 if (ic_data.HasDeoptReason(ICData::kDeoptShiftMintOp)) { |
2020 return false; | 2020 return false; |
2021 } | 2021 } |
2022 // Check for smi/mint << smi or smi/mint >> smi. | 2022 // Check for smi/mint << smi or smi/mint >> smi. |
2023 operands_type = kMintCid; | 2023 operands_type = kMintCid; |
2024 } else { | 2024 } else { |
2025 return false; | 2025 return false; |
2026 } | 2026 } |
2027 break; | 2027 break; |
2028 case Token::kMOD: | 2028 case Token::kMOD: |
2029 case Token::kTRUNCDIV: | 2029 case Token::kTRUNCDIV: |
2030 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 2030 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
2031 if (ic_data.deopt_reason() == kDeoptBinarySmiOp) { | 2031 if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) { |
2032 return false; | 2032 return false; |
2033 } | 2033 } |
2034 operands_type = kSmiCid; | 2034 operands_type = kSmiCid; |
2035 } else { | 2035 } else { |
2036 return false; | 2036 return false; |
2037 } | 2037 } |
2038 break; | 2038 break; |
2039 default: | 2039 default: |
2040 UNREACHABLE(); | 2040 UNREACHABLE(); |
2041 } | 2041 } |
(...skipping 782 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2824 } | 2824 } |
2825 | 2825 |
2826 if (class_ids[0] == kDoubleCid) { | 2826 if (class_ids[0] == kDoubleCid) { |
2827 switch (recognized_kind) { | 2827 switch (recognized_kind) { |
2828 case MethodRecognizer::kDoubleToInteger: { | 2828 case MethodRecognizer::kDoubleToInteger: { |
2829 AddReceiverCheck(call); | 2829 AddReceiverCheck(call); |
2830 ASSERT(call->HasICData()); | 2830 ASSERT(call->HasICData()); |
2831 const ICData& ic_data = *call->ic_data(); | 2831 const ICData& ic_data = *call->ic_data(); |
2832 Definition* input = call->ArgumentAt(0); | 2832 Definition* input = call->ArgumentAt(0); |
2833 Definition* d2i_instr = NULL; | 2833 Definition* d2i_instr = NULL; |
2834 if (ic_data.deopt_reason() == kDeoptDoubleToSmi) { | 2834 if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) { |
2835 // Do not repeatedly deoptimize because result didn't fit into Smi. | 2835 // Do not repeatedly deoptimize because result didn't fit into Smi. |
2836 d2i_instr = new DoubleToIntegerInstr(new Value(input), call); | 2836 d2i_instr = new DoubleToIntegerInstr(new Value(input), call); |
2837 } else { | 2837 } else { |
2838 // Optimistically assume result fits into Smi. | 2838 // Optimistically assume result fits into Smi. |
2839 d2i_instr = new DoubleToSmiInstr(new Value(input), call->deopt_id()); | 2839 d2i_instr = new DoubleToSmiInstr(new Value(input), call->deopt_id()); |
2840 } | 2840 } |
2841 ReplaceCall(call, d2i_instr); | 2841 ReplaceCall(call, d2i_instr); |
2842 return true; | 2842 return true; |
2843 } | 2843 } |
2844 case MethodRecognizer::kDoubleMod: | 2844 case MethodRecognizer::kDoubleMod: |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2932 if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | 2932 if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) { |
2933 return TryInlineInt32x4Method(call, recognized_kind); | 2933 return TryInlineInt32x4Method(call, recognized_kind); |
2934 } | 2934 } |
2935 | 2935 |
2936 if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) { | 2936 if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) { |
2937 return TryInlineFloat64x2Method(call, recognized_kind); | 2937 return TryInlineFloat64x2Method(call, recognized_kind); |
2938 } | 2938 } |
2939 | 2939 |
2940 if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) { | 2940 if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) { |
2941 ASSERT(call->ArgumentCount() == 3); | 2941 ASSERT(call->ArgumentCount() == 3); |
2942 ASSERT(ic_data.num_args_tested() == 2); | 2942 ASSERT(ic_data.NumArgsTested() == 2); |
2943 Definition* value = call->ArgumentAt(0); | 2943 Definition* value = call->ArgumentAt(0); |
2944 Definition* count = call->ArgumentAt(1); | 2944 Definition* count = call->ArgumentAt(1); |
2945 Definition* int32_mask = call->ArgumentAt(2); | 2945 Definition* int32_mask = call->ArgumentAt(2); |
2946 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 2946 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
2947 if (ic_data.deopt_reason() == kDeoptShiftMintOp) { | 2947 if (ic_data.HasDeoptReason(ICData::kDeoptShiftMintOp)) { |
2948 return false; | 2948 return false; |
2949 } | 2949 } |
2950 // We cannot overflow. The input value must be a Smi | 2950 // We cannot overflow. The input value must be a Smi |
2951 AddCheckSmi(value, call->deopt_id(), call->env(), call); | 2951 AddCheckSmi(value, call->deopt_id(), call->env(), call); |
2952 AddCheckSmi(count, call->deopt_id(), call->env(), call); | 2952 AddCheckSmi(count, call->deopt_id(), call->env(), call); |
2953 ASSERT(int32_mask->IsConstant()); | 2953 ASSERT(int32_mask->IsConstant()); |
2954 const Integer& mask_literal = Integer::Cast( | 2954 const Integer& mask_literal = Integer::Cast( |
2955 int32_mask->AsConstant()->value()); | 2955 int32_mask->AsConstant()->value()); |
2956 const int64_t mask_value = mask_literal.AsInt64Value(); | 2956 const int64_t mask_value = mask_literal.AsInt64Value(); |
2957 ASSERT(mask_value >= 0); | 2957 ASSERT(mask_value >= 0); |
(...skipping 16 matching lines...) Expand all Loading... |
2974 new Value(left_shift), new Value(int32_mask), | 2974 new Value(left_shift), new Value(int32_mask), |
2975 call->deopt_id()); | 2975 call->deopt_id()); |
2976 ReplaceCall(call, bit_and); | 2976 ReplaceCall(call, bit_and); |
2977 } | 2977 } |
2978 return true; | 2978 return true; |
2979 } | 2979 } |
2980 | 2980 |
2981 if (HasTwoMintOrSmi(ic_data) && | 2981 if (HasTwoMintOrSmi(ic_data) && |
2982 HasOnlyOneSmi(ICData::Handle(ic_data.AsUnaryClassChecksForArgNr(1)))) { | 2982 HasOnlyOneSmi(ICData::Handle(ic_data.AsUnaryClassChecksForArgNr(1)))) { |
2983 if (!FlowGraphCompiler::SupportsUnboxedMints() || | 2983 if (!FlowGraphCompiler::SupportsUnboxedMints() || |
2984 (ic_data.deopt_reason() == kDeoptShiftMintOp)) { | 2984 ic_data.HasDeoptReason(ICData::kDeoptShiftMintOp)) { |
2985 return false; | 2985 return false; |
2986 } | 2986 } |
2987 ShiftMintOpInstr* left_shift = | 2987 ShiftMintOpInstr* left_shift = |
2988 new ShiftMintOpInstr(Token::kSHL, | 2988 new ShiftMintOpInstr(Token::kSHL, |
2989 new Value(value), new Value(count), | 2989 new Value(value), new Value(count), |
2990 call->deopt_id()); | 2990 call->deopt_id()); |
2991 InsertBefore(call, left_shift, call->env(), Definition::kValue); | 2991 InsertBefore(call, left_shift, call->env(), Definition::kValue); |
2992 BinaryMintOpInstr* bit_and = | 2992 BinaryMintOpInstr* bit_and = |
2993 new BinaryMintOpInstr(Token::kBIT_AND, | 2993 new BinaryMintOpInstr(Token::kBIT_AND, |
2994 new Value(left_shift), new Value(int32_mask), | 2994 new Value(left_shift), new Value(int32_mask), |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3400 view_cid, | 3400 view_cid, |
3401 &array, | 3401 &array, |
3402 index, | 3402 index, |
3403 &cursor); | 3403 &cursor); |
3404 | 3404 |
3405 intptr_t deopt_id = Isolate::kNoDeoptId; | 3405 intptr_t deopt_id = Isolate::kNoDeoptId; |
3406 if ((array_cid == kTypedDataInt32ArrayCid) || | 3406 if ((array_cid == kTypedDataInt32ArrayCid) || |
3407 (array_cid == kTypedDataUint32ArrayCid)) { | 3407 (array_cid == kTypedDataUint32ArrayCid)) { |
3408 // Set deopt_id if we can optimistically assume that the result is Smi. | 3408 // Set deopt_id if we can optimistically assume that the result is Smi. |
3409 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 3409 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
3410 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 3410 deopt_id = ic_data.HasDeoptReasons() ? |
3411 call->deopt_id() : Isolate::kNoDeoptId; | 3411 Isolate::kNoDeoptId : call->deopt_id(); |
3412 } | 3412 } |
3413 | 3413 |
3414 *last = new LoadIndexedInstr(new Value(array), | 3414 *last = new LoadIndexedInstr(new Value(array), |
3415 new Value(index), | 3415 new Value(index), |
3416 1, | 3416 1, |
3417 view_cid, | 3417 view_cid, |
3418 deopt_id); | 3418 deopt_id); |
3419 cursor = flow_graph()->AppendTo( | 3419 cursor = flow_graph()->AppendTo( |
3420 cursor, | 3420 cursor, |
3421 *last, | 3421 *last, |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3482 Isolate::kNoDeoptId, | 3482 Isolate::kNoDeoptId, |
3483 1); | 3483 1); |
3484 value_check.AddReceiverCheck(kSmiCid, target); | 3484 value_check.AddReceiverCheck(kSmiCid, target); |
3485 break; | 3485 break; |
3486 } | 3486 } |
3487 case kTypedDataInt32ArrayCid: | 3487 case kTypedDataInt32ArrayCid: |
3488 case kTypedDataUint32ArrayCid: | 3488 case kTypedDataUint32ArrayCid: |
3489 // We don't have ICData for the value stored, so we optimistically assume | 3489 // We don't have ICData for the value stored, so we optimistically assume |
3490 // smis first. If we ever deoptimized here, we require to unbox the value | 3490 // smis first. If we ever deoptimized here, we require to unbox the value |
3491 // before storing to handle the mint case, too. | 3491 // before storing to handle the mint case, too. |
3492 if (i_call->ic_data()->deopt_reason() == kDeoptUnknown) { | 3492 if (!i_call->ic_data()->HasDeoptReasons()) { |
3493 value_check = ICData::New(flow_graph_->parsed_function().function(), | 3493 value_check = ICData::New(flow_graph_->parsed_function().function(), |
3494 i_call->function_name(), | 3494 i_call->function_name(), |
3495 Object::empty_array(), // Dummy args. descr. | 3495 Object::empty_array(), // Dummy args. descr. |
3496 Isolate::kNoDeoptId, | 3496 Isolate::kNoDeoptId, |
3497 1); | 3497 1); |
3498 value_check.AddReceiverCheck(kSmiCid, target); | 3498 value_check.AddReceiverCheck(kSmiCid, target); |
3499 } | 3499 } |
3500 break; | 3500 break; |
3501 case kTypedDataFloat32ArrayCid: | 3501 case kTypedDataFloat32ArrayCid: |
3502 case kTypedDataFloat64ArrayCid: { | 3502 case kTypedDataFloat64ArrayCid: { |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3677 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 3677 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
3678 // If all tests yield the same result, return it otherwise return Bool::null. | 3678 // If all tests yield the same result, return it otherwise return Bool::null. |
3679 // If no mapping is possible, 'results' is empty. | 3679 // If no mapping is possible, 'results' is empty. |
3680 // An instance-of test returning all same results can be converted to a class | 3680 // An instance-of test returning all same results can be converted to a class |
3681 // check. | 3681 // check. |
3682 RawBool* FlowGraphOptimizer::InstanceOfAsBool( | 3682 RawBool* FlowGraphOptimizer::InstanceOfAsBool( |
3683 const ICData& ic_data, | 3683 const ICData& ic_data, |
3684 const AbstractType& type, | 3684 const AbstractType& type, |
3685 ZoneGrowableArray<intptr_t>* results) const { | 3685 ZoneGrowableArray<intptr_t>* results) const { |
3686 results->Clear(); | 3686 results->Clear(); |
3687 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 3687 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. |
3688 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 3688 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
3689 return Bool::null(); | 3689 return Bool::null(); |
3690 } | 3690 } |
3691 const Class& type_class = Class::Handle(type.type_class()); | 3691 const Class& type_class = Class::Handle(type.type_class()); |
3692 const intptr_t num_type_args = type_class.NumTypeArguments(); | 3692 const intptr_t num_type_args = type_class.NumTypeArguments(); |
3693 if (num_type_args > 0) { | 3693 if (num_type_args > 0) { |
3694 // Only raw types can be directly compared, thus disregarding type | 3694 // Only raw types can be directly compared, thus disregarding type |
3695 // arguments. | 3695 // arguments. |
3696 const intptr_t num_type_params = type_class.NumTypeParameters(); | 3696 const intptr_t num_type_params = type_class.NumTypeParameters(); |
3697 const intptr_t from_index = num_type_args - num_type_params; | 3697 const intptr_t from_index = num_type_args - num_type_params; |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4221 } else { | 4221 } else { |
4222 FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field); | 4222 FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field); |
4223 } | 4223 } |
4224 } | 4224 } |
4225 } | 4225 } |
4226 | 4226 |
4227 | 4227 |
4228 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 4228 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
4229 const ICData& unary_ic_data) { | 4229 const ICData& unary_ic_data) { |
4230 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 4230 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
4231 (unary_ic_data.num_args_tested() == 1)); | 4231 (unary_ic_data.NumArgsTested() == 1)); |
4232 if (FLAG_enable_type_checks) { | 4232 if (FLAG_enable_type_checks) { |
4233 // Checked mode setters are inlined like normal methods by conventional | 4233 // Checked mode setters are inlined like normal methods by conventional |
4234 // inlining. | 4234 // inlining. |
4235 return false; | 4235 return false; |
4236 } | 4236 } |
4237 | 4237 |
4238 ASSERT(instr->HasICData()); | 4238 ASSERT(instr->HasICData()); |
4239 if (unary_ic_data.NumberOfChecks() == 0) { | 4239 if (unary_ic_data.NumberOfChecks() == 0) { |
4240 // No type feedback collected. | 4240 // No type feedback collected. |
4241 return false; | 4241 return false; |
(...skipping 4911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9153 } | 9153 } |
9154 | 9154 |
9155 // Insert materializations at environment uses. | 9155 // Insert materializations at environment uses. |
9156 for (intptr_t i = 0; i < exits.length(); i++) { | 9156 for (intptr_t i = 0; i < exits.length(); i++) { |
9157 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); | 9157 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); |
9158 } | 9158 } |
9159 } | 9159 } |
9160 | 9160 |
9161 | 9161 |
9162 } // namespace dart | 9162 } // namespace dart |
OLD | NEW |