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/jit_optimizer.h" | 5 #include "vm/jit_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1215 } | 1215 } |
1216 InvokeMathCFunctionInstr* invoke = | 1216 InvokeMathCFunctionInstr* invoke = |
1217 new(Z) InvokeMathCFunctionInstr(args, | 1217 new(Z) InvokeMathCFunctionInstr(args, |
1218 call->deopt_id(), | 1218 call->deopt_id(), |
1219 recognized_kind, | 1219 recognized_kind, |
1220 call->token_pos()); | 1220 call->token_pos()); |
1221 ReplaceCall(call, invoke); | 1221 ReplaceCall(call, invoke); |
1222 } | 1222 } |
1223 | 1223 |
1224 | 1224 |
1225 static bool IsSupportedByteArrayViewCid(intptr_t cid) { | |
1226 switch (cid) { | |
1227 case kTypedDataInt8ArrayCid: | |
1228 case kTypedDataUint8ArrayCid: | |
1229 case kExternalTypedDataUint8ArrayCid: | |
1230 case kTypedDataUint8ClampedArrayCid: | |
1231 case kExternalTypedDataUint8ClampedArrayCid: | |
1232 case kTypedDataInt16ArrayCid: | |
1233 case kTypedDataUint16ArrayCid: | |
1234 case kTypedDataInt32ArrayCid: | |
1235 case kTypedDataUint32ArrayCid: | |
1236 case kTypedDataFloat32ArrayCid: | |
1237 case kTypedDataFloat64ArrayCid: | |
1238 case kTypedDataFloat32x4ArrayCid: | |
1239 case kTypedDataInt32x4ArrayCid: | |
1240 return true; | |
1241 default: | |
1242 return false; | |
1243 } | |
1244 } | |
1245 | |
1246 | |
1247 // Inline only simple, frequently called core library methods. | 1225 // Inline only simple, frequently called core library methods. |
1248 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1226 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
1249 ASSERT(call->HasICData()); | 1227 ASSERT(call->HasICData()); |
1250 const ICData& ic_data = *call->ic_data(); | 1228 const ICData& ic_data = *call->ic_data(); |
1251 if (ic_data.NumberOfUsedChecks() != 1) { | 1229 if (ic_data.NumberOfUsedChecks() != 1) { |
1252 // No type feedback collected or multiple targets found. | 1230 // No type feedback collected or multiple targets found. |
1253 return false; | 1231 return false; |
1254 } | 1232 } |
1255 | 1233 |
1256 Function& target = Function::Handle(Z); | 1234 Function& target = Function::Handle(Z); |
1257 GrowableArray<intptr_t> class_ids; | 1235 GrowableArray<intptr_t> class_ids; |
1258 ic_data.GetCheckAt(0, &class_ids, &target); | 1236 ic_data.GetCheckAt(0, &class_ids, &target); |
1259 MethodRecognizer::Kind recognized_kind = | 1237 MethodRecognizer::Kind recognized_kind = |
1260 MethodRecognizer::RecognizeKind(target); | 1238 MethodRecognizer::RecognizeKind(target); |
1261 | 1239 |
1262 if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) || | |
1263 (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) || | |
1264 (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) || | |
1265 (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) || | |
1266 (recognized_kind == MethodRecognizer::kGrowableArraySetData) || | |
1267 (recognized_kind == MethodRecognizer::kGrowableArraySetLength) || | |
1268 (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) { | |
1269 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1270 flow_graph_, current_iterator(), call); | |
1271 } | |
1272 | |
1273 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { | |
1274 ASSERT((class_ids[0] == kOneByteStringCid) || | |
1275 (class_ids[0] == kTwoByteStringCid) || | |
1276 (class_ids[0] == kExternalOneByteStringCid) || | |
1277 (class_ids[0] == kExternalTwoByteStringCid)); | |
1278 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1279 flow_graph_, current_iterator(), call); | |
1280 } | |
1281 | |
1282 if (class_ids[0] == kOneByteStringCid) { | |
1283 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | |
1284 // This is an internal method, no need to check argument types nor | |
1285 // range. | |
1286 Definition* str = call->ArgumentAt(0); | |
1287 Definition* index = call->ArgumentAt(1); | |
1288 Definition* value = call->ArgumentAt(2); | |
1289 StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr( | |
1290 new(Z) Value(str), | |
1291 new(Z) Value(index), | |
1292 new(Z) Value(value), | |
1293 kNoStoreBarrier, | |
1294 1, // Index scale | |
1295 kOneByteStringCid, | |
1296 call->deopt_id(), | |
1297 call->token_pos()); | |
1298 ReplaceCall(call, store_op); | |
1299 return true; | |
1300 } | |
1301 return false; | |
1302 } | |
1303 | |
1304 if (CanUnboxDouble() && | 1240 if (CanUnboxDouble() && |
1305 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { | 1241 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { |
1306 if (class_ids[0] == kSmiCid) { | 1242 if (class_ids[0] == kSmiCid) { |
1307 AddReceiverCheck(call); | 1243 AddReceiverCheck(call); |
1308 ReplaceCall(call, | 1244 ReplaceCall(call, |
1309 new(Z) SmiToDoubleInstr( | 1245 new(Z) SmiToDoubleInstr( |
1310 new(Z) Value(call->ArgumentAt(0)), | 1246 new(Z) Value(call->ArgumentAt(0)), |
1311 call->token_pos())); | 1247 call->token_pos())); |
1312 return true; | 1248 return true; |
1313 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { | 1249 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1352 if (!TargetCPUFeatures::double_truncate_round_supported()) { | 1288 if (!TargetCPUFeatures::double_truncate_round_supported()) { |
1353 ReplaceWithMathCFunction(call, recognized_kind); | 1289 ReplaceWithMathCFunction(call, recognized_kind); |
1354 } else { | 1290 } else { |
1355 AddReceiverCheck(call); | 1291 AddReceiverCheck(call); |
1356 DoubleToDoubleInstr* d2d_instr = | 1292 DoubleToDoubleInstr* d2d_instr = |
1357 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), | 1293 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), |
1358 recognized_kind, call->deopt_id()); | 1294 recognized_kind, call->deopt_id()); |
1359 ReplaceCall(call, d2d_instr); | 1295 ReplaceCall(call, d2d_instr); |
1360 } | 1296 } |
1361 return true; | 1297 return true; |
1362 case MethodRecognizer::kDoubleAdd: | |
1363 case MethodRecognizer::kDoubleSub: | |
1364 case MethodRecognizer::kDoubleMul: | |
1365 case MethodRecognizer::kDoubleDiv: | |
1366 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1367 flow_graph_, current_iterator(), call); | |
1368 default: | 1298 default: |
1369 // Unsupported method. | 1299 break; |
1370 return false; | |
1371 } | 1300 } |
1372 } | 1301 } |
1373 | 1302 |
1374 if (IsSupportedByteArrayViewCid(class_ids[0]) || | 1303 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
1375 (class_ids[0] == kFloat32x4Cid) || | 1304 flow_graph_, current_iterator(), call); |
1376 (class_ids[0] == kInt32x4Cid) || | |
1377 (class_ids[0] == kFloat64x2Cid)) { | |
1378 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1379 flow_graph_, current_iterator(), call); | |
1380 } | |
1381 | |
1382 return false; | |
1383 } | 1305 } |
1384 | 1306 |
1385 | 1307 |
1386 // If type tests specified by 'ic_data' do not depend on type arguments, | 1308 // If type tests specified by 'ic_data' do not depend on type arguments, |
1387 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 1309 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
1388 // If all tests yield the same result, return it otherwise return Bool::null. | 1310 // If all tests yield the same result, return it otherwise return Bool::null. |
1389 // If no mapping is possible, 'results' is empty. | 1311 // If no mapping is possible, 'results' is empty. |
1390 // An instance-of test returning all same results can be converted to a class | 1312 // An instance-of test returning all same results can be converted to a class |
1391 // check. | 1313 // check. |
1392 RawBool* JitOptimizer::InstanceOfAsBool( | 1314 RawBool* JitOptimizer::InstanceOfAsBool( |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1816 PolymorphicInstanceCallInstr* call = | 1738 PolymorphicInstanceCallInstr* call = |
1817 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 1739 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
1818 call_with_checks, | 1740 call_with_checks, |
1819 /* complete = */ false); | 1741 /* complete = */ false); |
1820 instr->ReplaceWith(call, current_iterator()); | 1742 instr->ReplaceWith(call, current_iterator()); |
1821 } | 1743 } |
1822 } | 1744 } |
1823 | 1745 |
1824 | 1746 |
1825 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1747 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
1826 if (!CanUnboxDouble()) { | |
1827 return; | |
1828 } | |
1829 MethodRecognizer::Kind recognized_kind = | 1748 MethodRecognizer::Kind recognized_kind = |
1830 MethodRecognizer::RecognizeKind(call->function()); | 1749 MethodRecognizer::RecognizeKind(call->function()); |
1831 MathUnaryInstr::MathUnaryKind unary_kind; | |
1832 switch (recognized_kind) { | 1750 switch (recognized_kind) { |
1833 case MethodRecognizer::kMathSqrt: | 1751 case MethodRecognizer::kObjectConstructor: |
1834 unary_kind = MathUnaryInstr::kSqrt; | 1752 case MethodRecognizer::kObjectArrayAllocate: |
1835 break; | |
1836 case MethodRecognizer::kMathSin: | |
1837 unary_kind = MathUnaryInstr::kSin; | |
1838 break; | |
1839 case MethodRecognizer::kMathCos: | |
1840 unary_kind = MathUnaryInstr::kCos; | |
1841 break; | |
1842 default: | |
1843 unary_kind = MathUnaryInstr::kIllegal; | |
1844 break; | |
1845 } | |
1846 if (unary_kind != MathUnaryInstr::kIllegal) { | |
1847 MathUnaryInstr* math_unary = | |
1848 new(Z) MathUnaryInstr(unary_kind, | |
1849 new(Z) Value(call->ArgumentAt(0)), | |
1850 call->deopt_id()); | |
1851 ReplaceCall(call, math_unary); | |
1852 return; | |
1853 } | |
1854 switch (recognized_kind) { | |
1855 case MethodRecognizer::kFloat32x4Zero: | 1753 case MethodRecognizer::kFloat32x4Zero: |
1856 case MethodRecognizer::kFloat32x4Splat: | 1754 case MethodRecognizer::kFloat32x4Splat: |
1857 case MethodRecognizer::kFloat32x4Constructor: | 1755 case MethodRecognizer::kFloat32x4Constructor: |
1858 case MethodRecognizer::kFloat32x4FromFloat64x2: | 1756 case MethodRecognizer::kFloat32x4FromFloat64x2: |
1859 case MethodRecognizer::kFloat64x2Constructor: | 1757 case MethodRecognizer::kFloat64x2Constructor: |
1860 case MethodRecognizer::kFloat64x2Zero: | 1758 case MethodRecognizer::kFloat64x2Zero: |
1861 case MethodRecognizer::kFloat64x2Splat: | 1759 case MethodRecognizer::kFloat64x2Splat: |
1862 case MethodRecognizer::kFloat64x2FromFloat32x4: | 1760 case MethodRecognizer::kFloat64x2FromFloat32x4: |
1863 case MethodRecognizer::kInt32x4BoolConstructor: | 1761 case MethodRecognizer::kInt32x4BoolConstructor: |
1864 case MethodRecognizer::kInt32x4Constructor: | 1762 case MethodRecognizer::kInt32x4Constructor: |
| 1763 case MethodRecognizer::kMathSqrt: |
| 1764 case MethodRecognizer::kMathDoublePow: |
| 1765 case MethodRecognizer::kMathSin: |
| 1766 case MethodRecognizer::kMathCos: |
| 1767 case MethodRecognizer::kMathTan: |
| 1768 case MethodRecognizer::kMathAsin: |
| 1769 case MethodRecognizer::kMathAcos: |
| 1770 case MethodRecognizer::kMathAtan: |
| 1771 case MethodRecognizer::kMathAtan2: |
1865 FlowGraphInliner::TryReplaceStaticCallWithInline( | 1772 FlowGraphInliner::TryReplaceStaticCallWithInline( |
1866 flow_graph_, current_iterator(), call); | 1773 flow_graph_, current_iterator(), call); |
1867 break; | 1774 break; |
1868 case MethodRecognizer::kObjectConstructor: { | |
1869 // Remove the original push arguments. | |
1870 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
1871 PushArgumentInstr* push = call->PushArgumentAt(i); | |
1872 push->ReplaceUsesWith(push->value()->definition()); | |
1873 push->RemoveFromGraph(); | |
1874 } | |
1875 // Manually replace call with global null constant. ReplaceCall can't | |
1876 // be used for definitions that are already in the graph. | |
1877 call->ReplaceUsesWith(flow_graph_->constant_null()); | |
1878 ASSERT(current_iterator()->Current() == call); | |
1879 current_iterator()->RemoveCurrentFromGraph(); | |
1880 break; | |
1881 } | |
1882 case MethodRecognizer::kMathMin: | 1775 case MethodRecognizer::kMathMin: |
1883 case MethodRecognizer::kMathMax: { | 1776 case MethodRecognizer::kMathMax: { |
1884 // We can handle only monomorphic min/max call sites with both arguments | 1777 // We can handle only monomorphic min/max call sites with both arguments |
1885 // being either doubles or smis. | 1778 // being either doubles or smis. |
1886 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 1779 if (CanUnboxDouble() && |
| 1780 call->HasICData() && |
| 1781 (call->ic_data()->NumberOfChecks() == 1)) { |
1887 const ICData& ic_data = *call->ic_data(); | 1782 const ICData& ic_data = *call->ic_data(); |
1888 intptr_t result_cid = kIllegalCid; | 1783 intptr_t result_cid = kIllegalCid; |
1889 if (ICDataHasReceiverArgumentClassIds(ic_data, | 1784 if (ICDataHasReceiverArgumentClassIds(ic_data, |
1890 kDoubleCid, kDoubleCid)) { | 1785 kDoubleCid, kDoubleCid)) { |
1891 result_cid = kDoubleCid; | 1786 result_cid = kDoubleCid; |
1892 } else if (ICDataHasReceiverArgumentClassIds(ic_data, | 1787 } else if (ICDataHasReceiverArgumentClassIds(ic_data, |
1893 kSmiCid, kSmiCid)) { | 1788 kSmiCid, kSmiCid)) { |
1894 result_cid = kSmiCid; | 1789 result_cid = kSmiCid; |
1895 } | 1790 } |
1896 if (result_cid != kIllegalCid) { | 1791 if (result_cid != kIllegalCid) { |
(...skipping 13 matching lines...) Expand all Loading... |
1910 AddCheckClass(min_max->right()->definition(), | 1805 AddCheckClass(min_max->right()->definition(), |
1911 unary_checks, | 1806 unary_checks, |
1912 call->deopt_id(), | 1807 call->deopt_id(), |
1913 call->env(), | 1808 call->env(), |
1914 call); | 1809 call); |
1915 ReplaceCall(call, min_max); | 1810 ReplaceCall(call, min_max); |
1916 } | 1811 } |
1917 } | 1812 } |
1918 break; | 1813 break; |
1919 } | 1814 } |
1920 case MethodRecognizer::kMathDoublePow: | 1815 |
1921 case MethodRecognizer::kMathTan: | |
1922 case MethodRecognizer::kMathAsin: | |
1923 case MethodRecognizer::kMathAcos: | |
1924 case MethodRecognizer::kMathAtan: | |
1925 case MethodRecognizer::kMathAtan2: { | |
1926 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble | |
1927 // instructions contain type checks and conversions to double. | |
1928 ZoneGrowableArray<Value*>* args = | |
1929 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | |
1930 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | |
1931 args->Add(new(Z) Value(call->ArgumentAt(i))); | |
1932 } | |
1933 InvokeMathCFunctionInstr* invoke = | |
1934 new(Z) InvokeMathCFunctionInstr(args, | |
1935 call->deopt_id(), | |
1936 recognized_kind, | |
1937 call->token_pos()); | |
1938 ReplaceCall(call, invoke); | |
1939 break; | |
1940 } | |
1941 case MethodRecognizer::kDoubleFromInteger: { | 1816 case MethodRecognizer::kDoubleFromInteger: { |
1942 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 1817 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
1943 const ICData& ic_data = *call->ic_data(); | 1818 const ICData& ic_data = *call->ic_data(); |
1944 if (CanUnboxDouble()) { | 1819 if (CanUnboxDouble()) { |
1945 if (ArgIsAlways(kSmiCid, ic_data, 1)) { | 1820 if (ArgIsAlways(kSmiCid, ic_data, 1)) { |
1946 Definition* arg = call->ArgumentAt(1); | 1821 Definition* arg = call->ArgumentAt(1); |
1947 AddCheckSmi(arg, call->deopt_id(), call->env(), call); | 1822 AddCheckSmi(arg, call->deopt_id(), call->env(), call); |
1948 ReplaceCall(call, | 1823 ReplaceCall(call, |
1949 new(Z) SmiToDoubleInstr(new(Z) Value(arg), | 1824 new(Z) SmiToDoubleInstr(new(Z) Value(arg), |
1950 call->token_pos())); | 1825 call->token_pos())); |
1951 } else if (ArgIsAlways(kMintCid, ic_data, 1) && | 1826 } else if (ArgIsAlways(kMintCid, ic_data, 1) && |
1952 CanConvertUnboxedMintToDouble()) { | 1827 CanConvertUnboxedMintToDouble()) { |
1953 Definition* arg = call->ArgumentAt(1); | 1828 Definition* arg = call->ArgumentAt(1); |
1954 ReplaceCall(call, | 1829 ReplaceCall(call, |
1955 new(Z) MintToDoubleInstr(new(Z) Value(arg), | 1830 new(Z) MintToDoubleInstr(new(Z) Value(arg), |
1956 call->deopt_id())); | 1831 call->deopt_id())); |
1957 } | 1832 } |
1958 } | 1833 } |
1959 } | 1834 } |
1960 break; | 1835 break; |
1961 } | 1836 } |
1962 default: { | 1837 default: |
1963 if (call->function().IsFactory()) { | 1838 break; |
1964 const Class& function_class = | |
1965 Class::Handle(Z, call->function().Owner()); | |
1966 if ((function_class.library() == Library::CoreLibrary()) || | |
1967 (function_class.library() == Library::TypedDataLibrary())) { | |
1968 intptr_t cid = FactoryRecognizer::ResultCid(call->function()); | |
1969 switch (cid) { | |
1970 case kArrayCid: { | |
1971 Value* type = new(Z) Value(call->ArgumentAt(0)); | |
1972 Value* num_elements = new(Z) Value(call->ArgumentAt(1)); | |
1973 if (num_elements->BindsToConstant() && | |
1974 num_elements->BoundConstant().IsSmi()) { | |
1975 intptr_t length = | |
1976 Smi::Cast(num_elements->BoundConstant()).Value(); | |
1977 if (length >= 0 && length <= Array::kMaxElements) { | |
1978 CreateArrayInstr* create_array = | |
1979 new(Z) CreateArrayInstr( | |
1980 call->token_pos(), type, num_elements); | |
1981 ReplaceCall(call, create_array); | |
1982 } | |
1983 } | |
1984 } | |
1985 default: | |
1986 break; | |
1987 } | |
1988 } | |
1989 } | |
1990 } | |
1991 } | 1839 } |
1992 } | 1840 } |
1993 | 1841 |
1994 | 1842 |
1995 void JitOptimizer::VisitStoreInstanceField( | 1843 void JitOptimizer::VisitStoreInstanceField( |
1996 StoreInstanceFieldInstr* instr) { | 1844 StoreInstanceFieldInstr* instr) { |
1997 if (instr->IsUnboxedStore()) { | 1845 if (instr->IsUnboxedStore()) { |
1998 // Determine if this field should be unboxed based on the usage of getter | 1846 // Determine if this field should be unboxed based on the usage of getter |
1999 // and setter functions: The heuristic requires that the setter has a | 1847 // and setter functions: The heuristic requires that the setter has a |
2000 // usage count of at least 1/kGetterSetterRatio of the getter usage count. | 1848 // usage count of at least 1/kGetterSetterRatio of the getter usage count. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2165 | 2013 |
2166 // Discard the environment from the original instruction because the store | 2014 // Discard the environment from the original instruction because the store |
2167 // can't deoptimize. | 2015 // can't deoptimize. |
2168 instr->RemoveEnvironment(); | 2016 instr->RemoveEnvironment(); |
2169 ReplaceCall(instr, store); | 2017 ReplaceCall(instr, store); |
2170 return true; | 2018 return true; |
2171 } | 2019 } |
2172 | 2020 |
2173 | 2021 |
2174 } // namespace dart | 2022 } // namespace dart |
OLD | NEW |