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 |