Chromium Code Reviews| 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/compiler.h" | 7 #include "vm/compiler.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/flow_graph.h" | 9 #include "vm/flow_graph.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 // A collection of call sites to consider for inlining. | 182 // A collection of call sites to consider for inlining. |
| 183 class CallSites : public FlowGraphVisitor { | 183 class CallSites : public FlowGraphVisitor { |
| 184 public: | 184 public: |
| 185 explicit CallSites(FlowGraph* flow_graph) | 185 explicit CallSites(FlowGraph* flow_graph) |
| 186 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. | 186 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. |
| 187 static_calls_(), | 187 static_calls_(), |
| 188 closure_calls_(), | 188 closure_calls_(), |
| 189 instance_calls_(), | 189 instance_calls_(), |
| 190 skip_static_call_deopt_ids_() { } | 190 skip_static_call_deopt_ids_() { } |
| 191 | 191 |
| 192 const GrowableArray<StaticCallInstr*>& static_calls() const { | |
| 193 return static_calls_; | |
| 194 } | |
| 195 | |
| 196 const GrowableArray<ClosureCallInstr*>& closure_calls() const { | 192 const GrowableArray<ClosureCallInstr*>& closure_calls() const { |
| 197 return closure_calls_; | 193 return closure_calls_; |
| 198 } | 194 } |
| 199 | 195 |
| 200 struct InstanceCallInfo { | 196 struct InstanceCallInfo { |
| 201 PolymorphicInstanceCallInstr* call; | 197 PolymorphicInstanceCallInstr* call; |
| 202 double ratio; | 198 double ratio; |
| 203 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg) | 199 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg) |
| 204 : call(call_arg), ratio(0.0) {} | 200 : call(call_arg), ratio(0.0) {} |
| 205 }; | 201 }; |
| 206 | 202 |
| 203 struct StaticCallInfo { | |
| 204 StaticCallInstr* call; | |
| 205 double ratio; | |
| 206 explicit StaticCallInfo(StaticCallInstr* value) | |
| 207 : call(value), ratio(0.0) {} | |
| 208 }; | |
| 209 | |
| 207 const GrowableArray<InstanceCallInfo>& instance_calls() const { | 210 const GrowableArray<InstanceCallInfo>& instance_calls() const { |
| 208 return instance_calls_; | 211 return instance_calls_; |
| 209 } | 212 } |
| 210 | 213 |
| 214 const GrowableArray<StaticCallInfo>& static_calls() const { | |
| 215 return static_calls_; | |
| 216 } | |
| 217 | |
| 211 bool HasCalls() const { | 218 bool HasCalls() const { |
| 212 return !(static_calls_.is_empty() && | 219 return !(static_calls_.is_empty() && |
| 213 closure_calls_.is_empty() && | 220 closure_calls_.is_empty() && |
| 214 instance_calls_.is_empty()); | 221 instance_calls_.is_empty()); |
| 215 } | 222 } |
| 216 | 223 |
| 217 void Clear() { | 224 void Clear() { |
| 218 static_calls_.Clear(); | 225 static_calls_.Clear(); |
| 219 closure_calls_.Clear(); | 226 closure_calls_.Clear(); |
| 220 instance_calls_.Clear(); | 227 instance_calls_.Clear(); |
| 221 skip_static_call_deopt_ids_.Clear(); | 228 skip_static_call_deopt_ids_.Clear(); |
| 222 } | 229 } |
| 223 | 230 |
| 231 void ComputeCallSiteRatio(intptr_t static_call_start_ix, | |
| 232 intptr_t instance_call_start_ix) { | |
| 233 const intptr_t num_static_calls = | |
| 234 static_calls_.length() - static_call_start_ix; | |
| 235 const intptr_t num_instance_calls = | |
| 236 instance_calls_.length() - instance_call_start_ix; | |
| 237 | |
| 238 intptr_t max_count = 0; | |
| 239 GrowableArray<intptr_t> instance_call_counts(num_instance_calls); | |
| 240 for (intptr_t i = 0; i < num_instance_calls; ++i) { | |
| 241 const intptr_t aggregate_count = | |
| 242 instance_calls_[i + instance_call_start_ix]. | |
| 243 call->ic_data().AggregateCount(); | |
| 244 instance_call_counts.Add(aggregate_count); | |
| 245 if (aggregate_count > max_count) max_count = aggregate_count; | |
| 246 } | |
| 247 | |
| 248 GrowableArray<intptr_t> static_call_counts(num_static_calls); | |
| 249 for (intptr_t i = 0; i < num_static_calls; ++i) { | |
| 250 const intptr_t aggregate_count = | |
| 251 static_calls_[i + static_call_start_ix]. | |
| 252 call->ic_data()->AggregateCount(); | |
| 253 static_call_counts.Add(aggregate_count); | |
| 254 if (aggregate_count > max_count) max_count = aggregate_count; | |
| 255 } | |
| 256 | |
| 257 for (intptr_t i = 0; i < num_instance_calls; ++i) { | |
| 258 const double ratio = | |
| 259 static_cast<double>(instance_call_counts[i]) / max_count; | |
| 260 instance_calls_[i + instance_call_start_ix].ratio = ratio; | |
| 261 } | |
| 262 for (intptr_t i = 0; i < num_static_calls; ++i) { | |
| 263 const double ratio = | |
| 264 static_cast<double>(static_call_counts[i]) / max_count; | |
| 265 static_calls_[i + static_call_start_ix].ratio = ratio; | |
| 266 } | |
| 267 } | |
| 268 | |
| 224 void FindCallSites(FlowGraph* graph) { | 269 void FindCallSites(FlowGraph* graph) { |
| 225 ASSERT(graph != NULL); | 270 ASSERT(graph != NULL); |
| 226 const Function& function = graph->parsed_function().function(); | 271 const Function& function = graph->parsed_function().function(); |
| 227 ASSERT(function.HasCode()); | 272 ASSERT(function.HasCode()); |
| 228 const Code& code = Code::Handle(function.unoptimized_code()); | 273 const Code& code = Code::Handle(function.unoptimized_code()); |
| 229 | 274 |
| 230 skip_static_call_deopt_ids_.Clear(); | 275 skip_static_call_deopt_ids_.Clear(); |
| 231 code.ExtractUncalledStaticCallDeoptIds(&skip_static_call_deopt_ids_); | 276 code.ExtractUncalledStaticCallDeoptIds(&skip_static_call_deopt_ids_); |
| 232 | 277 |
| 233 const intptr_t instance_call_start_ix = instance_calls_.length(); | 278 const intptr_t instance_call_start_ix = instance_calls_.length(); |
| 279 const intptr_t static_call_start_ix = static_calls_.length(); | |
| 234 for (BlockIterator block_it = graph->postorder_iterator(); | 280 for (BlockIterator block_it = graph->postorder_iterator(); |
| 235 !block_it.Done(); | 281 !block_it.Done(); |
| 236 block_it.Advance()) { | 282 block_it.Advance()) { |
| 237 for (ForwardInstructionIterator it(block_it.Current()); | 283 for (ForwardInstructionIterator it(block_it.Current()); |
| 238 !it.Done(); | 284 !it.Done(); |
| 239 it.Advance()) { | 285 it.Advance()) { |
| 240 it.Current()->Accept(this); | 286 it.Current()->Accept(this); |
| 241 } | 287 } |
| 242 } | 288 } |
| 243 // Compute instance call site ratio. | 289 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix); |
| 244 const intptr_t num_instance_calls = | |
| 245 instance_calls_.length() - instance_call_start_ix; | |
| 246 intptr_t max_count = 0; | |
| 247 GrowableArray<intptr_t> call_counts(num_instance_calls); | |
| 248 for (intptr_t i = 0; i < num_instance_calls; ++i) { | |
| 249 const intptr_t aggregate_count = | |
| 250 instance_calls_[i + instance_call_start_ix]. | |
| 251 call->ic_data().AggregateCount(); | |
| 252 call_counts.Add(aggregate_count); | |
| 253 if (aggregate_count > max_count) max_count = aggregate_count; | |
| 254 } | |
| 255 | |
| 256 | |
| 257 for (intptr_t i = 0; i < num_instance_calls; ++i) { | |
| 258 const double ratio = static_cast<double>(call_counts[i]) / max_count; | |
| 259 instance_calls_[i + instance_call_start_ix].ratio = ratio; | |
| 260 } | |
| 261 } | 290 } |
| 262 | 291 |
| 263 void VisitClosureCall(ClosureCallInstr* call) { | 292 void VisitClosureCall(ClosureCallInstr* call) { |
| 264 closure_calls_.Add(call); | 293 closure_calls_.Add(call); |
| 265 } | 294 } |
| 266 | 295 |
| 267 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { | 296 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { |
| 268 instance_calls_.Add(InstanceCallInfo(call)); | 297 instance_calls_.Add(InstanceCallInfo(call)); |
| 269 } | 298 } |
| 270 | 299 |
| 271 void VisitStaticCall(StaticCallInstr* call) { | 300 void VisitStaticCall(StaticCallInstr* call) { |
| 272 if (!call->function().IsInlineable()) return; | 301 if (!call->function().IsInlineable()) return; |
| 273 const intptr_t call_deopt_id = call->deopt_id(); | 302 const intptr_t call_deopt_id = call->deopt_id(); |
| 274 for (intptr_t i = 0; i < skip_static_call_deopt_ids_.length(); i++) { | 303 for (intptr_t i = 0; i < skip_static_call_deopt_ids_.length(); i++) { |
| 275 if (call_deopt_id == skip_static_call_deopt_ids_[i]) { | 304 if (call_deopt_id == skip_static_call_deopt_ids_[i]) { |
| 276 // Do not inline this call. | 305 // Do not inline this call. |
| 277 return; | 306 return; |
| 278 } | 307 } |
| 279 } | 308 } |
| 280 static_calls_.Add(call); | 309 static_calls_.Add(StaticCallInfo(call)); |
| 281 } | 310 } |
| 282 | 311 |
| 283 private: | 312 private: |
| 284 GrowableArray<StaticCallInstr*> static_calls_; | 313 GrowableArray<StaticCallInfo> static_calls_; |
| 285 GrowableArray<ClosureCallInstr*> closure_calls_; | 314 GrowableArray<ClosureCallInstr*> closure_calls_; |
| 286 GrowableArray<InstanceCallInfo> instance_calls_; | 315 GrowableArray<InstanceCallInfo> instance_calls_; |
| 287 GrowableArray<intptr_t> skip_static_call_deopt_ids_; | 316 GrowableArray<intptr_t> skip_static_call_deopt_ids_; |
| 288 | 317 |
| 289 DISALLOW_COPY_AND_ASSIGN(CallSites); | 318 DISALLOW_COPY_AND_ASSIGN(CallSites); |
| 290 }; | 319 }; |
| 291 | 320 |
| 292 | 321 |
| 293 struct InlinedCallData { | 322 struct InlinedCallData { |
| 294 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments) | 323 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments) |
| (...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 706 ParsedFunction* parsed_function = new ParsedFunction(function); | 735 ParsedFunction* parsed_function = new ParsedFunction(function); |
| 707 Parser::ParseFunction(parsed_function); | 736 Parser::ParseFunction(parsed_function); |
| 708 parsed_function->AllocateVariables(); | 737 parsed_function->AllocateVariables(); |
| 709 return parsed_function; | 738 return parsed_function; |
| 710 } | 739 } |
| 711 | 740 |
| 712 // Include special handling for List. factory: inlining it is not helpful | 741 // Include special handling for List. factory: inlining it is not helpful |
| 713 // if the incoming argument is a non-constant value. | 742 // if the incoming argument is a non-constant value. |
| 714 // TODO(srdjan): Fix inlining of List. factory. | 743 // TODO(srdjan): Fix inlining of List. factory. |
| 715 void InlineStaticCalls() { | 744 void InlineStaticCalls() { |
| 716 const GrowableArray<StaticCallInstr*>& calls = | 745 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
| 717 inlining_call_sites_->static_calls(); | 746 inlining_call_sites_->static_calls(); |
| 718 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length())); | 747 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", call_info.length())); |
| 719 for (intptr_t i = 0; i < calls.length(); ++i) { | 748 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 720 StaticCallInstr* call = calls[i]; | 749 StaticCallInstr* call = call_info[call_idx].call; |
| 721 if (call->function().name() == Symbols::ListFactory().raw()) { | 750 if (call->function().name() == Symbols::ListFactory().raw()) { |
| 722 // Inline only if no arguments or a constant was passed. | 751 // Inline only if no arguments or a constant was passed. |
| 723 ASSERT(call->function().NumImplicitParameters() == 1); | 752 ASSERT(call->function().NumImplicitParameters() == 1); |
| 724 ASSERT(call->ArgumentCount() <= 2); | 753 ASSERT(call->ArgumentCount() <= 2); |
| 725 // Arg 0: Instantiator type arguments. | 754 // Arg 0: Instantiator type arguments. |
| 726 // Arg 1: Length (optional). | 755 // Arg 1: Length (optional). |
| 727 if ((call->ArgumentCount() == 2) && | 756 if ((call->ArgumentCount() == 2) && |
| 728 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 757 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 729 // Do not inline since a non-constant argument was passed. | 758 // Do not inline since a non-constant argument was passed. |
| 730 continue; | 759 continue; |
| 731 } | 760 } |
| 732 } | 761 } |
| 762 if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | |
|
Florian Schneider
2013/06/25 08:48:32
Maybe we need to adapt the threshold now that stat
| |
| 763 const Function& target = call->function(); | |
| 764 TRACE_INLINING(OS::Print( | |
| 765 " => %s (deopt count %d)\n Bailout: cold %f\n", | |
| 766 target.ToCString(), | |
| 767 target.deoptimization_counter(), | |
| 768 call_info[call_idx].ratio)); | |
| 769 continue; | |
| 770 } | |
| 733 GrowableArray<Value*> arguments(call->ArgumentCount()); | 771 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 734 for (int i = 0; i < call->ArgumentCount(); ++i) { | 772 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 735 arguments.Add(call->PushArgumentAt(i)->value()); | 773 arguments.Add(call->PushArgumentAt(i)->value()); |
| 736 } | 774 } |
| 737 InlinedCallData call_data(call, &arguments); | 775 InlinedCallData call_data(call, &arguments); |
| 738 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 776 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 739 InlineCall(&call_data); | 777 InlineCall(&call_data); |
| 740 } | 778 } |
| 741 } | 779 } |
| 742 } | 780 } |
| (...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1343 OS::Print("After Inlining of %s\n", flow_graph_-> | 1381 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1344 parsed_function().function().ToFullyQualifiedCString()); | 1382 parsed_function().function().ToFullyQualifiedCString()); |
| 1345 FlowGraphPrinter printer(*flow_graph_); | 1383 FlowGraphPrinter printer(*flow_graph_); |
| 1346 printer.PrintBlocks(); | 1384 printer.PrintBlocks(); |
| 1347 } | 1385 } |
| 1348 } | 1386 } |
| 1349 } | 1387 } |
| 1350 } | 1388 } |
| 1351 | 1389 |
| 1352 } // namespace dart | 1390 } // namespace dart |
| OLD | NEW |