| 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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 | 181 |
| 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 | 190 |
| 191 const GrowableArray<StaticCallInstr*>& static_calls() const { | |
| 192 return static_calls_; | |
| 193 } | |
| 194 | |
| 195 const GrowableArray<ClosureCallInstr*>& closure_calls() const { | 191 const GrowableArray<ClosureCallInstr*>& closure_calls() const { |
| 196 return closure_calls_; | 192 return closure_calls_; |
| 197 } | 193 } |
| 198 | 194 |
| 199 struct InstanceCallInfo { | 195 struct InstanceCallInfo { |
| 200 PolymorphicInstanceCallInstr* call; | 196 PolymorphicInstanceCallInstr* call; |
| 201 double ratio; | 197 double ratio; |
| 202 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg) | 198 explicit InstanceCallInfo(PolymorphicInstanceCallInstr* call_arg) |
| 203 : call(call_arg), ratio(0.0) {} | 199 : call(call_arg), ratio(0.0) {} |
| 204 }; | 200 }; |
| 205 | 201 |
| 202 struct StaticCallInfo { |
| 203 StaticCallInstr* call; |
| 204 double ratio; |
| 205 explicit StaticCallInfo(StaticCallInstr* value) |
| 206 : call(value), ratio(0.0) {} |
| 207 }; |
| 208 |
| 206 const GrowableArray<InstanceCallInfo>& instance_calls() const { | 209 const GrowableArray<InstanceCallInfo>& instance_calls() const { |
| 207 return instance_calls_; | 210 return instance_calls_; |
| 208 } | 211 } |
| 209 | 212 |
| 213 const GrowableArray<StaticCallInfo>& static_calls() const { |
| 214 return static_calls_; |
| 215 } |
| 216 |
| 210 bool HasCalls() const { | 217 bool HasCalls() const { |
| 211 return !(static_calls_.is_empty() && | 218 return !(static_calls_.is_empty() && |
| 212 closure_calls_.is_empty() && | 219 closure_calls_.is_empty() && |
| 213 instance_calls_.is_empty()); | 220 instance_calls_.is_empty()); |
| 214 } | 221 } |
| 215 | 222 |
| 216 void Clear() { | 223 void Clear() { |
| 217 static_calls_.Clear(); | 224 static_calls_.Clear(); |
| 218 closure_calls_.Clear(); | 225 closure_calls_.Clear(); |
| 219 instance_calls_.Clear(); | 226 instance_calls_.Clear(); |
| 220 } | 227 } |
| 221 | 228 |
| 229 void ComputeCallSiteRatio(intptr_t static_call_start_ix, |
| 230 intptr_t instance_call_start_ix) { |
| 231 const intptr_t num_static_calls = |
| 232 static_calls_.length() - static_call_start_ix; |
| 233 const intptr_t num_instance_calls = |
| 234 instance_calls_.length() - instance_call_start_ix; |
| 235 |
| 236 intptr_t max_count = 0; |
| 237 GrowableArray<intptr_t> instance_call_counts(num_instance_calls); |
| 238 for (intptr_t i = 0; i < num_instance_calls; ++i) { |
| 239 const intptr_t aggregate_count = |
| 240 instance_calls_[i + instance_call_start_ix]. |
| 241 call->ic_data().AggregateCount(); |
| 242 instance_call_counts.Add(aggregate_count); |
| 243 if (aggregate_count > max_count) max_count = aggregate_count; |
| 244 } |
| 245 |
| 246 GrowableArray<intptr_t> static_call_counts(num_static_calls); |
| 247 for (intptr_t i = 0; i < num_static_calls; ++i) { |
| 248 const intptr_t aggregate_count = |
| 249 static_calls_[i + static_call_start_ix]. |
| 250 call->ic_data()->AggregateCount(); |
| 251 static_call_counts.Add(aggregate_count); |
| 252 if (aggregate_count > max_count) max_count = aggregate_count; |
| 253 } |
| 254 |
| 255 |
| 256 for (intptr_t i = 0; i < num_instance_calls; ++i) { |
| 257 ASSERT(max_count > 0); |
| 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 ASSERT(max_count > 0); |
| 264 const double ratio = |
| 265 static_cast<double>(static_call_counts[i]) / max_count; |
| 266 static_calls_[i + static_call_start_ix].ratio = ratio; |
| 267 } |
| 268 } |
| 269 |
| 222 void FindCallSites(FlowGraph* graph) { | 270 void FindCallSites(FlowGraph* graph) { |
| 223 ASSERT(graph != NULL); | 271 ASSERT(graph != NULL); |
| 224 | 272 |
| 225 const intptr_t instance_call_start_ix = instance_calls_.length(); | 273 const intptr_t instance_call_start_ix = instance_calls_.length(); |
| 274 const intptr_t static_call_start_ix = static_calls_.length(); |
| 226 for (BlockIterator block_it = graph->postorder_iterator(); | 275 for (BlockIterator block_it = graph->postorder_iterator(); |
| 227 !block_it.Done(); | 276 !block_it.Done(); |
| 228 block_it.Advance()) { | 277 block_it.Advance()) { |
| 229 for (ForwardInstructionIterator it(block_it.Current()); | 278 for (ForwardInstructionIterator it(block_it.Current()); |
| 230 !it.Done(); | 279 !it.Done(); |
| 231 it.Advance()) { | 280 it.Advance()) { |
| 232 it.Current()->Accept(this); | 281 it.Current()->Accept(this); |
| 233 } | 282 } |
| 234 } | 283 } |
| 235 // Compute instance call site ratio. | 284 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix); |
| 236 const intptr_t num_instance_calls = | |
| 237 instance_calls_.length() - instance_call_start_ix; | |
| 238 intptr_t max_count = 0; | |
| 239 GrowableArray<intptr_t> 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 call_counts.Add(aggregate_count); | |
| 245 if (aggregate_count > max_count) max_count = aggregate_count; | |
| 246 } | |
| 247 | |
| 248 for (intptr_t i = 0; i < num_instance_calls; ++i) { | |
| 249 const double ratio = static_cast<double>(call_counts[i]) / max_count; | |
| 250 instance_calls_[i + instance_call_start_ix].ratio = ratio; | |
| 251 } | |
| 252 } | 285 } |
| 253 | 286 |
| 254 void VisitClosureCall(ClosureCallInstr* call) { | 287 void VisitClosureCall(ClosureCallInstr* call) { |
| 255 closure_calls_.Add(call); | 288 closure_calls_.Add(call); |
| 256 } | 289 } |
| 257 | 290 |
| 258 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { | 291 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { |
| 259 instance_calls_.Add(InstanceCallInfo(call)); | 292 instance_calls_.Add(InstanceCallInfo(call)); |
| 260 } | 293 } |
| 261 | 294 |
| 262 void VisitStaticCall(StaticCallInstr* call) { | 295 void VisitStaticCall(StaticCallInstr* call) { |
| 263 if (!call->function().IsInlineable()) return; | 296 if (!call->function().IsInlineable()) return; |
| 264 static_calls_.Add(call); | 297 static_calls_.Add(StaticCallInfo(call)); |
| 265 } | 298 } |
| 266 | 299 |
| 267 private: | 300 private: |
| 268 GrowableArray<StaticCallInstr*> static_calls_; | 301 GrowableArray<StaticCallInfo> static_calls_; |
| 269 GrowableArray<ClosureCallInstr*> closure_calls_; | 302 GrowableArray<ClosureCallInstr*> closure_calls_; |
| 270 GrowableArray<InstanceCallInfo> instance_calls_; | 303 GrowableArray<InstanceCallInfo> instance_calls_; |
| 271 | 304 |
| 272 DISALLOW_COPY_AND_ASSIGN(CallSites); | 305 DISALLOW_COPY_AND_ASSIGN(CallSites); |
| 273 }; | 306 }; |
| 274 | 307 |
| 275 | 308 |
| 276 struct InlinedCallData { | 309 struct InlinedCallData { |
| 277 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments) | 310 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments) |
| 278 : call(call), | 311 : call(call), |
| (...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 ParsedFunction* parsed_function = new ParsedFunction(function); | 722 ParsedFunction* parsed_function = new ParsedFunction(function); |
| 690 Parser::ParseFunction(parsed_function); | 723 Parser::ParseFunction(parsed_function); |
| 691 parsed_function->AllocateVariables(); | 724 parsed_function->AllocateVariables(); |
| 692 return parsed_function; | 725 return parsed_function; |
| 693 } | 726 } |
| 694 | 727 |
| 695 // Include special handling for List. factory: inlining it is not helpful | 728 // Include special handling for List. factory: inlining it is not helpful |
| 696 // if the incoming argument is a non-constant value. | 729 // if the incoming argument is a non-constant value. |
| 697 // TODO(srdjan): Fix inlining of List. factory. | 730 // TODO(srdjan): Fix inlining of List. factory. |
| 698 void InlineStaticCalls() { | 731 void InlineStaticCalls() { |
| 699 const GrowableArray<StaticCallInstr*>& calls = | 732 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
| 700 inlining_call_sites_->static_calls(); | 733 inlining_call_sites_->static_calls(); |
| 701 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length())); | 734 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", call_info.length())); |
| 702 for (intptr_t i = 0; i < calls.length(); ++i) { | 735 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 703 StaticCallInstr* call = calls[i]; | 736 StaticCallInstr* call = call_info[call_idx].call; |
| 704 if (call->function().name() == Symbols::ListFactory().raw()) { | 737 if (call->function().name() == Symbols::ListFactory().raw()) { |
| 705 // Inline only if no arguments or a constant was passed. | 738 // Inline only if no arguments or a constant was passed. |
| 706 ASSERT(call->function().NumImplicitParameters() == 1); | 739 ASSERT(call->function().NumImplicitParameters() == 1); |
| 707 ASSERT(call->ArgumentCount() <= 2); | 740 ASSERT(call->ArgumentCount() <= 2); |
| 708 // Arg 0: Instantiator type arguments. | 741 // Arg 0: Instantiator type arguments. |
| 709 // Arg 1: Length (optional). | 742 // Arg 1: Length (optional). |
| 710 if ((call->ArgumentCount() == 2) && | 743 if ((call->ArgumentCount() == 2) && |
| 711 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 744 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 712 // Do not inline since a non-constant argument was passed. | 745 // Do not inline since a non-constant argument was passed. |
| 713 continue; | 746 continue; |
| 714 } | 747 } |
| 715 } | 748 } |
| 749 if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 750 const Function& target = call->function(); |
| 751 TRACE_INLINING(OS::Print( |
| 752 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 753 target.ToCString(), |
| 754 target.deoptimization_counter(), |
| 755 call_info[call_idx].ratio)); |
| 756 continue; |
| 757 } |
| 716 GrowableArray<Value*> arguments(call->ArgumentCount()); | 758 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 717 for (int i = 0; i < call->ArgumentCount(); ++i) { | 759 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 718 arguments.Add(call->PushArgumentAt(i)->value()); | 760 arguments.Add(call->PushArgumentAt(i)->value()); |
| 719 } | 761 } |
| 720 InlinedCallData call_data(call, &arguments); | 762 InlinedCallData call_data(call, &arguments); |
| 721 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 763 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 722 InlineCall(&call_data); | 764 InlineCall(&call_data); |
| 723 } | 765 } |
| 724 } | 766 } |
| 725 } | 767 } |
| (...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 OS::Print("After Inlining of %s\n", flow_graph_-> | 1368 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1327 parsed_function().function().ToFullyQualifiedCString()); | 1369 parsed_function().function().ToFullyQualifiedCString()); |
| 1328 FlowGraphPrinter printer(*flow_graph_); | 1370 FlowGraphPrinter printer(*flow_graph_); |
| 1329 printer.PrintBlocks(); | 1371 printer.PrintBlocks(); |
| 1330 } | 1372 } |
| 1331 } | 1373 } |
| 1332 } | 1374 } |
| 1333 } | 1375 } |
| 1334 | 1376 |
| 1335 } // namespace dart | 1377 } // namespace dart |
| OLD | NEW |