| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 420 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 421 return class_id; | 421 return class_id; |
| 422 } | 422 } |
| 423 | 423 |
| 424 | 424 |
| 425 void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call, | 425 void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call, |
| 426 Value* value) { | 426 Value* value) { |
| 427 // Type propagation has not run yet, we cannot eliminate the check. | 427 // Type propagation has not run yet, we cannot eliminate the check. |
| 428 const ICData& unary_checks = | 428 const ICData& unary_checks = |
| 429 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 429 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 430 CheckClassInstr* check = | 430 Instruction* check = NULL; |
| 431 new CheckClassInstr(value, call->deopt_id(), unary_checks); | 431 if ((unary_checks.NumberOfChecks() == 1) && |
| 432 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { |
| 433 check = new CheckSmiInstr(value, call->deopt_id()); |
| 434 } else { |
| 435 check = new CheckClassInstr(value, call->deopt_id(), unary_checks); |
| 436 } |
| 432 InsertBefore(call, check, call->env(), Definition::kEffect); | 437 InsertBefore(call, check, call->env(), Definition::kEffect); |
| 433 } | 438 } |
| 434 | 439 |
| 435 | 440 |
| 436 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { | 441 static bool ArgIsAlwaysSmi(const ICData& ic_data, intptr_t arg_n) { |
| 437 ASSERT(ic_data.num_args_tested() > arg_n); | 442 ASSERT(ic_data.num_args_tested() > arg_n); |
| 438 if (ic_data.NumberOfChecks() == 0) return false; | 443 if (ic_data.NumberOfChecks() == 0) return false; |
| 439 GrowableArray<intptr_t> class_ids; | 444 GrowableArray<intptr_t> class_ids; |
| 440 Function& target = Function::Handle(); | 445 Function& target = Function::Handle(); |
| 441 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 446 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 InsertBefore(call, elements, NULL, Definition::kValue); | 489 InsertBefore(call, elements, NULL, Definition::kValue); |
| 485 *array = new Value(elements); | 490 *array = new Value(elements); |
| 486 return kArrayCid; | 491 return kArrayCid; |
| 487 } | 492 } |
| 488 return class_id; | 493 return class_id; |
| 489 } | 494 } |
| 490 | 495 |
| 491 | 496 |
| 492 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { | 497 bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
| 493 const intptr_t class_id = ReceiverClassId(call); | 498 const intptr_t class_id = ReceiverClassId(call); |
| 494 ICData& value_check = ICData::Handle(); | 499 ICData& value_check = ICData::ZoneHandle(); |
| 495 switch (class_id) { | 500 switch (class_id) { |
| 496 case kArrayCid: | 501 case kArrayCid: |
| 497 case kGrowableObjectArrayCid: | 502 case kGrowableObjectArrayCid: |
| 498 // Acceptable store index classes. | 503 // Acceptable store index classes. |
| 499 break; | 504 break; |
| 500 case kFloat32ArrayCid: | 505 case kFloat32ArrayCid: |
| 501 case kFloat64ArrayCid: { | 506 case kFloat64ArrayCid: { |
| 502 // Check that value is always double. | 507 // Check that value is always double. |
| 503 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 508 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 504 if ((value_check.NumberOfChecks() != 1) || | 509 if ((value_check.NumberOfChecks() != 1) || |
| (...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 const bool call_with_checks = false; | 1144 const bool call_with_checks = false; |
| 1140 PolymorphicInstanceCallInstr* call = | 1145 PolymorphicInstanceCallInstr* call = |
| 1141 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1146 new PolymorphicInstanceCallInstr(instr, unary_checks, |
| 1142 call_with_checks); | 1147 call_with_checks); |
| 1143 instr->ReplaceWith(call, current_iterator()); | 1148 instr->ReplaceWith(call, current_iterator()); |
| 1144 return; | 1149 return; |
| 1145 } | 1150 } |
| 1146 const intptr_t kMaxChecks = 4; | 1151 const intptr_t kMaxChecks = 4; |
| 1147 if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) { | 1152 if (instr->ic_data()->NumberOfChecks() <= kMaxChecks) { |
| 1148 bool call_with_checks; | 1153 bool call_with_checks; |
| 1149 // TODO(srdjan): Add check class instr for mixed smi/non-smi. | 1154 if (unary_checks.HasOneTarget()) { |
| 1150 if (unary_checks.HasOneTarget() && | |
| 1151 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { | |
| 1152 // Type propagation has not run yet, we cannot eliminate the check. | 1155 // Type propagation has not run yet, we cannot eliminate the check. |
| 1153 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1156 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); |
| 1154 // Call can still deoptimize, do not detach environment from instr. | 1157 // Call can still deoptimize, do not detach environment from instr. |
| 1155 call_with_checks = false; | 1158 call_with_checks = false; |
| 1156 } else { | 1159 } else { |
| 1157 call_with_checks = true; | 1160 call_with_checks = true; |
| 1158 } | 1161 } |
| 1159 PolymorphicInstanceCallInstr* call = | 1162 PolymorphicInstanceCallInstr* call = |
| 1160 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1163 new PolymorphicInstanceCallInstr(instr, unary_checks, |
| 1161 call_with_checks); | 1164 call_with_checks); |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1332 | 1335 |
| 1333 // Check if ICDData contains checks with Smi/Null combinations. In that case | 1336 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 1334 // we can still emit the optimized Smi equality operation but need to add | 1337 // we can still emit the optimized Smi equality operation but need to add |
| 1335 // checks for null or Smi. | 1338 // checks for null or Smi. |
| 1336 // TODO(srdjan): Add it for Double and Mint. | 1339 // TODO(srdjan): Add it for Double and Mint. |
| 1337 GrowableArray<intptr_t> smi_or_null(2); | 1340 GrowableArray<intptr_t> smi_or_null(2); |
| 1338 smi_or_null.Add(kSmiCid); | 1341 smi_or_null.Add(kSmiCid); |
| 1339 smi_or_null.Add(kNullCid); | 1342 smi_or_null.Add(kNullCid); |
| 1340 if (ICDataHasOnlyReceiverArgumentClassIds( | 1343 if (ICDataHasOnlyReceiverArgumentClassIds( |
| 1341 *comp->ic_data(), smi_or_null, smi_or_null)) { | 1344 *comp->ic_data(), smi_or_null, smi_or_null)) { |
| 1342 ICData& unary_checks = | 1345 const ICData& unary_checks_0 = |
| 1343 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 1346 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 1344 const intptr_t deopt_id = comp->deopt_id(); | 1347 const intptr_t deopt_id = comp->deopt_id(); |
| 1345 if ((unary_checks.NumberOfChecks() == 1) && | 1348 if ((unary_checks_0.NumberOfChecks() == 1) && |
| 1346 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { | 1349 (unary_checks_0.GetReceiverClassIdAt(0) == kSmiCid)) { |
| 1347 // Smi only. | 1350 // Smi only. |
| 1348 optimizer->InsertBefore( | 1351 optimizer->InsertBefore( |
| 1349 instr, | 1352 instr, |
| 1350 new CheckSmiInstr(comp->left()->Copy(), deopt_id), | 1353 new CheckSmiInstr(comp->left()->Copy(), deopt_id), |
| 1351 instr->env(), | 1354 instr->env(), |
| 1352 Definition::kEffect); | 1355 Definition::kEffect); |
| 1353 } else { | 1356 } else { |
| 1354 // Smi or NULL. | 1357 // Smi or NULL. |
| 1355 optimizer->InsertBefore( | 1358 optimizer->InsertBefore( |
| 1356 instr, | 1359 instr, |
| 1357 new CheckClassInstr(comp->left()->Copy(), deopt_id, unary_checks), | 1360 new CheckClassInstr(comp->left()->Copy(), deopt_id, unary_checks_0), |
| 1358 instr->env(), | 1361 instr->env(), |
| 1359 Definition::kEffect); | 1362 Definition::kEffect); |
| 1360 } | 1363 } |
| 1361 | 1364 |
| 1362 unary_checks = comp->ic_data()->AsUnaryClassChecksForArgNr(1); | 1365 const ICData& unary_checks_1 = |
| 1363 if ((unary_checks.NumberOfChecks() == 1) && | 1366 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1364 (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) { | 1367 if ((unary_checks_1.NumberOfChecks() == 1) && |
| 1368 (unary_checks_1.GetReceiverClassIdAt(0) == kSmiCid)) { |
| 1365 // Smi only. | 1369 // Smi only. |
| 1366 optimizer->InsertBefore( | 1370 optimizer->InsertBefore( |
| 1367 instr, | 1371 instr, |
| 1368 new CheckSmiInstr(comp->right()->Copy(), deopt_id), | 1372 new CheckSmiInstr(comp->right()->Copy(), deopt_id), |
| 1369 instr->env(), | 1373 instr->env(), |
| 1370 Definition::kEffect); | 1374 Definition::kEffect); |
| 1371 } else { | 1375 } else { |
| 1372 // Smi or NULL. | 1376 // Smi or NULL. |
| 1373 optimizer->InsertBefore( | 1377 optimizer->InsertBefore( |
| 1374 instr, | 1378 instr, |
| 1375 new CheckClassInstr(comp->right()->Copy(), deopt_id, unary_checks), | 1379 new CheckClassInstr(comp->right()->Copy(), deopt_id, unary_checks_1), |
| 1376 instr->env(), | 1380 instr->env(), |
| 1377 Definition::kEffect); | 1381 Definition::kEffect); |
| 1378 } | 1382 } |
| 1379 comp->set_receiver_class_id(kSmiCid); | 1383 comp->set_receiver_class_id(kSmiCid); |
| 1380 } | 1384 } |
| 1381 } | 1385 } |
| 1382 | 1386 |
| 1383 | 1387 |
| 1384 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | 1388 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 1385 HandleEqualityCompare(this, instr, instr, current_iterator()); | 1389 HandleEqualityCompare(this, instr, instr, current_iterator()); |
| (...skipping 2118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3504 | 3508 |
| 3505 if (FLAG_trace_constant_propagation) { | 3509 if (FLAG_trace_constant_propagation) { |
| 3506 OS::Print("\n==== After constant propagation ====\n"); | 3510 OS::Print("\n==== After constant propagation ====\n"); |
| 3507 FlowGraphPrinter printer(*graph_); | 3511 FlowGraphPrinter printer(*graph_); |
| 3508 printer.PrintBlocks(); | 3512 printer.PrintBlocks(); |
| 3509 } | 3513 } |
| 3510 } | 3514 } |
| 3511 | 3515 |
| 3512 | 3516 |
| 3513 } // namespace dart | 3517 } // namespace dart |
| OLD | NEW |