| 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 #ifndef DART_PRECOMPILED_RUNTIME | 4 #ifndef DART_PRECOMPILED_RUNTIME |
| 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 1317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1328 return true; // May deoptimize since we have not identified all 'true' tests. | 1328 return true; // May deoptimize since we have not identified all 'true' tests. |
| 1329 } | 1329 } |
| 1330 | 1330 |
| 1331 | 1331 |
| 1332 // TODO(srdjan): Use ICData to check if always true or false. | 1332 // TODO(srdjan): Use ICData to check if always true or false. |
| 1333 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 1333 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 1334 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 1334 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 1335 Definition* left = call->ArgumentAt(0); | 1335 Definition* left = call->ArgumentAt(0); |
| 1336 Definition* type_args = NULL; | 1336 Definition* type_args = NULL; |
| 1337 AbstractType& type = AbstractType::ZoneHandle(Z); | 1337 AbstractType& type = AbstractType::ZoneHandle(Z); |
| 1338 bool negate = false; | |
| 1339 if (call->ArgumentCount() == 2) { | 1338 if (call->ArgumentCount() == 2) { |
| 1340 type_args = flow_graph()->constant_null(); | 1339 type_args = flow_graph()->constant_null(); |
| 1341 if (call->MatchesCoreName(Symbols::_simpleInstanceOf())) { | 1340 ASSERT(call->MatchesCoreName(Symbols::_simpleInstanceOf())); |
| 1342 type = | 1341 type = AbstractType::Cast(call->ArgumentAt(1)->AsConstant()->value()).raw(); |
| 1343 AbstractType::Cast(call->ArgumentAt(1)->AsConstant()->value()).raw(); | |
| 1344 negate = false; // Just to be sure. | |
| 1345 } else { | |
| 1346 if (call->MatchesCoreName(Symbols::_instanceOfNum())) { | |
| 1347 type = Type::Number(); | |
| 1348 } else if (call->MatchesCoreName(Symbols::_instanceOfInt())) { | |
| 1349 type = Type::IntType(); | |
| 1350 } else if (call->MatchesCoreName(Symbols::_instanceOfSmi())) { | |
| 1351 type = Type::SmiType(); | |
| 1352 } else if (call->MatchesCoreName(Symbols::_instanceOfDouble())) { | |
| 1353 type = Type::Double(); | |
| 1354 } else if (call->MatchesCoreName(Symbols::_instanceOfString())) { | |
| 1355 type = Type::StringType(); | |
| 1356 } else { | |
| 1357 UNIMPLEMENTED(); | |
| 1358 } | |
| 1359 negate = | |
| 1360 Bool::Cast( | |
| 1361 call->ArgumentAt(1)->OriginalDefinition()->AsConstant()->value()) | |
| 1362 .value(); | |
| 1363 } | |
| 1364 } else { | 1342 } else { |
| 1365 type_args = call->ArgumentAt(1); | 1343 type_args = call->ArgumentAt(1); |
| 1366 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); | 1344 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); |
| 1367 negate = | |
| 1368 Bool::Cast( | |
| 1369 call->ArgumentAt(3)->OriginalDefinition()->AsConstant()->value()) | |
| 1370 .value(); | |
| 1371 } | 1345 } |
| 1372 const ICData& unary_checks = | 1346 const ICData& unary_checks = |
| 1373 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | 1347 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 1374 const intptr_t number_of_checks = unary_checks.NumberOfChecks(); | 1348 const intptr_t number_of_checks = unary_checks.NumberOfChecks(); |
| 1375 if ((number_of_checks > 0) && | 1349 if ((number_of_checks > 0) && |
| 1376 (number_of_checks <= FLAG_max_polymorphic_checks)) { | 1350 (number_of_checks <= FLAG_max_polymorphic_checks)) { |
| 1377 ZoneGrowableArray<intptr_t>* results = | 1351 ZoneGrowableArray<intptr_t>* results = |
| 1378 new (Z) ZoneGrowableArray<intptr_t>(number_of_checks * 2); | 1352 new (Z) ZoneGrowableArray<intptr_t>(number_of_checks * 2); |
| 1379 Bool& as_bool = | 1353 Bool& as_bool = |
| 1380 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results)); | 1354 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results)); |
| 1381 if (as_bool.IsNull()) { | 1355 if (as_bool.IsNull()) { |
| 1382 if (results->length() == number_of_checks * 2) { | 1356 if (results->length() == number_of_checks * 2) { |
| 1383 const bool can_deopt = TryExpandTestCidsResult(results, type); | 1357 const bool can_deopt = TryExpandTestCidsResult(results, type); |
| 1384 TestCidsInstr* test_cids = new (Z) TestCidsInstr( | 1358 TestCidsInstr* test_cids = new (Z) TestCidsInstr( |
| 1385 call->token_pos(), negate ? Token::kISNOT : Token::kIS, | 1359 call->token_pos(), Token::kIS, new (Z) Value(left), *results, |
| 1386 new (Z) Value(left), *results, | |
| 1387 can_deopt ? call->deopt_id() : Thread::kNoDeoptId); | 1360 can_deopt ? call->deopt_id() : Thread::kNoDeoptId); |
| 1388 // Remove type. | 1361 // Remove type. |
| 1389 ReplaceCall(call, test_cids); | 1362 ReplaceCall(call, test_cids); |
| 1390 return; | 1363 return; |
| 1391 } | 1364 } |
| 1392 } else { | 1365 } else { |
| 1393 // TODO(srdjan): Use TestCidsInstr also for this case. | 1366 // TODO(srdjan): Use TestCidsInstr also for this case. |
| 1394 // One result only. | 1367 // One result only. |
| 1395 AddReceiverCheck(call); | 1368 AddReceiverCheck(call); |
| 1396 if (negate) { | |
| 1397 as_bool = Bool::Get(!as_bool.value()).raw(); | |
| 1398 } | |
| 1399 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); | 1369 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); |
| 1400 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 1370 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 1401 PushArgumentInstr* push = call->PushArgumentAt(i); | 1371 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 1402 push->ReplaceUsesWith(push->value()->definition()); | 1372 push->ReplaceUsesWith(push->value()->definition()); |
| 1403 push->RemoveFromGraph(); | 1373 push->RemoveFromGraph(); |
| 1404 } | 1374 } |
| 1405 call->ReplaceUsesWith(bool_const); | 1375 call->ReplaceUsesWith(bool_const); |
| 1406 ASSERT(current_iterator()->Current() == call); | 1376 ASSERT(current_iterator()->Current() == call); |
| 1407 current_iterator()->RemoveCurrentFromGraph(); | 1377 current_iterator()->RemoveCurrentFromGraph(); |
| 1408 return; | 1378 return; |
| 1409 } | 1379 } |
| 1410 } | 1380 } |
| 1411 | 1381 |
| 1412 if (TypeCheckAsClassEquality(type)) { | 1382 if (TypeCheckAsClassEquality(type)) { |
| 1413 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left)); | 1383 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left)); |
| 1414 InsertBefore(call, left_cid, NULL, FlowGraph::kValue); | 1384 InsertBefore(call, left_cid, NULL, FlowGraph::kValue); |
| 1415 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id(); | 1385 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id(); |
| 1416 ConstantInstr* cid = | 1386 ConstantInstr* cid = |
| 1417 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); | 1387 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); |
| 1418 | 1388 |
| 1419 StrictCompareInstr* check_cid = new (Z) StrictCompareInstr( | 1389 StrictCompareInstr* check_cid = |
| 1420 call->token_pos(), negate ? Token::kNE_STRICT : Token::kEQ_STRICT, | 1390 new (Z) StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, |
| 1421 new (Z) Value(left_cid), new (Z) Value(cid), | 1391 new (Z) Value(left_cid), new (Z) Value(cid), |
| 1422 false); // No number check. | 1392 false); // No number check. |
| 1423 ReplaceCall(call, check_cid); | 1393 ReplaceCall(call, check_cid); |
| 1424 return; | 1394 return; |
| 1425 } | 1395 } |
| 1426 | 1396 |
| 1427 InstanceOfInstr* instance_of = new (Z) | 1397 InstanceOfInstr* instance_of = |
| 1428 InstanceOfInstr(call->token_pos(), new (Z) Value(left), | 1398 new (Z) InstanceOfInstr(call->token_pos(), new (Z) Value(left), |
| 1429 new (Z) Value(type_args), type, negate, call->deopt_id()); | 1399 new (Z) Value(type_args), type, call->deopt_id()); |
| 1430 ReplaceCall(call, instance_of); | 1400 ReplaceCall(call, instance_of); |
| 1431 } | 1401 } |
| 1432 | 1402 |
| 1433 | 1403 |
| 1434 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 1404 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
| 1435 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 1405 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 1436 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 1406 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 1437 Definition* left = call->ArgumentAt(0); | 1407 Definition* left = call->ArgumentAt(0); |
| 1438 Definition* type_args = call->ArgumentAt(1); | 1408 Definition* type_args = call->ArgumentAt(1); |
| 1439 const AbstractType& type = | 1409 const AbstractType& type = |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1831 // Discard the environment from the original instruction because the store | 1801 // Discard the environment from the original instruction because the store |
| 1832 // can't deoptimize. | 1802 // can't deoptimize. |
| 1833 instr->RemoveEnvironment(); | 1803 instr->RemoveEnvironment(); |
| 1834 ReplaceCall(instr, store); | 1804 ReplaceCall(instr, store); |
| 1835 return true; | 1805 return true; |
| 1836 } | 1806 } |
| 1837 | 1807 |
| 1838 | 1808 |
| 1839 } // namespace dart | 1809 } // namespace dart |
| 1840 #endif // DART_PRECOMPILED_RUNTIME | 1810 #endif // DART_PRECOMPILED_RUNTIME |
| OLD | NEW |