| 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 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 | 28 |
| 29 void FlowGraphOptimizer::OptimizeComputations() { | 29 void FlowGraphOptimizer::OptimizeComputations() { |
| 30 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 30 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 31 BlockEntryInstr* entry = block_order_[i]; | 31 BlockEntryInstr* entry = block_order_[i]; |
| 32 entry->Accept(this); | 32 entry->Accept(this); |
| 33 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 33 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 34 BindInstr* instr = it.Current()->AsBind(); | 34 BindInstr* instr = it.Current()->AsBind(); |
| 35 if (instr != NULL) { | 35 if (instr != NULL) { |
| 36 Definition* result = instr->computation()->TryReplace(instr); | 36 Definition* result = instr->computation()->TryReplace(instr); |
| 37 if (result != NULL) { | 37 if (result != instr) { |
| 38 // Replace uses and remove the current instructions via the iterator. | 38 if (result != NULL) { |
| 39 instr->ReplaceUsesWith(result); | 39 instr->ReplaceUsesWith(result); |
| 40 if (FLAG_trace_optimization) { |
| 41 OS::Print("Replacing v%d with v%d\n", |
| 42 instr->ssa_temp_index(), |
| 43 result->ssa_temp_index()); |
| 44 } |
| 45 } else if (FLAG_trace_optimization) { |
| 46 OS::Print("Removing v%d.\n", instr->ssa_temp_index()); |
| 47 } |
| 40 it.RemoveCurrentFromGraph(); | 48 it.RemoveCurrentFromGraph(); |
| 41 if (FLAG_trace_optimization) { | |
| 42 OS::Print("Replacing v%d with v%d\n", | |
| 43 instr->ssa_temp_index(), | |
| 44 result->ssa_temp_index()); | |
| 45 } | |
| 46 } | 49 } |
| 47 } | 50 } |
| 48 } | 51 } |
| 49 } | 52 } |
| 50 } | 53 } |
| 51 | 54 |
| 52 | 55 |
| 53 static bool ICDataHasReceiverClassId(const ICData& ic_data, intptr_t class_id) { | 56 static bool ICDataHasReceiverClassId(const ICData& ic_data, intptr_t class_id) { |
| 54 ASSERT(ic_data.num_args_tested() > 0); | 57 ASSERT(ic_data.num_args_tested() > 0); |
| 55 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 58 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; | 190 if (ic_data.NumberOfChecks() != 1) return kIllegalCid; |
| 188 ASSERT(HasOneTarget(ic_data)); | 191 ASSERT(HasOneTarget(ic_data)); |
| 189 | 192 |
| 190 Function& target = Function::Handle(); | 193 Function& target = Function::Handle(); |
| 191 intptr_t class_id; | 194 intptr_t class_id; |
| 192 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 195 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 193 return class_id; | 196 return class_id; |
| 194 } | 197 } |
| 195 | 198 |
| 196 | 199 |
| 200 // Insert a check computation before an instruction and set the environment |
| 201 // of the check to the same as the instruction. |
| 202 static void InsertCheckBefore(BindInstr* instr, |
| 203 Computation* check, |
| 204 Environment* env) { |
| 205 BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check); |
| 206 check_instr->InsertBefore(instr); |
| 207 ASSERT(env != NULL); |
| 208 // Attach an environment to the check instruction. |
| 209 check_instr->set_env(env); |
| 210 } |
| 211 |
| 212 |
| 197 static void AddCheckClass(BindInstr* instr, | 213 static void AddCheckClass(BindInstr* instr, |
| 198 InstanceCallComp* comp, | 214 InstanceCallComp* comp, |
| 199 Value* value) { | 215 Value* value) { |
| 200 // Type propagation has not run yet, we cannot eliminate the check. | 216 // Type propagation has not run yet, we cannot eliminate the check. |
| 201 CheckClassComp* check = new CheckClassComp(value, comp); | 217 CheckClassComp* check = new CheckClassComp(value, comp); |
| 202 const ICData& unary_checks = | 218 const ICData& unary_checks = |
| 203 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 219 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 204 check->set_ic_data(&unary_checks); | 220 check->set_ic_data(&unary_checks); |
| 205 BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check); | 221 InsertCheckBefore(instr, check, instr->env()); |
| 206 ASSERT(instr->env() != NULL); // Always the case with SSA. | 222 // Detach environment from the original instruction because it can't |
| 207 // Attach the original environment to the check instruction. | 223 // deoptimize. |
| 208 check_instr->set_env(instr->env()); | 224 instr->set_env(NULL); |
| 209 check_instr->InsertBefore(instr); | |
| 210 } | 225 } |
| 211 | 226 |
| 212 | 227 |
| 213 bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, | 228 bool FlowGraphOptimizer::TryReplaceWithArrayOp(BindInstr* instr, |
| 214 InstanceCallComp* comp, | 229 InstanceCallComp* comp, |
| 215 Token::Kind op_kind) { | 230 Token::Kind op_kind) { |
| 216 // TODO(fschneider): Optimize []= operator in checked mode as well. | 231 // TODO(fschneider): Optimize []= operator in checked mode as well. |
| 217 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; | 232 if (op_kind == Token::kASSIGN_INDEX && FLAG_enable_type_checks) return false; |
| 218 | 233 |
| 219 const intptr_t class_id = ReceiverClassId(comp); | 234 const intptr_t class_id = ReceiverClassId(comp); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 comp, | 325 comp, |
| 311 left, | 326 left, |
| 312 right); | 327 right); |
| 313 bin_op->set_ic_data(comp->ic_data()); | 328 bin_op->set_ic_data(comp->ic_data()); |
| 314 instr->set_computation(bin_op); | 329 instr->set_computation(bin_op); |
| 315 RemovePushArguments(comp); | 330 RemovePushArguments(comp); |
| 316 } else { | 331 } else { |
| 317 ASSERT(operands_type == kSmiCid); | 332 ASSERT(operands_type == kSmiCid); |
| 318 Value* left = comp->ArgumentAt(0)->value(); | 333 Value* left = comp->ArgumentAt(0)->value(); |
| 319 Value* right = comp->ArgumentAt(1)->value(); | 334 Value* right = comp->ArgumentAt(1)->value(); |
| 335 // Insert two smi checks and attach a copy of the original |
| 336 // environment because the smi operation can still deoptimize. |
| 337 InsertCheckBefore(instr, |
| 338 new CheckSmiComp(left, comp), |
| 339 instr->env()->Copy()); |
| 340 InsertCheckBefore(instr, |
| 341 new CheckSmiComp(right, comp), |
| 342 instr->env()->Copy()); |
| 320 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, | 343 BinarySmiOpComp* bin_op = new BinarySmiOpComp(op_kind, |
| 321 comp, | 344 comp, |
| 322 left, | 345 left, |
| 323 right); | 346 right); |
| 324 bin_op->set_ic_data(comp->ic_data()); | 347 bin_op->set_ic_data(comp->ic_data()); |
| 325 instr->set_computation(bin_op); | 348 instr->set_computation(bin_op); |
| 326 RemovePushArguments(comp); | 349 RemovePushArguments(comp); |
| 327 } | 350 } |
| 328 return true; | 351 return true; |
| 329 } | 352 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 if (target.kind() == RawFunction::kImplicitGetter) { | 407 if (target.kind() == RawFunction::kImplicitGetter) { |
| 385 if (!HasOneTarget(ic_data)) { | 408 if (!HasOneTarget(ic_data)) { |
| 386 // TODO(srdjan): Implement for mutiple targets. | 409 // TODO(srdjan): Implement for mutiple targets. |
| 387 return false; | 410 return false; |
| 388 } | 411 } |
| 389 // Inline implicit instance getter. | 412 // Inline implicit instance getter. |
| 390 const String& field_name = | 413 const String& field_name = |
| 391 String::Handle(Field::NameFromGetter(comp->function_name())); | 414 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 392 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 415 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 393 ASSERT(!field.IsNull()); | 416 ASSERT(!field.IsNull()); |
| 417 |
| 394 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()); | 418 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()); |
| 395 instr->set_env(NULL); | |
| 396 LoadInstanceFieldComp* load = | 419 LoadInstanceFieldComp* load = |
| 397 new LoadInstanceFieldComp(field, | 420 new LoadInstanceFieldComp(field, |
| 398 comp->ArgumentAt(0)->value(), | 421 comp->ArgumentAt(0)->value(), |
| 399 NULL); // Can not deoptimize. | 422 NULL); // Can not deoptimize. |
| 400 instr->set_computation(load); | 423 instr->set_computation(load); |
| 401 RemovePushArguments(comp); | 424 RemovePushArguments(comp); |
| 402 return true; | 425 return true; |
| 403 } | 426 } |
| 404 | 427 |
| 405 // Not an implicit getter. | 428 // Not an implicit getter. |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 // TODO(srdjan): Inline special setters. | 589 // TODO(srdjan): Inline special setters. |
| 567 return false; | 590 return false; |
| 568 } | 591 } |
| 569 // Inline implicit instance setter. | 592 // Inline implicit instance setter. |
| 570 const String& field_name = | 593 const String& field_name = |
| 571 String::Handle(Field::NameFromSetter(comp->function_name())); | 594 String::Handle(Field::NameFromSetter(comp->function_name())); |
| 572 const Field& field = Field::Handle(GetField(class_id, field_name)); | 595 const Field& field = Field::Handle(GetField(class_id, field_name)); |
| 573 ASSERT(!field.IsNull()); | 596 ASSERT(!field.IsNull()); |
| 574 | 597 |
| 575 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()); | 598 AddCheckClass(instr, comp, comp->ArgumentAt(0)->value()); |
| 576 instr->set_env(NULL); | |
| 577 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 599 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 578 field, | 600 field, |
| 579 comp->ArgumentAt(0)->value(), | 601 comp->ArgumentAt(0)->value(), |
| 580 comp->ArgumentAt(1)->value(), | 602 comp->ArgumentAt(1)->value(), |
| 581 NULL); // Can not deoptimize. | 603 NULL); // Can not deoptimize. |
| 582 instr->set_computation(store); | 604 instr->set_computation(store); |
| 583 RemovePushArguments(comp); | 605 RemovePushArguments(comp); |
| 584 return true; | 606 return true; |
| 585 } | 607 } |
| 586 | 608 |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 OS::Print("Replacing v%d with v%d\n", | 975 OS::Print("Replacing v%d with v%d\n", |
| 954 instr->ssa_temp_index(), | 976 instr->ssa_temp_index(), |
| 955 result->ssa_temp_index()); | 977 result->ssa_temp_index()); |
| 956 } | 978 } |
| 957 } | 979 } |
| 958 } | 980 } |
| 959 } | 981 } |
| 960 | 982 |
| 961 | 983 |
| 962 } // namespace dart | 984 } // namespace dart |
| OLD | NEW |