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

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

Issue 2809583002: Use off-heap data for type feedback in PolymorphicInstanceCallInstr (Closed)
Patch Set: Feedback from Slava 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
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->targets().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] 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->targets().HasSingleRecognizedTarget() ||
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 CallTargets* non_inlined_variants_;
Vyacheslav Egorov (Google) 2017/04/20 16:45:33 Add a comment that non_inlined_variants_ can be us
erikcorry 2017/04/21 13:04:44 Done.
498 GrowableArray<BlockEntryInstr*> inlined_entries_; 494 GrowableArray<BlockEntryInstr*> inlined_entries_;
499 InlineExitCollector* exit_collector_; 495 InlineExitCollector* exit_collector_;
500 496
501 const Function& caller_function_; 497 const Function& caller_function_;
502 const intptr_t caller_inlining_id_; 498 const intptr_t caller_inlining_id_;
503 }; 499 };
504 500
505 501
506 static bool HasAnnotation(const Function& function, const char* annotation) { 502 static bool HasAnnotation(const Function& function, const char* annotation) {
507 const Class& owner = Class::Handle(function.Owner()); 503 const Class& owner = Class::Handle(function.Owner());
(...skipping 790 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 continue; 1294 continue;
1299 } 1295 }
1300 const Function& cl = call_info[call_idx].caller(); 1296 const Function& cl = call_info[call_idx].caller();
1301 intptr_t caller_inlining_id = 1297 intptr_t caller_inlining_id =
1302 call_info[call_idx].caller_graph->inlining_id(); 1298 call_info[call_idx].caller_graph->inlining_id();
1303 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); 1299 PolymorphicInliner inliner(this, call, cl, caller_inlining_id);
1304 inliner.Inline(); 1300 inliner.Inline();
1305 continue; 1301 continue;
1306 } 1302 }
1307 1303
1308 const ICData& ic_data = call->ic_data(); 1304 const Function& target = call->targets().MostPopularTarget();
1309 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
1310 if (!inliner_->AlwaysInline(target) && 1305 if (!inliner_->AlwaysInline(target) &&
1311 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 1306 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
1312 if (trace_inlining()) { 1307 if (trace_inlining()) {
1313 String& name = String::Handle(target.QualifiedUserVisibleName()); 1308 String& name = String::Handle(target.QualifiedUserVisibleName());
1314 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n", 1309 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n",
1315 name.ToCString(), target.deoptimization_counter(), 1310 name.ToCString(), target.deoptimization_counter(),
1316 call_info[call_idx].ratio); 1311 call_info[call_idx].ratio);
1317 } 1312 }
1318 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), &target, 1313 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), &target,
1319 call); 1314 call);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1440 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); 1435 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner);
1441 }; 1436 };
1442 1437
1443 1438
1444 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, 1439 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner,
1445 PolymorphicInstanceCallInstr* call, 1440 PolymorphicInstanceCallInstr* call,
1446 const Function& caller_function, 1441 const Function& caller_function,
1447 intptr_t caller_inlining_id) 1442 intptr_t caller_inlining_id)
1448 : owner_(owner), 1443 : owner_(owner),
1449 call_(call), 1444 call_(call),
1450 num_variants_(call->ic_data().NumberOfChecks()), 1445 num_variants_(call->NumberOfChecks()),
1451 variants_(num_variants_), 1446 variants_(call->targets_),
1452 inlined_variants_(num_variants_), 1447 inlined_variants_(),
1453 non_inlined_variants_(num_variants_), 1448 non_inlined_variants_(new (zone()) CallTargets()),
1454 inlined_entries_(num_variants_), 1449 inlined_entries_(num_variants_),
1455 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), 1450 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)),
1456 caller_function_(caller_function), 1451 caller_function_(caller_function),
1457 caller_inlining_id_(caller_inlining_id) {} 1452 caller_inlining_id_(caller_inlining_id) {}
1458 1453
1459 1454
1460 Isolate* PolymorphicInliner::isolate() const { 1455 Isolate* PolymorphicInliner::isolate() const {
1461 return owner_->caller_graph()->isolate(); 1456 return owner_->caller_graph()->isolate();
1462 } 1457 }
1463 1458
(...skipping 12 matching lines...) Expand all
1476 // inlined target. This sharing is represented by using three different 1471 // inlined target. This sharing is represented by using three different
1477 // types of entries in the inlined_entries_ array: 1472 // types of entries in the inlined_entries_ array:
1478 // 1473 //
1479 // * GraphEntry: the inlined body is not shared. 1474 // * GraphEntry: the inlined body is not shared.
1480 // 1475 //
1481 // * TargetEntry: the inlined body is shared and this is the first variant. 1476 // * TargetEntry: the inlined body is shared and this is the first variant.
1482 // 1477 //
1483 // * JoinEntry: the inlined body is shared and this is a subsequent variant. 1478 // * JoinEntry: the inlined body is shared and this is a subsequent variant.
1484 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { 1479 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) {
1485 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { 1480 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
1486 if ((target.raw() == inlined_variants_[i].target->raw()) && 1481 if ((target.raw() == inlined_variants_.At(i).target->raw()) &&
Vyacheslav Egorov (Google) 2017/04/20 16:45:33 just [i] should work?
erikcorry 2017/04/21 13:04:44 Done.
1487 !MethodRecognizer::PolymorphicTarget(target)) { 1482 !MethodRecognizer::PolymorphicTarget(target)) {
1488 // The call target is shared with a previous inlined variant. Share 1483 // The call target is shared with a previous inlined variant. Share
1489 // the graph. This requires a join block at the entry, and edge-split 1484 // the graph. This requires a join block at the entry, and edge-split
1490 // form requires a target for each branch. 1485 // form requires a target for each branch.
1491 // 1486 //
1492 // Represent the sharing by recording a fresh target for the first 1487 // Represent the sharing by recording a fresh target for the first
1493 // variant and the shared join for all later variants. 1488 // variant and the shared join for all later variants.
1494 if (inlined_entries_[i]->IsGraphEntry()) { 1489 if (inlined_entries_[i]->IsGraphEntry()) {
1495 // Convert the old target entry to a new join entry. 1490 // Convert the old target entry to a new join entry.
1496 TargetEntryInstr* old_target = 1491 TargetEntryInstr* old_target =
(...skipping 30 matching lines...) Expand all
1527 inlined_entries_.Add(join); 1522 inlined_entries_.Add(join);
1528 return true; 1523 return true;
1529 } 1524 }
1530 } 1525 }
1531 1526
1532 return false; 1527 return false;
1533 } 1528 }
1534 1529
1535 1530
1536 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { 1531 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) {
1537 for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) { 1532 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) {
1538 if (target.raw() == non_inlined_variants_[i].target->raw()) { 1533 if (target.raw() == non_inlined_variants_->At(i).target->raw()) {
1539 return true; 1534 return true;
1540 } 1535 }
1541 } 1536 }
1542 1537
1543 return false; 1538 return false;
1544 } 1539 }
1545 1540
1546 1541
1547 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) { 1542 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) {
1548 if ((!FLAG_precompiled_mode || 1543 if ((!FLAG_precompiled_mode ||
1549 owner_->inliner_->use_speculative_inlining()) && 1544 owner_->inliner_->use_speculative_inlining()) &&
1550 range.cid_start == range.cid_end && 1545 range.cid_start == range.cid_end &&
1551 TryInlineRecognizedMethod(range.cid_start, *range.target)) { 1546 TryInlineRecognizedMethod(range.cid_start, *range.target)) {
1552 owner_->inlined_ = true; 1547 owner_->inlined_ = true;
1553 return true; 1548 return true;
1554 } 1549 }
1555 1550
1556 GrowableArray<Value*> arguments(call_->ArgumentCount()); 1551 GrowableArray<Value*> arguments(call_->ArgumentCount());
1557 for (int i = 0; i < call_->ArgumentCount(); ++i) { 1552 for (int i = 0; i < call_->ArgumentCount(); ++i) {
1558 arguments.Add(call_->PushArgumentAt(i)->value()); 1553 arguments.Add(call_->PushArgumentAt(i)->value());
1559 } 1554 }
1560 InlinedCallData call_data(call_, &arguments, caller_function_, 1555 InlinedCallData call_data(call_, &arguments, caller_function_,
1561 caller_inlining_id_); 1556 caller_inlining_id_);
1562 if (!owner_->TryInlining(*range.target, 1557 Function& target = Function::ZoneHandle(zone(), range.target->raw());
1563 call_->instance_call()->argument_names(), 1558 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(),
1564 &call_data)) { 1559 &call_data)) {
1565 return false; 1560 return false;
1566 } 1561 }
1567 1562
1568 FlowGraph* callee_graph = call_data.callee_graph; 1563 FlowGraph* callee_graph = call_data.callee_graph;
1569 call_data.exit_collector->PrepareGraphs(callee_graph); 1564 call_data.exit_collector->PrepareGraphs(callee_graph);
1570 inlined_entries_.Add(callee_graph->graph_entry()); 1565 inlined_entries_.Add(callee_graph->graph_entry());
1571 exit_collector_->Union(call_data.exit_collector); 1566 exit_collector_->Union(call_data.exit_collector);
1572 1567
1573 // Replace parameter stubs and constants. Replace the receiver argument 1568 // 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) { 1696 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
1702 const CidRangeTarget& variant = inlined_variants_[i]; 1697 const CidRangeTarget& variant = inlined_variants_[i];
1703 bool test_is_range = (variant.cid_start != variant.cid_end); 1698 bool test_is_range = (variant.cid_start != variant.cid_end);
1704 bool is_last_test = (i == inlined_variants_.length() - 1); 1699 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 1700 // 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 1701 // 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 1702 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an
1708 // arbitrary CidRangeTarget. Currently we don't go into this branch if the 1703 // 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. 1704 // last test is a range test - instead we set the follow_with_deopt flag.
1710 if (is_last_test && (!test_is_range || call_->complete()) && 1705 if (is_last_test && (!test_is_range || call_->complete()) &&
1711 non_inlined_variants_.is_empty()) { 1706 non_inlined_variants_->is_empty()) {
1712 // If it is the last variant use a check class id instruction which can 1707 // 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 1708 // deoptimize, followed unconditionally by the body. Omit the check if
1714 // we know that we have covered all possible classes. 1709 // we know that we have covered all possible classes.
1715 if (!call_->complete()) { 1710 if (!call_->complete()) {
1716 ASSERT(!test_is_range); // See condition above. 1711 ASSERT(!test_is_range); // See condition above.
1717 RedefinitionInstr* cid_redefinition = 1712 RedefinitionInstr* cid_redefinition =
1718 new RedefinitionInstr(new (Z) Value(load_cid)); 1713 new RedefinitionInstr(new (Z) Value(load_cid));
1719 cid_redefinition->set_ssa_temp_index( 1714 cid_redefinition->set_ssa_temp_index(
1720 owner_->caller_graph()->alloc_ssa_temp_index()); 1715 owner_->caller_graph()->alloc_ssa_temp_index());
1721 cursor = AppendInstruction(cursor, cid_redefinition); 1716 cursor = AppendInstruction(cursor, cid_redefinition);
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1877 false_target2->InheritDeoptTarget(zone(), call_); 1872 false_target2->InheritDeoptTarget(zone(), call_);
1878 goto_1->InheritDeoptTarget(zone(), call_); 1873 goto_1->InheritDeoptTarget(zone(), call_);
1879 goto_2->InheritDeoptTarget(zone(), call_); 1874 goto_2->InheritDeoptTarget(zone(), call_);
1880 1875
1881 cursor = current_block = join; 1876 cursor = current_block = join;
1882 } 1877 }
1883 } 1878 }
1884 } 1879 }
1885 1880
1886 // Handle any non-inlined variants. 1881 // Handle any non-inlined variants.
1887 if (!non_inlined_variants_.is_empty()) { 1882 if (!non_inlined_variants_->is_empty()) {
1888 // Move push arguments of the call. 1883 // Move push arguments of the call.
1889 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { 1884 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) {
1890 PushArgumentInstr* push = call_->PushArgumentAt(i); 1885 PushArgumentInstr* push = call_->PushArgumentAt(i);
1891 push->ReplaceUsesWith(push->value()->definition()); 1886 push->ReplaceUsesWith(push->value()->definition());
1892 push->previous()->LinkTo(push->next()); 1887 push->previous()->LinkTo(push->next());
1893 cursor->LinkTo(push); 1888 cursor->LinkTo(push);
1894 cursor = push; 1889 cursor = push;
1895 } 1890 }
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 = 1891 PolymorphicInstanceCallInstr* fallback_call =
1916 new PolymorphicInstanceCallInstr(call_->instance_call(), new_checks, 1892 new PolymorphicInstanceCallInstr(
1917 /* with_checks = */ true, 1893 call_->instance_call(), *non_inlined_variants_,
1918 call_->complete()); 1894 /* with_checks = */ true, call_->complete());
1919 fallback_call->set_ssa_temp_index( 1895 fallback_call->set_ssa_temp_index(
1920 owner_->caller_graph()->alloc_ssa_temp_index()); 1896 owner_->caller_graph()->alloc_ssa_temp_index());
1921 fallback_call->InheritDeoptTarget(zone(), call_); 1897 fallback_call->InheritDeoptTarget(zone(), call_);
1922 fallback_call->set_total_call_count(call_->CallCount()); 1898 fallback_call->set_total_call_count(call_->CallCount());
1923 ReturnInstr* fallback_return = new ReturnInstr( 1899 ReturnInstr* fallback_return = new ReturnInstr(
1924 call_->instance_call()->token_pos(), new Value(fallback_call)); 1900 call_->instance_call()->token_pos(), new Value(fallback_call));
1925 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, 1901 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_,
1926 fallback_call); 1902 fallback_call);
1927 AppendInstruction(AppendInstruction(cursor, fallback_call), 1903 AppendInstruction(AppendInstruction(cursor, fallback_call),
1928 fallback_return); 1904 fallback_return);
(...skipping 29 matching lines...) Expand all
1958 percent, message); 1934 percent, message);
1959 } 1935 }
1960 1936
1961 1937
1962 bool PolymorphicInliner::trace_inlining() const { 1938 bool PolymorphicInliner::trace_inlining() const {
1963 return owner_->trace_inlining(); 1939 return owner_->trace_inlining();
1964 } 1940 }
1965 1941
1966 1942
1967 void PolymorphicInliner::Inline() { 1943 void PolymorphicInliner::Inline() {
1968 // Consider the polymorphic variants in order by frequency. 1944 ASSERT(&variants_ == &call_->targets_);
1969 FlowGraphCompiler::SortICDataByCount(call_->ic_data(), &variants_, 1945
1970 /* drop_smi = */ false);
1971 intptr_t total = call_->total_call_count(); 1946 intptr_t total = call_->total_call_count();
1972 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { 1947 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) {
1973 if (variants_.length() > FLAG_max_polymorphic_checks) { 1948 if (variants_.length() > FLAG_max_polymorphic_checks) {
1974 non_inlined_variants_.Add(variants_[var_idx]); 1949 non_inlined_variants_->Add(variants_[var_idx]);
1975 continue; 1950 continue;
1976 } 1951 }
1977 1952
1978 // We we almost inlined all the cases then try a little harder to inline 1953 // 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 1954 // the last two, because it's a big win if we inline all of them (compiler
1980 // can see all side effects). 1955 // can see all side effects).
1981 const bool try_harder = (var_idx >= variants_.length() - 2) && 1956 const bool try_harder = (var_idx >= variants_.length() - 2) &&
1982 non_inlined_variants_.length() == 0; 1957 non_inlined_variants_->length() == 0;
1983 const Function& target = *variants_[var_idx].target; 1958 const Function& target = *variants_[var_idx].target;
1984 const intptr_t count = variants_[var_idx].count; 1959 const intptr_t count = variants_[var_idx].count;
1985 1960
1986 intptr_t size = target.optimized_instruction_count(); 1961 intptr_t size = target.optimized_instruction_count();
1987 bool small = (size != 0 && size < FLAG_inlining_size_threshold); 1962 bool small = (size != 0 && size < FLAG_inlining_size_threshold);
1988 1963
1989 // If it's less than 3% of the dispatches, we won't even consider 1964 // 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 1965 // checking for the class ID and branching to another already-inlined
1991 // version. 1966 // version.
1992 if (!try_harder && count < (total >> 5)) { 1967 if (!try_harder && count < (total >> 5)) {
1993 TRACE_INLINING( 1968 TRACE_INLINING(
1994 TracePolyInlining(variants_[var_idx], total, "way too infrequent")); 1969 TracePolyInlining(variants_[var_idx], total, "way too infrequent"));
1995 non_inlined_variants_.Add(variants_[var_idx]); 1970 non_inlined_variants_->Add(variants_[var_idx]);
1996 continue; 1971 continue;
1997 } 1972 }
1998 1973
1999 // First check if this is the same target as an earlier inlined variant. 1974 // First check if this is the same target as an earlier inlined variant.
2000 if (CheckInlinedDuplicate(target)) { 1975 if (CheckInlinedDuplicate(target)) {
2001 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, 1976 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total,
2002 "duplicate already inlined")); 1977 "duplicate already inlined"));
2003 inlined_variants_.Add(variants_[var_idx]); 1978 inlined_variants_.Add(variants_[var_idx]);
2004 continue; 1979 continue;
2005 } 1980 }
2006 1981
2007 // If it's less than 12% of the dispatches and it's not already inlined, we 1982 // 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 1983 // don't consider inlining. For very small functions we are willing to
2009 // consider inlining for 6% of the cases. 1984 // consider inlining for 6% of the cases.
2010 if (!try_harder && count < (total >> (small ? 4 : 3))) { 1985 if (!try_harder && count < (total >> (small ? 4 : 3))) {
2011 TRACE_INLINING( 1986 TRACE_INLINING(
2012 TracePolyInlining(variants_[var_idx], total, "too infrequent")); 1987 TracePolyInlining(variants_[var_idx], total, "too infrequent"));
2013 non_inlined_variants_.Add(variants_[var_idx]); 1988 non_inlined_variants_->Add(variants_[var_idx]);
2014 continue; 1989 continue;
2015 } 1990 }
2016 1991
2017 // Also check if this is the same target as an earlier non-inlined 1992 // 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 1993 // variant. If so and since inlining decisions are costly, do not try
2019 // to inline this variant. 1994 // to inline this variant.
2020 if (CheckNonInlinedDuplicate(target)) { 1995 if (CheckNonInlinedDuplicate(target)) {
2021 TRACE_INLINING( 1996 TRACE_INLINING(
2022 TracePolyInlining(variants_[var_idx], total, "already not inlined")); 1997 TracePolyInlining(variants_[var_idx], total, "already not inlined"));
2023 non_inlined_variants_.Add(variants_[var_idx]); 1998 non_inlined_variants_->Add(variants_[var_idx]);
2024 continue; 1999 continue;
2025 } 2000 }
2026 2001
2027 // Make an inlining decision. 2002 // Make an inlining decision.
2028 if (TryInliningPoly(variants_[var_idx])) { 2003 if (TryInliningPoly(variants_[var_idx])) {
2029 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined")); 2004 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined"));
2030 inlined_variants_.Add(variants_[var_idx]); 2005 inlined_variants_.Add(variants_[var_idx]);
2031 } else { 2006 } else {
2032 TRACE_INLINING( 2007 TRACE_INLINING(
2033 TracePolyInlining(variants_[var_idx], total, "not inlined")); 2008 TracePolyInlining(variants_[var_idx], total, "not inlined"));
2034 non_inlined_variants_.Add(variants_[var_idx]); 2009 non_inlined_variants_->Add(variants_[var_idx]);
2035 } 2010 }
2036 } 2011 }
2037 2012
2038 // If there are no inlined variants, leave the call in place. 2013 // If there are no inlined variants, leave the call in place.
2039 if (inlined_variants_.is_empty()) return; 2014 if (inlined_variants_.is_empty()) return;
2040 2015
2041 // Now build a decision tree (a DAG because of shared inline variants) and 2016 // Now build a decision tree (a DAG because of shared inline variants) and
2042 // inline it at the call site. 2017 // inline it at the call site.
2043 TargetEntryInstr* entry = BuildDecisionGraph(); 2018 TargetEntryInstr* entry = BuildDecisionGraph();
2044 exit_collector_->ReplaceCall(entry); 2019 exit_collector_->ReplaceCall(entry);
(...skipping 1787 matching lines...) Expand 10 before | Expand all | Expand 10 after
3832 } 3807 }
3833 3808
3834 default: 3809 default:
3835 return false; 3810 return false;
3836 } 3811 }
3837 } 3812 }
3838 3813
3839 3814
3840 } // namespace dart 3815 } // namespace dart
3841 #endif // !defined(DART_PRECOMPILED_RUNTIME) 3816 #endif // !defined(DART_PRECOMPILED_RUNTIME)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698