Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: runtime/vm/flow_graph_inliner.cc

Issue 2842753002: Reland "Use off-heap data for type feedback in PolymorphicInstanceCallInstr" (Closed)
Patch Set: Fix AOT case Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #if !defined(DART_PRECOMPILED_RUNTIME) 4 #if !defined(DART_PRECOMPILED_RUNTIME)
5 #include "vm/flow_graph_inliner.h" 5 #include "vm/flow_graph_inliner.h"
6 6
7 #include "vm/aot_optimizer.h" 7 #include "vm/aot_optimizer.h"
8 #include "vm/precompiler.h" 8 #include "vm/precompiler.h"
9 #include "vm/block_scheduler.h" 9 #include "vm/block_scheduler.h"
10 #include "vm/branch_optimizer.h" 10 #include "vm/branch_optimizer.h"
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 continue; 170 continue;
171 } 171 }
172 if (current->IsPolymorphicInstanceCall()) { 172 if (current->IsPolymorphicInstanceCall()) {
173 PolymorphicInstanceCallInstr* call = 173 PolymorphicInstanceCallInstr* call =
174 current->AsPolymorphicInstanceCall(); 174 current->AsPolymorphicInstanceCall();
175 // These checks make sure that the number of call-sites counted does 175 // These checks make sure that the number of call-sites counted does
176 // not change relative to the time when the current set of inlining 176 // not change relative to the time when the current set of inlining
177 // parameters was fixed. 177 // parameters was fixed.
178 // TODO(fschneider): Determine new heuristic parameters that avoid 178 // TODO(fschneider): Determine new heuristic parameters that avoid
179 // these checks entirely. 179 // these checks entirely.
180 if (!call->HasSingleRecognizedTarget() && 180 if (!call->IsSureToCallSingleRecognizedTarget() &&
181 (call->instance_call()->token_kind() != Token::kEQ)) { 181 (call->instance_call()->token_kind() != Token::kEQ)) {
182 ++call_site_count_; 182 ++call_site_count_;
183 } 183 }
184 } 184 }
185 } 185 }
186 } 186 }
187 } 187 }
188 188
189 intptr_t call_site_count() const { return call_site_count_; } 189 intptr_t call_site_count() const { return call_site_count_; }
190 intptr_t instruction_count() const { return instruction_count_; } 190 intptr_t instruction_count() const { return instruction_count_; }
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 intptr_t instance_call_start_ix) { 283 intptr_t instance_call_start_ix) {
284 const intptr_t num_static_calls = 284 const intptr_t num_static_calls =
285 static_calls_.length() - static_call_start_ix; 285 static_calls_.length() - static_call_start_ix;
286 const intptr_t num_instance_calls = 286 const intptr_t num_instance_calls =
287 instance_calls_.length() - instance_call_start_ix; 287 instance_calls_.length() - instance_call_start_ix;
288 288
289 intptr_t max_count = 0; 289 intptr_t max_count = 0;
290 GrowableArray<intptr_t> instance_call_counts(num_instance_calls); 290 GrowableArray<intptr_t> instance_call_counts(num_instance_calls);
291 for (intptr_t i = 0; i < num_instance_calls; ++i) { 291 for (intptr_t i = 0; i < num_instance_calls; ++i) {
292 const intptr_t aggregate_count = 292 const intptr_t aggregate_count =
293 instance_calls_[i + instance_call_start_ix] 293 instance_calls_[i + instance_call_start_ix].call->CallCount();
294 .call->ic_data()
295 .AggregateCount();
296 instance_call_counts.Add(aggregate_count); 294 instance_call_counts.Add(aggregate_count);
297 if (aggregate_count > max_count) max_count = aggregate_count; 295 if (aggregate_count > max_count) max_count = aggregate_count;
298 } 296 }
299 297
300 GrowableArray<intptr_t> static_call_counts(num_static_calls); 298 GrowableArray<intptr_t> static_call_counts(num_static_calls);
301 for (intptr_t i = 0; i < num_static_calls; ++i) { 299 for (intptr_t i = 0; i < num_static_calls; ++i) {
302 intptr_t aggregate_count = 0; 300 intptr_t aggregate_count = 0;
303 if (static_calls_[i + static_call_start_ix].call->ic_data() == NULL) { 301 if (static_calls_[i + static_call_start_ix].call->ic_data() == NULL) {
304 aggregate_count = 0; 302 aggregate_count = 0;
305 } else { 303 } else {
(...skipping 30 matching lines...) Expand all
336 Function& target = Function::ZoneHandle(); 334 Function& target = Function::ZoneHandle();
337 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done(); 335 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done();
338 block_it.Advance()) { 336 block_it.Advance()) {
339 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); 337 for (ForwardInstructionIterator it(block_it.Current()); !it.Done();
340 it.Advance()) { 338 it.Advance()) {
341 Instruction* current = it.Current(); 339 Instruction* current = it.Current();
342 Definition* call = NULL; 340 Definition* call = NULL;
343 if (current->IsPolymorphicInstanceCall()) { 341 if (current->IsPolymorphicInstanceCall()) {
344 PolymorphicInstanceCallInstr* instance_call = 342 PolymorphicInstanceCallInstr* instance_call =
345 current->AsPolymorphicInstanceCall(); 343 current->AsPolymorphicInstanceCall();
346 target = instance_call->ic_data().GetTargetAt(0); 344 target ^= instance_call->targets().FirstTarget().raw();
347 call = instance_call; 345 call = instance_call;
348 } else if (current->IsStaticCall()) { 346 } else if (current->IsStaticCall()) {
349 StaticCallInstr* static_call = current->AsStaticCall(); 347 StaticCallInstr* static_call = current->AsStaticCall();
350 target = static_call->function().raw(); 348 target ^= static_call->function().raw();
351 call = static_call; 349 call = static_call;
352 } else if (current->IsClosureCall()) { 350 } else if (current->IsClosureCall()) {
353 // TODO(srdjan): Add data for closure calls. 351 // TODO(srdjan): Add data for closure calls.
354 } 352 }
355 if (call != NULL) { 353 if (call != NULL) {
356 inlined_info->Add( 354 inlined_info->Add(
357 InlinedInfo(caller, &target, depth + 1, call, "Too deep")); 355 InlinedInfo(caller, &target, depth + 1, call, "Too deep"));
358 } 356 }
359 } 357 }
360 } 358 }
(...skipping 20 matching lines...) Expand all
381 const intptr_t static_call_start_ix = static_calls_.length(); 379 const intptr_t static_call_start_ix = static_calls_.length();
382 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done(); 380 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done();
383 block_it.Advance()) { 381 block_it.Advance()) {
384 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); 382 for (ForwardInstructionIterator it(block_it.Current()); !it.Done();
385 it.Advance()) { 383 it.Advance()) {
386 Instruction* current = it.Current(); 384 Instruction* current = it.Current();
387 if (current->IsPolymorphicInstanceCall()) { 385 if (current->IsPolymorphicInstanceCall()) {
388 PolymorphicInstanceCallInstr* instance_call = 386 PolymorphicInstanceCallInstr* instance_call =
389 current->AsPolymorphicInstanceCall(); 387 current->AsPolymorphicInstanceCall();
390 if (!inline_only_recognized_methods || 388 if (!inline_only_recognized_methods ||
391 instance_call->HasSingleRecognizedTarget() || 389 instance_call->IsSureToCallSingleRecognizedTarget() ||
392 instance_call->ic_data() 390 instance_call->HasOnlyDispatcherOrImplicitAccessorTargets()) {
393 .HasOnlyDispatcherOrImplicitAccessorTargets()) {
394 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); 391 instance_calls_.Add(InstanceCallInfo(instance_call, graph));
395 } else { 392 } else {
396 // Method not inlined because inlining too deep and method 393 // Method not inlined because inlining too deep and method
397 // not recognized. 394 // not recognized.
398 if (FLAG_print_inlining_tree) { 395 if (FLAG_print_inlining_tree) {
399 const Function* caller = &graph->function(); 396 const Function* caller = &graph->function();
400 const Function* target = &Function::ZoneHandle( 397 const Function* target = &instance_call->targets().FirstTarget();
401 instance_call->ic_data().GetTargetAt(0));
402 inlined_info->Add(InlinedInfo(caller, target, depth + 1, 398 inlined_info->Add(InlinedInfo(caller, target, depth + 1,
403 instance_call, "Too deep")); 399 instance_call, "Too deep"));
404 } 400 }
405 } 401 }
406 } else if (current->IsStaticCall()) { 402 } else if (current->IsStaticCall()) {
407 StaticCallInstr* static_call = current->AsStaticCall(); 403 StaticCallInstr* static_call = current->AsStaticCall();
408 if (!inline_only_recognized_methods || 404 if (!inline_only_recognized_methods ||
409 static_call->function().IsRecognized() || 405 static_call->function().IsRecognized() ||
410 static_call->function().IsDispatcherOrImplicitAccessor()) { 406 static_call->function().IsDispatcherOrImplicitAccessor()) {
411 static_calls_.Add(StaticCallInfo(static_call, graph)); 407 static_calls_.Add(StaticCallInfo(static_call, graph));
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 TargetEntryInstr* BuildDecisionGraph(); 480 TargetEntryInstr* BuildDecisionGraph();
485 481
486 Isolate* isolate() const; 482 Isolate* isolate() const;
487 Zone* zone() const; 483 Zone* zone() const;
488 intptr_t AllocateBlockId() const; 484 intptr_t AllocateBlockId() const;
489 inline bool trace_inlining() const; 485 inline bool trace_inlining() const;
490 486
491 CallSiteInliner* const owner_; 487 CallSiteInliner* const owner_;
492 PolymorphicInstanceCallInstr* const call_; 488 PolymorphicInstanceCallInstr* const call_;
493 const intptr_t num_variants_; 489 const intptr_t num_variants_;
494 GrowableArray<CidRangeTarget> variants_; 490 const CallTargets& variants_;
495 491
496 GrowableArray<CidRangeTarget> inlined_variants_; 492 CallTargets inlined_variants_;
497 GrowableArray<CidRangeTarget> non_inlined_variants_; 493 // The non_inlined_variants_ can be used in a long-lived instruction object,
494 // so they are not embedded into the shorter-lived PolymorphicInliner object.
495 CallTargets* non_inlined_variants_;
498 GrowableArray<BlockEntryInstr*> inlined_entries_; 496 GrowableArray<BlockEntryInstr*> inlined_entries_;
499 InlineExitCollector* exit_collector_; 497 InlineExitCollector* exit_collector_;
500 498
501 const Function& caller_function_; 499 const Function& caller_function_;
502 const intptr_t caller_inlining_id_; 500 const intptr_t caller_inlining_id_;
503 }; 501 };
504 502
505 503
506 static bool HasAnnotation(const Function& function, const char* annotation) { 504 static bool HasAnnotation(const Function& function, const char* annotation) {
507 const Class& owner = Class::Handle(function.Owner()); 505 const Class& owner = Class::Handle(function.Owner());
(...skipping 790 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 continue; 1296 continue;
1299 } 1297 }
1300 const Function& cl = call_info[call_idx].caller(); 1298 const Function& cl = call_info[call_idx].caller();
1301 intptr_t caller_inlining_id = 1299 intptr_t caller_inlining_id =
1302 call_info[call_idx].caller_graph->inlining_id(); 1300 call_info[call_idx].caller_graph->inlining_id();
1303 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); 1301 PolymorphicInliner inliner(this, call, cl, caller_inlining_id);
1304 inliner.Inline(); 1302 inliner.Inline();
1305 continue; 1303 continue;
1306 } 1304 }
1307 1305
1308 const ICData& ic_data = call->ic_data(); 1306 const Function& target = call->targets().MostPopularTarget();
1309 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
1310 if (!inliner_->AlwaysInline(target) && 1307 if (!inliner_->AlwaysInline(target) &&
1311 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 1308 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
1312 if (trace_inlining()) { 1309 if (trace_inlining()) {
1313 String& name = String::Handle(target.QualifiedUserVisibleName()); 1310 String& name = String::Handle(target.QualifiedUserVisibleName());
1314 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n", 1311 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n",
1315 name.ToCString(), target.deoptimization_counter(), 1312 name.ToCString(), target.deoptimization_counter(),
1316 call_info[call_idx].ratio); 1313 call_info[call_idx].ratio);
1317 } 1314 }
1318 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), &target, 1315 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), &target,
1319 call); 1316 call);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1440 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); 1437 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner);
1441 }; 1438 };
1442 1439
1443 1440
1444 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, 1441 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner,
1445 PolymorphicInstanceCallInstr* call, 1442 PolymorphicInstanceCallInstr* call,
1446 const Function& caller_function, 1443 const Function& caller_function,
1447 intptr_t caller_inlining_id) 1444 intptr_t caller_inlining_id)
1448 : owner_(owner), 1445 : owner_(owner),
1449 call_(call), 1446 call_(call),
1450 num_variants_(call->ic_data().NumberOfChecks()), 1447 num_variants_(call->NumberOfChecks()),
1451 variants_(num_variants_), 1448 variants_(call->targets_),
1452 inlined_variants_(num_variants_), 1449 inlined_variants_(),
1453 non_inlined_variants_(num_variants_), 1450 non_inlined_variants_(new (zone()) CallTargets()),
1454 inlined_entries_(num_variants_), 1451 inlined_entries_(num_variants_),
1455 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), 1452 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)),
1456 caller_function_(caller_function), 1453 caller_function_(caller_function),
1457 caller_inlining_id_(caller_inlining_id) {} 1454 caller_inlining_id_(caller_inlining_id) {}
1458 1455
1459 1456
1460 Isolate* PolymorphicInliner::isolate() const { 1457 Isolate* PolymorphicInliner::isolate() const {
1461 return owner_->caller_graph()->isolate(); 1458 return owner_->caller_graph()->isolate();
1462 } 1459 }
1463 1460
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1527 inlined_entries_.Add(join); 1524 inlined_entries_.Add(join);
1528 return true; 1525 return true;
1529 } 1526 }
1530 } 1527 }
1531 1528
1532 return false; 1529 return false;
1533 } 1530 }
1534 1531
1535 1532
1536 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { 1533 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) {
1537 for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) { 1534 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) {
1538 if (target.raw() == non_inlined_variants_[i].target->raw()) { 1535 if (target.raw() == non_inlined_variants_->At(i).target->raw()) {
1539 return true; 1536 return true;
1540 } 1537 }
1541 } 1538 }
1542 1539
1543 return false; 1540 return false;
1544 } 1541 }
1545 1542
1546 1543
1547 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) { 1544 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) {
1548 if ((!FLAG_precompiled_mode || 1545 if ((!FLAG_precompiled_mode ||
1549 owner_->inliner_->use_speculative_inlining()) && 1546 owner_->inliner_->use_speculative_inlining()) &&
1550 range.cid_start == range.cid_end && 1547 range.cid_start == range.cid_end &&
1551 TryInlineRecognizedMethod(range.cid_start, *range.target)) { 1548 TryInlineRecognizedMethod(range.cid_start, *range.target)) {
1552 owner_->inlined_ = true; 1549 owner_->inlined_ = true;
1553 return true; 1550 return true;
1554 } 1551 }
1555 1552
1556 GrowableArray<Value*> arguments(call_->ArgumentCount()); 1553 GrowableArray<Value*> arguments(call_->ArgumentCount());
1557 for (int i = 0; i < call_->ArgumentCount(); ++i) { 1554 for (int i = 0; i < call_->ArgumentCount(); ++i) {
1558 arguments.Add(call_->PushArgumentAt(i)->value()); 1555 arguments.Add(call_->PushArgumentAt(i)->value());
1559 } 1556 }
1560 InlinedCallData call_data(call_, &arguments, caller_function_, 1557 InlinedCallData call_data(call_, &arguments, caller_function_,
1561 caller_inlining_id_); 1558 caller_inlining_id_);
1562 if (!owner_->TryInlining(*range.target, 1559 Function& target = Function::ZoneHandle(zone(), range.target->raw());
1563 call_->instance_call()->argument_names(), 1560 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(),
1564 &call_data)) { 1561 &call_data)) {
1565 return false; 1562 return false;
1566 } 1563 }
1567 1564
1568 FlowGraph* callee_graph = call_data.callee_graph; 1565 FlowGraph* callee_graph = call_data.callee_graph;
1569 call_data.exit_collector->PrepareGraphs(callee_graph); 1566 call_data.exit_collector->PrepareGraphs(callee_graph);
1570 inlined_entries_.Add(callee_graph->graph_entry()); 1567 inlined_entries_.Add(callee_graph->graph_entry());
1571 exit_collector_->Union(call_data.exit_collector); 1568 exit_collector_->Union(call_data.exit_collector);
1572 1569
1573 // Replace parameter stubs and constants. Replace the receiver argument 1570 // Replace parameter stubs and constants. Replace the receiver argument
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
1701 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { 1698 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
1702 const CidRangeTarget& variant = inlined_variants_[i]; 1699 const CidRangeTarget& variant = inlined_variants_[i];
1703 bool test_is_range = (variant.cid_start != variant.cid_end); 1700 bool test_is_range = (variant.cid_start != variant.cid_end);
1704 bool is_last_test = (i == inlined_variants_.length() - 1); 1701 bool is_last_test = (i == inlined_variants_.length() - 1);
1705 // 1. Guard the body with a class id check. We don't need any check if 1702 // 1. Guard the body with a class id check. We don't need any check if
1706 // it's the last test and global analysis has told us that the call is 1703 // it's the last test and global analysis has told us that the call is
1707 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an 1704 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an
1708 // arbitrary CidRangeTarget. Currently we don't go into this branch if the 1705 // arbitrary CidRangeTarget. Currently we don't go into this branch if the
1709 // last test is a range test - instead we set the follow_with_deopt flag. 1706 // last test is a range test - instead we set the follow_with_deopt flag.
1710 if (is_last_test && (!test_is_range || call_->complete()) && 1707 if (is_last_test && (!test_is_range || call_->complete()) &&
1711 non_inlined_variants_.is_empty()) { 1708 non_inlined_variants_->is_empty()) {
1712 // If it is the last variant use a check class id instruction which can 1709 // If it is the last variant use a check class id instruction which can
1713 // deoptimize, followed unconditionally by the body. Omit the check if 1710 // deoptimize, followed unconditionally by the body. Omit the check if
1714 // we know that we have covered all possible classes. 1711 // we know that we have covered all possible classes.
1715 if (!call_->complete()) { 1712 if (!call_->complete()) {
1716 ASSERT(!test_is_range); // See condition above. 1713 ASSERT(!test_is_range); // See condition above.
1717 RedefinitionInstr* cid_redefinition = 1714 RedefinitionInstr* cid_redefinition =
1718 new RedefinitionInstr(new (Z) Value(load_cid)); 1715 new RedefinitionInstr(new (Z) Value(load_cid));
1719 cid_redefinition->set_ssa_temp_index( 1716 cid_redefinition->set_ssa_temp_index(
1720 owner_->caller_graph()->alloc_ssa_temp_index()); 1717 owner_->caller_graph()->alloc_ssa_temp_index());
1721 cursor = AppendInstruction(cursor, cid_redefinition); 1718 cursor = AppendInstruction(cursor, cid_redefinition);
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1877 false_target2->InheritDeoptTarget(zone(), call_); 1874 false_target2->InheritDeoptTarget(zone(), call_);
1878 goto_1->InheritDeoptTarget(zone(), call_); 1875 goto_1->InheritDeoptTarget(zone(), call_);
1879 goto_2->InheritDeoptTarget(zone(), call_); 1876 goto_2->InheritDeoptTarget(zone(), call_);
1880 1877
1881 cursor = current_block = join; 1878 cursor = current_block = join;
1882 } 1879 }
1883 } 1880 }
1884 } 1881 }
1885 1882
1886 // Handle any non-inlined variants. 1883 // Handle any non-inlined variants.
1887 if (!non_inlined_variants_.is_empty()) { 1884 if (!non_inlined_variants_->is_empty()) {
1888 // Move push arguments of the call. 1885 // Move push arguments of the call.
1889 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { 1886 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) {
1890 PushArgumentInstr* push = call_->PushArgumentAt(i); 1887 PushArgumentInstr* push = call_->PushArgumentAt(i);
1891 push->ReplaceUsesWith(push->value()->definition()); 1888 push->ReplaceUsesWith(push->value()->definition());
1892 push->previous()->LinkTo(push->next()); 1889 push->previous()->LinkTo(push->next());
1893 cursor->LinkTo(push); 1890 cursor->LinkTo(push);
1894 cursor = push; 1891 cursor = push;
1895 } 1892 }
1896 const ICData& old_checks = call_->ic_data();
1897 const ICData& new_checks = ICData::ZoneHandle(ICData::New(
1898 Function::Handle(old_checks.Owner()),
1899 String::Handle(old_checks.target_name()),
1900 Array::Handle(old_checks.arguments_descriptor()), old_checks.deopt_id(),
1901 1, // Number of args tested.
1902 false)); // is_static_call
1903 for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) {
1904 // We are adding all the cids in each range. They will be joined
1905 // together again by the PolymorphicInstanceCall instruction, which is a
1906 // bit messy.
1907 intptr_t count = non_inlined_variants_[i].count;
1908
1909 for (intptr_t j = non_inlined_variants_[i].cid_start;
1910 j <= non_inlined_variants_[i].cid_end; j++) {
1911 new_checks.AddReceiverCheck(j, *non_inlined_variants_[i].target, count);
1912 count = 0;
1913 }
1914 }
1915 PolymorphicInstanceCallInstr* fallback_call = 1893 PolymorphicInstanceCallInstr* fallback_call =
1916 new PolymorphicInstanceCallInstr(call_->instance_call(), new_checks, 1894 new PolymorphicInstanceCallInstr(
1917 /* with_checks = */ true, 1895 call_->instance_call(), *non_inlined_variants_,
1918 call_->complete()); 1896 /* with_checks = */ true, call_->complete());
1919 fallback_call->set_ssa_temp_index( 1897 fallback_call->set_ssa_temp_index(
1920 owner_->caller_graph()->alloc_ssa_temp_index()); 1898 owner_->caller_graph()->alloc_ssa_temp_index());
1921 fallback_call->InheritDeoptTarget(zone(), call_); 1899 fallback_call->InheritDeoptTarget(zone(), call_);
1922 fallback_call->set_total_call_count(call_->CallCount()); 1900 fallback_call->set_total_call_count(call_->CallCount());
1923 ReturnInstr* fallback_return = new ReturnInstr( 1901 ReturnInstr* fallback_return = new ReturnInstr(
1924 call_->instance_call()->token_pos(), new Value(fallback_call)); 1902 call_->instance_call()->token_pos(), new Value(fallback_call));
1925 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, 1903 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_,
1926 fallback_call); 1904 fallback_call);
1927 AppendInstruction(AppendInstruction(cursor, fallback_call), 1905 AppendInstruction(AppendInstruction(cursor, fallback_call),
1928 fallback_return); 1906 fallback_return);
(...skipping 29 matching lines...) Expand all
1958 percent, message); 1936 percent, message);
1959 } 1937 }
1960 1938
1961 1939
1962 bool PolymorphicInliner::trace_inlining() const { 1940 bool PolymorphicInliner::trace_inlining() const {
1963 return owner_->trace_inlining(); 1941 return owner_->trace_inlining();
1964 } 1942 }
1965 1943
1966 1944
1967 void PolymorphicInliner::Inline() { 1945 void PolymorphicInliner::Inline() {
1968 // Consider the polymorphic variants in order by frequency. 1946 ASSERT(&variants_ == &call_->targets_);
1969 FlowGraphCompiler::SortICDataByCount(call_->ic_data(), &variants_, 1947
1970 /* drop_smi = */ false);
1971 intptr_t total = call_->total_call_count(); 1948 intptr_t total = call_->total_call_count();
1972 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { 1949 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) {
1973 if (variants_.length() > FLAG_max_polymorphic_checks) { 1950 if (variants_.length() > FLAG_max_polymorphic_checks) {
1974 non_inlined_variants_.Add(variants_[var_idx]); 1951 non_inlined_variants_->Add(variants_[var_idx]);
1975 continue; 1952 continue;
1976 } 1953 }
1977 1954
1978 // We we almost inlined all the cases then try a little harder to inline 1955 // We we almost inlined all the cases then try a little harder to inline
1979 // the last two, because it's a big win if we inline all of them (compiler 1956 // the last two, because it's a big win if we inline all of them (compiler
1980 // can see all side effects). 1957 // can see all side effects).
1981 const bool try_harder = (var_idx >= variants_.length() - 2) && 1958 const bool try_harder = (var_idx >= variants_.length() - 2) &&
1982 non_inlined_variants_.length() == 0; 1959 non_inlined_variants_->length() == 0;
1983 const Function& target = *variants_[var_idx].target; 1960 const Function& target = *variants_[var_idx].target;
1984 const intptr_t count = variants_[var_idx].count; 1961 const intptr_t count = variants_[var_idx].count;
1985 1962
1986 intptr_t size = target.optimized_instruction_count(); 1963 intptr_t size = target.optimized_instruction_count();
1987 bool small = (size != 0 && size < FLAG_inlining_size_threshold); 1964 bool small = (size != 0 && size < FLAG_inlining_size_threshold);
1988 1965
1989 // If it's less than 3% of the dispatches, we won't even consider 1966 // If it's less than 3% of the dispatches, we won't even consider
1990 // checking for the class ID and branching to another already-inlined 1967 // checking for the class ID and branching to another already-inlined
1991 // version. 1968 // version.
1992 if (!try_harder && count < (total >> 5)) { 1969 if (!try_harder && count < (total >> 5)) {
1993 TRACE_INLINING( 1970 TRACE_INLINING(
1994 TracePolyInlining(variants_[var_idx], total, "way too infrequent")); 1971 TracePolyInlining(variants_[var_idx], total, "way too infrequent"));
1995 non_inlined_variants_.Add(variants_[var_idx]); 1972 non_inlined_variants_->Add(variants_[var_idx]);
1996 continue; 1973 continue;
1997 } 1974 }
1998 1975
1999 // First check if this is the same target as an earlier inlined variant. 1976 // First check if this is the same target as an earlier inlined variant.
2000 if (CheckInlinedDuplicate(target)) { 1977 if (CheckInlinedDuplicate(target)) {
2001 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, 1978 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total,
2002 "duplicate already inlined")); 1979 "duplicate already inlined"));
2003 inlined_variants_.Add(variants_[var_idx]); 1980 inlined_variants_.Add(variants_[var_idx]);
2004 continue; 1981 continue;
2005 } 1982 }
2006 1983
2007 // If it's less than 12% of the dispatches and it's not already inlined, we 1984 // If it's less than 12% of the dispatches and it's not already inlined, we
2008 // don't consider inlining. For very small functions we are willing to 1985 // don't consider inlining. For very small functions we are willing to
2009 // consider inlining for 6% of the cases. 1986 // consider inlining for 6% of the cases.
2010 if (!try_harder && count < (total >> (small ? 4 : 3))) { 1987 if (!try_harder && count < (total >> (small ? 4 : 3))) {
2011 TRACE_INLINING( 1988 TRACE_INLINING(
2012 TracePolyInlining(variants_[var_idx], total, "too infrequent")); 1989 TracePolyInlining(variants_[var_idx], total, "too infrequent"));
2013 non_inlined_variants_.Add(variants_[var_idx]); 1990 non_inlined_variants_->Add(variants_[var_idx]);
2014 continue; 1991 continue;
2015 } 1992 }
2016 1993
2017 // Also check if this is the same target as an earlier non-inlined 1994 // Also check if this is the same target as an earlier non-inlined
2018 // variant. If so and since inlining decisions are costly, do not try 1995 // variant. If so and since inlining decisions are costly, do not try
2019 // to inline this variant. 1996 // to inline this variant.
2020 if (CheckNonInlinedDuplicate(target)) { 1997 if (CheckNonInlinedDuplicate(target)) {
2021 TRACE_INLINING( 1998 TRACE_INLINING(
2022 TracePolyInlining(variants_[var_idx], total, "already not inlined")); 1999 TracePolyInlining(variants_[var_idx], total, "already not inlined"));
2023 non_inlined_variants_.Add(variants_[var_idx]); 2000 non_inlined_variants_->Add(variants_[var_idx]);
2024 continue; 2001 continue;
2025 } 2002 }
2026 2003
2027 // Make an inlining decision. 2004 // Make an inlining decision.
2028 if (TryInliningPoly(variants_[var_idx])) { 2005 if (TryInliningPoly(variants_[var_idx])) {
2029 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined")); 2006 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined"));
2030 inlined_variants_.Add(variants_[var_idx]); 2007 inlined_variants_.Add(variants_[var_idx]);
2031 } else { 2008 } else {
2032 TRACE_INLINING( 2009 TRACE_INLINING(
2033 TracePolyInlining(variants_[var_idx], total, "not inlined")); 2010 TracePolyInlining(variants_[var_idx], total, "not inlined"));
2034 non_inlined_variants_.Add(variants_[var_idx]); 2011 non_inlined_variants_->Add(variants_[var_idx]);
2035 } 2012 }
2036 } 2013 }
2037 2014
2038 // If there are no inlined variants, leave the call in place. 2015 // If there are no inlined variants, leave the call in place.
2039 if (inlined_variants_.is_empty()) return; 2016 if (inlined_variants_.is_empty()) return;
2040 2017
2041 // Now build a decision tree (a DAG because of shared inline variants) and 2018 // Now build a decision tree (a DAG because of shared inline variants) and
2042 // inline it at the call site. 2019 // inline it at the call site.
2043 TargetEntryInstr* entry = BuildDecisionGraph(); 2020 TargetEntryInstr* entry = BuildDecisionGraph();
2044 exit_collector_->ReplaceCall(entry); 2021 exit_collector_->ReplaceCall(entry);
(...skipping 1787 matching lines...) Expand 10 before | Expand all | Expand 10 after
3832 } 3809 }
3833 3810
3834 default: 3811 default:
3835 return false; 3812 return false;
3836 } 3813 }
3837 } 3814 }
3838 3815
3839 3816
3840 } // namespace dart 3817 } // namespace dart
3841 #endif // !defined(DART_PRECOMPILED_RUNTIME) 3818 #endif // !defined(DART_PRECOMPILED_RUNTIME)
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698