| 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 |