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/flow_graph_builder.h" | 7 #include "vm/flow_graph_builder.h" |
| 8 #include "vm/hash_map.h" |
8 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
9 #include "vm/object_store.h" | 10 #include "vm/object_store.h" |
10 #include "vm/parser.h" | 11 #include "vm/parser.h" |
11 #include "vm/scopes.h" | 12 #include "vm/scopes.h" |
12 #include "vm/symbols.h" | 13 #include "vm/symbols.h" |
13 | 14 |
14 namespace dart { | 15 namespace dart { |
15 | 16 |
16 DECLARE_FLAG(bool, eliminate_type_checks); | 17 DECLARE_FLAG(bool, eliminate_type_checks); |
17 DECLARE_FLAG(bool, enable_type_checks); | 18 DECLARE_FLAG(bool, enable_type_checks); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 if ((class_ids[0] == receiver_class_id) && | 75 if ((class_ids[0] == receiver_class_id) && |
75 (class_ids[1] == argument_class_id)) { | 76 (class_ids[1] == argument_class_id)) { |
76 return true; | 77 return true; |
77 } | 78 } |
78 } | 79 } |
79 return false; | 80 return false; |
80 } | 81 } |
81 | 82 |
82 | 83 |
83 static bool ClassIdIsOneOf(intptr_t class_id, | 84 static bool ClassIdIsOneOf(intptr_t class_id, |
84 GrowableArray<intptr_t>* class_ids) { | 85 const GrowableArray<intptr_t>& class_ids) { |
85 for (intptr_t i = 0; i < class_ids->length(); i++) { | 86 for (intptr_t i = 0; i < class_ids.length(); i++) { |
86 if ((*class_ids)[i] == class_id) { | 87 if (class_ids[i] == class_id) { |
87 return true; | 88 return true; |
88 } | 89 } |
89 } | 90 } |
90 return false; | 91 return false; |
91 } | 92 } |
92 | 93 |
93 | 94 |
94 static bool ICDataHasOnlyReceiverArgumentClassIds( | 95 static bool ICDataHasOnlyReceiverArgumentClassIds( |
95 const ICData& ic_data, | 96 const ICData& ic_data, |
96 GrowableArray<intptr_t>* receiver_class_ids, | 97 const GrowableArray<intptr_t>& receiver_class_ids, |
97 GrowableArray<intptr_t>* argument_class_ids) { | 98 const GrowableArray<intptr_t>& argument_class_ids) { |
98 if (ic_data.num_args_tested() != 2) return false; | 99 if (ic_data.num_args_tested() != 2) return false; |
99 | 100 |
100 Function& target = Function::Handle(); | 101 Function& target = Function::Handle(); |
101 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 102 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
102 GrowableArray<intptr_t> class_ids; | 103 GrowableArray<intptr_t> class_ids; |
103 ic_data.GetCheckAt(i, &class_ids, &target); | 104 ic_data.GetCheckAt(i, &class_ids, &target); |
104 ASSERT(class_ids.length() == 2); | 105 ASSERT(class_ids.length() == 2); |
105 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || | 106 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || |
106 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { | 107 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { |
107 return false; | 108 return false; |
(...skipping 10 matching lines...) Expand all Loading... |
118 | 119 |
119 static bool HasOnlyTwoSmi(const ICData& ic_data) { | 120 static bool HasOnlyTwoSmi(const ICData& ic_data) { |
120 return (ic_data.NumberOfChecks() == 1) && | 121 return (ic_data.NumberOfChecks() == 1) && |
121 ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid); | 122 ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid); |
122 } | 123 } |
123 | 124 |
124 | 125 |
125 // Returns false if the ICData contains anything other than the 4 combinations | 126 // Returns false if the ICData contains anything other than the 4 combinations |
126 // of Mint and Smi for the receiver and argument classes. | 127 // of Mint and Smi for the receiver and argument classes. |
127 static bool HasTwoMintOrSmi(const ICData& ic_data) { | 128 static bool HasTwoMintOrSmi(const ICData& ic_data) { |
128 GrowableArray<intptr_t> class_ids; | 129 GrowableArray<intptr_t> class_ids(2); |
129 class_ids.Add(kSmiCid); | 130 class_ids.Add(kSmiCid); |
130 class_ids.Add(kMintCid); | 131 class_ids.Add(kMintCid); |
131 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, &class_ids, &class_ids); | 132 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
132 } | 133 } |
133 | 134 |
134 | 135 |
135 static bool HasOneDouble(const ICData& ic_data) { | 136 static bool HasOneDouble(const ICData& ic_data) { |
136 return ICDataHasReceiverClassId(ic_data, kDoubleCid); | 137 return ICDataHasReceiverClassId(ic_data, kDoubleCid); |
137 } | 138 } |
138 | 139 |
139 | 140 |
140 static bool HasOnlyTwoDouble(const ICData& ic_data) { | 141 static bool HasOnlyTwoDouble(const ICData& ic_data) { |
141 return (ic_data.NumberOfChecks() == 1) && | 142 return (ic_data.NumberOfChecks() == 1) && |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 if (target.kind() == RawFunction::kImplicitGetter) { | 357 if (target.kind() == RawFunction::kImplicitGetter) { |
357 if (!HasOneTarget(ic_data)) { | 358 if (!HasOneTarget(ic_data)) { |
358 // TODO(srdjan): Implement for mutiple targets. | 359 // TODO(srdjan): Implement for mutiple targets. |
359 return false; | 360 return false; |
360 } | 361 } |
361 // Inline implicit instance getter. | 362 // Inline implicit instance getter. |
362 const String& field_name = | 363 const String& field_name = |
363 String::Handle(Field::NameFromGetter(comp->function_name())); | 364 String::Handle(Field::NameFromGetter(comp->function_name())); |
364 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 365 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
365 ASSERT(!field.IsNull()); | 366 ASSERT(!field.IsNull()); |
366 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 367 |
367 field, comp->ArgumentAt(0)->value(), comp); | 368 LoadInstanceFieldComp* load; |
368 load->set_ic_data(comp->ic_data()); | 369 if (!use_ssa_) { |
| 370 load = new LoadInstanceFieldComp(field, |
| 371 comp->ArgumentAt(0)->value(), |
| 372 comp, |
| 373 true); // Can deoptimize. |
| 374 // TODO(fschneider): Remove the boolean parameter can_deoptimize once |
| 375 // the non-SSA optimizer is removed. |
| 376 load->set_ic_data(comp->ic_data()); |
| 377 } else { |
| 378 // TODO(fschneider): Avoid generating redundant checks by checking the |
| 379 // result-cid of the value. |
| 380 CheckClassComp* check = |
| 381 new CheckClassComp(comp->ArgumentAt(0)->value(), comp); |
| 382 const ICData& unary_checks = |
| 383 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
| 384 check->set_ic_data(&unary_checks); |
| 385 BindInstr* check_instr = new BindInstr(BindInstr::kUnused, check); |
| 386 ASSERT(instr->env() != NULL); // Always the case with SSA. |
| 387 check_instr->set_env( |
| 388 new Environment(instr->env()->values(), |
| 389 instr->env()->fixed_parameter_count())); |
| 390 check_instr->InsertBefore(instr); |
| 391 load = new LoadInstanceFieldComp(field, |
| 392 comp->ArgumentAt(0)->value(), |
| 393 NULL, |
| 394 false); // Can not deoptimize. |
| 395 } |
369 instr->set_computation(load); | 396 instr->set_computation(load); |
370 RemovePushArguments(comp); | 397 RemovePushArguments(comp); |
371 return true; | 398 return true; |
372 } | 399 } |
373 | 400 |
374 // Not an implicit getter. | 401 // Not an implicit getter. |
375 MethodRecognizer::Kind recognized_kind = | 402 MethodRecognizer::Kind recognized_kind = |
376 MethodRecognizer::RecognizeKind(target); | 403 MethodRecognizer::RecognizeKind(target); |
377 | 404 |
378 // VM objects length getter. | 405 // VM objects length getter. |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 } | 509 } |
483 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { | 510 if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr, comp)) { |
484 return; | 511 return; |
485 } | 512 } |
486 if (TryInlineInstanceMethod(instr, comp)) { | 513 if (TryInlineInstanceMethod(instr, comp)) { |
487 return; | 514 return; |
488 } | 515 } |
489 const intptr_t kMaxChecks = 4; | 516 const intptr_t kMaxChecks = 4; |
490 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { | 517 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { |
491 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); | 518 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); |
492 ICData& unary_checks = | 519 const ICData& unary_checks = |
493 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | 520 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); |
494 call->set_ic_data(&unary_checks); | 521 call->set_ic_data(&unary_checks); |
495 instr->set_computation(call); | 522 instr->set_computation(call); |
496 } | 523 } |
497 } | 524 } |
498 // An instance call without ICData should continue calling via IC calls | 525 // An instance call without ICData should continue calling via IC calls |
499 // which should trigger reoptimization of optimized code. | 526 // which should trigger reoptimization of optimized code. |
500 } | 527 } |
501 | 528 |
502 | 529 |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
861 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 888 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
862 LocationSummary* locs = it.Current()->locs(); | 889 LocationSummary* locs = it.Current()->locs(); |
863 if ((locs != NULL) && locs->can_call()) { | 890 if ((locs != NULL) && locs->can_call()) { |
864 is_leaf_ = false; | 891 is_leaf_ = false; |
865 return; | 892 return; |
866 } | 893 } |
867 } | 894 } |
868 } | 895 } |
869 } | 896 } |
870 | 897 |
| 898 |
| 899 void LocalCSE::Optimize() { |
| 900 for (intptr_t i = 0; i < blocks_.length(); ++i) { |
| 901 BlockEntryInstr* entry = blocks_[i]; |
| 902 DirectChainedHashMap<BindInstr*> map; |
| 903 ASSERT(map.IsEmpty()); |
| 904 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 905 BindInstr* instr = it.Current()->AsBind(); |
| 906 if (instr == NULL || instr->computation()->HasSideEffect()) continue; |
| 907 BindInstr* result = map.Lookup(instr); |
| 908 if (result == NULL) { |
| 909 map.Insert(instr); |
| 910 continue; |
| 911 } |
| 912 // Replace current with lookup result. |
| 913 instr->ReplaceUsesWith(result); |
| 914 it.RemoveCurrentFromGraph(); |
| 915 if (FLAG_trace_optimization) { |
| 916 OS::Print("Replacing v%d with v%d\n", |
| 917 instr->ssa_temp_index(), |
| 918 result->ssa_temp_index()); |
| 919 } |
| 920 } |
| 921 } |
| 922 } |
| 923 |
| 924 |
871 } // namespace dart | 925 } // namespace dart |
OLD | NEW |