| 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/cha.h" | 7 #include "vm/cha.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/hash_map.h" | 9 #include "vm/hash_map.h" |
| 10 #include "vm/il_printer.h" | 10 #include "vm/il_printer.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { | 169 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { |
| 170 test_target = ic_data.GetTargetAt(i); | 170 test_target = ic_data.GetTargetAt(i); |
| 171 if (first_target.raw() != test_target.raw()) { | 171 if (first_target.raw() != test_target.raw()) { |
| 172 return false; | 172 return false; |
| 173 } | 173 } |
| 174 } | 174 } |
| 175 return true; | 175 return true; |
| 176 } | 176 } |
| 177 | 177 |
| 178 | 178 |
| 179 static intptr_t ReceiverClassId(Computation* comp) { | 179 static intptr_t ReceiverClassId(InstanceCallComp* comp) { |
| 180 if (!comp->HasICData()) return kIllegalCid; | 180 if (!comp->HasICData()) return kIllegalCid; |
| 181 | 181 |
| 182 const ICData& ic_data = *comp->ic_data(); | 182 const ICData& ic_data = *comp->ic_data(); |
| 183 | 183 |
| 184 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; | 184 if (ic_data.NumberOfChecks() == 0) return kIllegalCid; |
| 185 // TODO(vegorov): Add multiple receiver type support. | 185 // TODO(vegorov): Add multiple receiver type support. |
| 186 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; | 186 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; |
| 187 ASSERT(HasOneTarget(ic_data)); | 187 ASSERT(HasOneTarget(ic_data)); |
| 188 | 188 |
| 189 Function& target = Function::Handle(); | 189 Function& target = Function::Handle(); |
| 190 intptr_t class_id; | 190 intptr_t class_id; |
| 191 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 191 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 192 return class_id; | 192 return class_id; |
| 193 } | 193 } |
| 194 | 194 |
| 195 | 195 |
| 196 void FlowGraphOptimizer::AddCheckClass(BindInstr* instr, | 196 void FlowGraphOptimizer::AddCheckClass(BindInstr* instr, |
| 197 InstanceCallComp* comp, | 197 InstanceCallComp* comp, |
| 198 Value* value) { | 198 Value* value) { |
| 199 // Type propagation has not run yet, we cannot eliminate the check. | 199 // Type propagation has not run yet, we cannot eliminate the check. |
| 200 CheckClassComp* check = new CheckClassComp(value, comp); | |
| 201 const ICData& unary_checks = | 200 const ICData& unary_checks = |
| 202 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 201 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 203 check->set_ic_data(&unary_checks); | 202 CheckClassComp* check = new CheckClassComp(value, comp, unary_checks); |
| 204 InsertBefore(instr, check, instr->env(), BindInstr::kUnused); | 203 InsertBefore(instr, check, instr->env(), BindInstr::kUnused); |
| 205 } | 204 } |
| 206 | 205 |
| 207 | 206 |
| 208 bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, | 207 bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, |
| 209 InstanceCallComp* comp, | 208 InstanceCallComp* comp, |
| 210 Token::Kind op_kind) { | 209 Token::Kind op_kind) { |
| 211 // TODO(fschneider): Optimize []= operator in checked mode as well. | 210 // TODO(fschneider): Optimize []= operator in checked mode as well. |
| 212 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; | 211 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; |
| 213 | 212 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 237 comp), | 236 comp), |
| 238 instr->env(), | 237 instr->env(), |
| 239 BindInstr::kUnused); | 238 BindInstr::kUnused); |
| 240 Computation* array_op = NULL; | 239 Computation* array_op = NULL; |
| 241 if (op_kind == Token::kINDEX) { | 240 if (op_kind == Token::kINDEX) { |
| 242 array_op = new LoadIndexedComp(array, index, class_id); | 241 array_op = new LoadIndexedComp(array, index, class_id); |
| 243 } else { | 242 } else { |
| 244 Value* value = comp->ArgumentAt(2)->value(); | 243 Value* value = comp->ArgumentAt(2)->value(); |
| 245 array_op = new StoreIndexedComp(array, index, value, class_id); | 244 array_op = new StoreIndexedComp(array, index, value, class_id); |
| 246 } | 245 } |
| 247 array_op->set_ic_data(comp->ic_data()); | |
| 248 instr->set_computation(array_op); | 246 instr->set_computation(array_op); |
| 249 RemovePushArguments(comp); | 247 RemovePushArguments(comp); |
| 250 return true; | 248 return true; |
| 251 } | 249 } |
| 252 default: | 250 default: |
| 253 return false; | 251 return false; |
| 254 } | 252 } |
| 255 } | 253 } |
| 256 | 254 |
| 257 | 255 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 BindInstr* unbox_right = InsertBefore( | 352 BindInstr* unbox_right = InsertBefore( |
| 355 instr, | 353 instr, |
| 356 new UnboxDoubleComp(right->Copy(), comp), | 354 new UnboxDoubleComp(right->Copy(), comp), |
| 357 instr->env(), | 355 instr->env(), |
| 358 BindInstr::kUsed); | 356 BindInstr::kUsed); |
| 359 | 357 |
| 360 UnboxedDoubleBinaryOpComp* double_bin_op = | 358 UnboxedDoubleBinaryOpComp* double_bin_op = |
| 361 new UnboxedDoubleBinaryOpComp(op_kind, | 359 new UnboxedDoubleBinaryOpComp(op_kind, |
| 362 new Value(unbox_left), | 360 new Value(unbox_left), |
| 363 new Value(unbox_right)); | 361 new Value(unbox_right)); |
| 364 double_bin_op->set_ic_data(comp->ic_data()); | |
| 365 instr->set_computation(double_bin_op); | 362 instr->set_computation(double_bin_op); |
| 366 | 363 |
| 367 if (instr->is_used()) { | 364 if (instr->is_used()) { |
| 368 // Box result. | 365 // Box result. |
| 369 Value* value = new Value(instr); | 366 Value* value = new Value(instr); |
| 370 BindInstr* bind = InsertAfter(instr, | 367 BindInstr* bind = InsertAfter(instr, |
| 371 new BoxDoubleComp(value, comp), | 368 new BoxDoubleComp(value, comp), |
| 372 NULL, | 369 NULL, |
| 373 BindInstr::kUsed); | 370 BindInstr::kUsed); |
| 374 instr->ReplaceUsesWith(bind); | 371 instr->ReplaceUsesWith(bind); |
| 375 } | 372 } |
| 376 | 373 |
| 377 RemovePushArguments(comp); | 374 RemovePushArguments(comp); |
| 378 } else { | 375 } else { |
| 379 BinaryDoubleOpComp* double_bin_op = new BinaryDoubleOpComp(op_kind, comp); | 376 BinaryDoubleOpComp* double_bin_op = new BinaryDoubleOpComp(op_kind, comp); |
| 380 double_bin_op->set_ic_data(comp->ic_data()); | |
| 381 instr->set_computation(double_bin_op); | 377 instr->set_computation(double_bin_op); |
| 382 } | 378 } |
| 383 } else if (operands_type == kMintCid) { | 379 } else if (operands_type == kMintCid) { |
| 384 Value* left = comp->ArgumentAt(0)->value(); | 380 Value* left = comp->ArgumentAt(0)->value(); |
| 385 Value* right = comp->ArgumentAt(1)->value(); | 381 Value* right = comp->ArgumentAt(1)->value(); |
| 386 BinaryMintOpComp* bin_op = new BinaryMintOpComp(op_kind, | 382 BinaryMintOpComp* bin_op = new BinaryMintOpComp(op_kind, |
| 387 comp, | 383 comp, |
| 388 left, | 384 left, |
| 389 right); | 385 right); |
| 390 bin_op->set_ic_data(comp->ic_data()); | |
| 391 instr->set_computation(bin_op); | 386 instr->set_computation(bin_op); |
| 392 RemovePushArguments(comp); | 387 RemovePushArguments(comp); |
| 393 } else { | 388 } else { |
| 394 ASSERT(operands_type == kSmiCid); | 389 ASSERT(operands_type == kSmiCid); |
| 395 Value* left = comp->ArgumentAt(0)->value(); | 390 Value* left = comp->ArgumentAt(0)->value(); |
| 396 Value* right = comp->ArgumentAt(1)->value(); | 391 Value* right = comp->ArgumentAt(1)->value(); |
| 397 // Insert two smi checks and attach a copy of the original | 392 // Insert two smi checks and attach a copy of the original |
| 398 // environment because the smi operation can still deoptimize. | 393 // environment because the smi operation can still deoptimize. |
| 399 InsertBefore(instr, | 394 InsertBefore(instr, |
| 400 new CheckSmiComp(left->Copy(), comp), | 395 new CheckSmiComp(left->Copy(), comp), |
| 401 instr->env(), | 396 instr->env(), |
| 402 BindInstr::kUnused); | 397 BindInstr::kUnused); |
| 403 InsertBefore(instr, | 398 InsertBefore(instr, |
| 404 new CheckSmiComp(right->Copy(), comp), | 399 new CheckSmiComp(right->Copy(), comp), |
| 405 instr->env(), | 400 instr->env(), |
| 406 BindInstr::kUnused); | 401 BindInstr::kUnused); |
| 407 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, | 402 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, |
| 408 comp, | 403 comp, |
| 409 left, | 404 left, |
| 410 right); | 405 right); |
| 411 bin_op->set_ic_data(comp->ic_data()); | |
| 412 instr->set_computation(bin_op); | 406 instr->set_computation(bin_op); |
| 413 RemovePushArguments(comp); | 407 RemovePushArguments(comp); |
| 414 } | 408 } |
| 415 return true; | 409 return true; |
| 416 } | 410 } |
| 417 | 411 |
| 418 | 412 |
| 419 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, | 413 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, |
| 420 InstanceCallComp* comp, | 414 InstanceCallComp* comp, |
| 421 Token::Kind op_kind) { | 415 Token::Kind op_kind) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 432 instr->env(), | 426 instr->env(), |
| 433 BindInstr::kUnused); | 427 BindInstr::kUnused); |
| 434 unary_op = new UnarySmiOpComp(op_kind, | 428 unary_op = new UnarySmiOpComp(op_kind, |
| 435 (op_kind == Token::kNEGATE) ? comp : NULL, | 429 (op_kind == Token::kNEGATE) ? comp : NULL, |
| 436 value); | 430 value); |
| 437 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { | 431 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
| 438 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); | 432 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); |
| 439 } | 433 } |
| 440 if (unary_op == NULL) return false; | 434 if (unary_op == NULL) return false; |
| 441 | 435 |
| 442 unary_op->set_ic_data(comp->ic_data()); | |
| 443 instr->set_computation(unary_op); | 436 instr->set_computation(unary_op); |
| 444 RemovePushArguments(comp); | 437 RemovePushArguments(comp); |
| 445 return true; | 438 return true; |
| 446 } | 439 } |
| 447 | 440 |
| 448 | 441 |
| 449 // Using field class | 442 // Using field class |
| 450 static RawField* GetField(intptr_t class_id, const String& field_name) { | 443 static RawField* GetField(intptr_t class_id, const String& field_name) { |
| 451 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); | 444 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); |
| 452 Field& field = Field::Handle(); | 445 Field& field = Field::Handle(); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 if (HasOneTarget(unary_checks) && | 617 if (HasOneTarget(unary_checks) && |
| 625 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { | 618 (unary_checks.GetReceiverClassIdAt(0) != kSmiCid)) { |
| 626 // Type propagation has not run yet, we cannot eliminate the check. | 619 // Type propagation has not run yet, we cannot eliminate the check. |
| 627 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); | 620 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()->Copy()); |
| 628 // Call can still deoptimize, do not detach environment from instr. | 621 // Call can still deoptimize, do not detach environment from instr. |
| 629 call_with_checks = false; | 622 call_with_checks = false; |
| 630 } else { | 623 } else { |
| 631 call_with_checks = true; | 624 call_with_checks = true; |
| 632 } | 625 } |
| 633 PolymorphicInstanceCallComp* call = | 626 PolymorphicInstanceCallComp* call = |
| 634 new PolymorphicInstanceCallComp(comp, call_with_checks); | 627 new PolymorphicInstanceCallComp(comp, |
| 635 call->set_ic_data(&unary_checks); | 628 unary_checks, |
| 629 call_with_checks); |
| 636 instr->set_computation(call); | 630 instr->set_computation(call); |
| 637 } | 631 } |
| 638 } | 632 } |
| 639 // An instance call without ICData should continue calling via IC calls | 633 // An instance call without ICData should continue calling via IC calls |
| 640 // which should trigger reoptimization of optimized code. | 634 // which should trigger reoptimization of optimized code. |
| 641 } | 635 } |
| 642 | 636 |
| 643 | 637 |
| 644 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp, | 638 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp, |
| 645 BindInstr* instr) { | 639 BindInstr* instr) { |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. | 1060 DirectChainedHashMap<BindInstr*> child_map(*map); // Copy map. |
| 1067 OptimizeRecursive(child, &child_map); | 1061 OptimizeRecursive(child, &child_map); |
| 1068 } else { | 1062 } else { |
| 1069 OptimizeRecursive(child, map); // Reuse map for the last child. | 1063 OptimizeRecursive(child, map); // Reuse map for the last child. |
| 1070 } | 1064 } |
| 1071 } | 1065 } |
| 1072 } | 1066 } |
| 1073 | 1067 |
| 1074 | 1068 |
| 1075 } // namespace dart | 1069 } // namespace dart |
| OLD | NEW |