| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
| 6 | 6 |
| 7 #include "vm/block_scheduler.h" | 7 #include "vm/block_scheduler.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/flags.h" | 9 #include "vm/flags.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 PolymorphicInliner(CallSiteInliner* owner, | 357 PolymorphicInliner(CallSiteInliner* owner, |
| 358 PolymorphicInstanceCallInstr* call); | 358 PolymorphicInstanceCallInstr* call); |
| 359 | 359 |
| 360 void Inline(); | 360 void Inline(); |
| 361 | 361 |
| 362 private: | 362 private: |
| 363 bool CheckInlinedDuplicate(const Function& target); | 363 bool CheckInlinedDuplicate(const Function& target); |
| 364 bool CheckNonInlinedDuplicate(const Function& target); | 364 bool CheckNonInlinedDuplicate(const Function& target); |
| 365 | 365 |
| 366 bool TryInlining(const Function& target); | 366 bool TryInlining(const Function& target); |
| 367 bool TryInlineRecognizedMethod(const Function& target); |
| 367 | 368 |
| 368 TargetEntryInstr* BuildDecisionGraph(); | 369 TargetEntryInstr* BuildDecisionGraph(); |
| 369 | 370 |
| 370 CallSiteInliner* const owner_; | 371 CallSiteInliner* const owner_; |
| 371 PolymorphicInstanceCallInstr* const call_; | 372 PolymorphicInstanceCallInstr* const call_; |
| 372 const intptr_t num_variants_; | 373 const intptr_t num_variants_; |
| 373 GrowableArray<CidTarget> variants_; | 374 GrowableArray<CidTarget> variants_; |
| 374 | 375 |
| 375 GrowableArray<CidTarget> inlined_variants_; | 376 GrowableArray<CidTarget> inlined_variants_; |
| 376 GrowableArray<CidTarget> non_inlined_variants_; | 377 GrowableArray<CidTarget> non_inlined_variants_; |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 error = isolate->object_store()->sticky_error(); | 675 error = isolate->object_store()->sticky_error(); |
| 675 isolate->object_store()->clear_sticky_error(); | 676 isolate->object_store()->clear_sticky_error(); |
| 676 isolate->set_long_jump_base(base); | 677 isolate->set_long_jump_base(base); |
| 677 isolate->set_deopt_id(prev_deopt_id); | 678 isolate->set_deopt_id(prev_deopt_id); |
| 678 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 679 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 679 return false; | 680 return false; |
| 680 } | 681 } |
| 681 } | 682 } |
| 682 | 683 |
| 683 private: | 684 private: |
| 685 friend class PolymorphicInliner; |
| 686 |
| 684 void InlineCall(InlinedCallData* call_data) { | 687 void InlineCall(InlinedCallData* call_data) { |
| 685 TimerScope timer(FLAG_compiler_stats, | 688 TimerScope timer(FLAG_compiler_stats, |
| 686 &CompilerStats::graphinliner_subst_timer, | 689 &CompilerStats::graphinliner_subst_timer, |
| 687 Isolate::Current()); | 690 Isolate::Current()); |
| 688 | 691 |
| 689 // For closure calls: Store context value. | 692 // For closure calls: Store context value. |
| 690 FlowGraph* callee_graph = call_data->callee_graph; | 693 FlowGraph* callee_graph = call_data->callee_graph; |
| 691 TargetEntryInstr* callee_entry = | 694 TargetEntryInstr* callee_entry = |
| 692 callee_graph->graph_entry()->normal_entry(); | 695 callee_graph->graph_entry()->normal_entry(); |
| 693 ClosureCallInstr* closure_call = call_data->call->AsClosureCall(); | 696 ClosureCallInstr* closure_call = call_data->call->AsClosureCall(); |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 return true; | 1079 return true; |
| 1077 } | 1080 } |
| 1078 } | 1081 } |
| 1079 | 1082 |
| 1080 return false; | 1083 return false; |
| 1081 } | 1084 } |
| 1082 | 1085 |
| 1083 | 1086 |
| 1084 bool PolymorphicInliner::TryInlining(const Function& target) { | 1087 bool PolymorphicInliner::TryInlining(const Function& target) { |
| 1085 if (!target.is_optimizable()) { | 1088 if (!target.is_optimizable()) { |
| 1089 if (TryInlineRecognizedMethod(target)) { |
| 1090 owner_->inlined_ = true; |
| 1091 return true; |
| 1092 } |
| 1086 return false; | 1093 return false; |
| 1087 } | 1094 } |
| 1095 |
| 1088 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1096 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
| 1089 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1097 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
| 1090 arguments.Add(call_->PushArgumentAt(i)->value()); | 1098 arguments.Add(call_->PushArgumentAt(i)->value()); |
| 1091 } | 1099 } |
| 1092 InlinedCallData call_data(call_, &arguments); | 1100 InlinedCallData call_data(call_, &arguments); |
| 1093 if (!owner_->TryInlining(target, | 1101 if (!owner_->TryInlining(target, |
| 1094 call_->instance_call()->argument_names(), | 1102 call_->instance_call()->argument_names(), |
| 1095 &call_data)) { | 1103 &call_data)) { |
| 1096 return false; | 1104 return false; |
| 1097 } | 1105 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 Instruction* second) { | 1145 Instruction* second) { |
| 1138 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { | 1146 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { |
| 1139 Value* input = second->InputAt(i); | 1147 Value* input = second->InputAt(i); |
| 1140 input->definition()->AddInputUse(input); | 1148 input->definition()->AddInputUse(input); |
| 1141 } | 1149 } |
| 1142 first->LinkTo(second); | 1150 first->LinkTo(second); |
| 1143 return second; | 1151 return second; |
| 1144 } | 1152 } |
| 1145 | 1153 |
| 1146 | 1154 |
| 1155 bool PolymorphicInliner::TryInlineRecognizedMethod(const Function& target) { |
| 1156 FlowGraphOptimizer optimizer(owner_->caller_graph(), |
| 1157 NULL); // No guarded fields needed. |
| 1158 TargetEntryInstr* entry; |
| 1159 Definition* last; |
| 1160 if (optimizer.TryInlineRecognizedMethod(target, |
| 1161 call_, |
| 1162 call_->ic_data(), |
| 1163 &entry, &last)) { |
| 1164 // Create a graph fragment. |
| 1165 InlineExitCollector* exit_collector = |
| 1166 new InlineExitCollector(owner_->caller_graph(), call_); |
| 1167 |
| 1168 ReturnInstr* result = |
| 1169 new ReturnInstr(call_->instance_call()->token_pos(), |
| 1170 new Value(last)); |
| 1171 owner_->caller_graph()->AppendTo( |
| 1172 last, |
| 1173 result, |
| 1174 call_->env(), // Return can become deoptimization target. |
| 1175 Definition::kEffect); |
| 1176 entry->set_last_instruction(result); |
| 1177 exit_collector->AddExit(result); |
| 1178 GraphEntryInstr* graph_entry = |
| 1179 new GraphEntryInstr(NULL, // No parsed function. |
| 1180 entry, |
| 1181 Isolate::kNoDeoptId); // No OSR id. |
| 1182 // Update polymorphic inliner state. |
| 1183 inlined_entries_.Add(graph_entry); |
| 1184 exit_collector_->Union(exit_collector); |
| 1185 return true; |
| 1186 } |
| 1187 return false; |
| 1188 } |
| 1189 |
| 1190 |
| 1147 // Build a DAG to dispatch to the inlined function bodies. Load the class | 1191 // Build a DAG to dispatch to the inlined function bodies. Load the class |
| 1148 // id of the receiver and make explicit comparisons for each inlined body, | 1192 // id of the receiver and make explicit comparisons for each inlined body, |
| 1149 // in frequency order. If all variants are inlined, the entry to the last | 1193 // in frequency order. If all variants are inlined, the entry to the last |
| 1150 // inlined body is guarded by a CheckClassId instruction which can deopt. | 1194 // inlined body is guarded by a CheckClassId instruction which can deopt. |
| 1151 // If not all variants are inlined, we add a PolymorphicInstanceCall | 1195 // If not all variants are inlined, we add a PolymorphicInstanceCall |
| 1152 // instruction to handle the non-inlined variants. | 1196 // instruction to handle the non-inlined variants. |
| 1153 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { | 1197 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
| 1154 // Start with a fresh target entry. | 1198 // Start with a fresh target entry. |
| 1155 TargetEntryInstr* entry = | 1199 TargetEntryInstr* entry = |
| 1156 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), | 1200 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1442 OS::Print("After Inlining of %s\n", flow_graph_-> | 1486 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1443 parsed_function().function().ToFullyQualifiedCString()); | 1487 parsed_function().function().ToFullyQualifiedCString()); |
| 1444 FlowGraphPrinter printer(*flow_graph_); | 1488 FlowGraphPrinter printer(*flow_graph_); |
| 1445 printer.PrintBlocks(); | 1489 printer.PrintBlocks(); |
| 1446 } | 1490 } |
| 1447 } | 1491 } |
| 1448 } | 1492 } |
| 1449 } | 1493 } |
| 1450 | 1494 |
| 1451 } // namespace dart | 1495 } // namespace dart |
| OLD | NEW |