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

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

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