Index: runtime/vm/flow_graph_inliner.cc |
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc |
index 094a557e337c768a5e8211040d632bb3ce833fe8..95e634b1a1815002f21702aa1889bdf8a54acbf0 100644 |
--- a/runtime/vm/flow_graph_inliner.cc |
+++ b/runtime/vm/flow_graph_inliner.cc |
@@ -177,7 +177,7 @@ class GraphInfoCollector : public ValueObject { |
// parameters was fixed. |
// TODO(fschneider): Determine new heuristic parameters that avoid |
// these checks entirely. |
- if (!call->HasSingleRecognizedTarget() && |
+ if (!call->IsSureToCallSingleRecognizedTarget() && |
(call->instance_call()->token_kind() != Token::kEQ)) { |
++call_site_count_; |
} |
@@ -290,9 +290,7 @@ class CallSites : public ValueObject { |
GrowableArray<intptr_t> instance_call_counts(num_instance_calls); |
for (intptr_t i = 0; i < num_instance_calls; ++i) { |
const intptr_t aggregate_count = |
- instance_calls_[i + instance_call_start_ix] |
- .call->ic_data() |
- .AggregateCount(); |
+ instance_calls_[i + instance_call_start_ix].call->CallCount(); |
instance_call_counts.Add(aggregate_count); |
if (aggregate_count > max_count) max_count = aggregate_count; |
} |
@@ -343,11 +341,11 @@ class CallSites : public ValueObject { |
if (current->IsPolymorphicInstanceCall()) { |
PolymorphicInstanceCallInstr* instance_call = |
current->AsPolymorphicInstanceCall(); |
- target = instance_call->ic_data().GetTargetAt(0); |
+ target ^= instance_call->targets().FirstTarget().raw(); |
call = instance_call; |
} else if (current->IsStaticCall()) { |
StaticCallInstr* static_call = current->AsStaticCall(); |
- target = static_call->function().raw(); |
+ target ^= static_call->function().raw(); |
call = static_call; |
} else if (current->IsClosureCall()) { |
// TODO(srdjan): Add data for closure calls. |
@@ -388,17 +386,15 @@ class CallSites : public ValueObject { |
PolymorphicInstanceCallInstr* instance_call = |
current->AsPolymorphicInstanceCall(); |
if (!inline_only_recognized_methods || |
- instance_call->HasSingleRecognizedTarget() || |
- instance_call->ic_data() |
- .HasOnlyDispatcherOrImplicitAccessorTargets()) { |
+ instance_call->IsSureToCallSingleRecognizedTarget() || |
+ instance_call->HasOnlyDispatcherOrImplicitAccessorTargets()) { |
instance_calls_.Add(InstanceCallInfo(instance_call, graph)); |
} else { |
// Method not inlined because inlining too deep and method |
// not recognized. |
if (FLAG_print_inlining_tree) { |
const Function* caller = &graph->function(); |
- const Function* target = &Function::ZoneHandle( |
- instance_call->ic_data().GetTargetAt(0)); |
+ const Function* target = &instance_call->targets().FirstTarget(); |
inlined_info->Add(InlinedInfo(caller, target, depth + 1, |
instance_call, "Too deep")); |
} |
@@ -491,10 +487,12 @@ class PolymorphicInliner : public ValueObject { |
CallSiteInliner* const owner_; |
PolymorphicInstanceCallInstr* const call_; |
const intptr_t num_variants_; |
- GrowableArray<CidRangeTarget> variants_; |
+ const CallTargets& variants_; |
- GrowableArray<CidRangeTarget> inlined_variants_; |
- GrowableArray<CidRangeTarget> non_inlined_variants_; |
+ CallTargets inlined_variants_; |
+ // The non_inlined_variants_ can be used in a long-lived instruction object, |
+ // so they are not embedded into the shorter-lived PolymorphicInliner object. |
+ CallTargets* non_inlined_variants_; |
GrowableArray<BlockEntryInstr*> inlined_entries_; |
InlineExitCollector* exit_collector_; |
@@ -1305,8 +1303,7 @@ class CallSiteInliner : public ValueObject { |
continue; |
} |
- const ICData& ic_data = call->ic_data(); |
- const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
+ const Function& target = call->targets().MostPopularTarget(); |
if (!inliner_->AlwaysInline(target) && |
(call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
if (trace_inlining()) { |
@@ -1447,10 +1444,10 @@ PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
intptr_t caller_inlining_id) |
: owner_(owner), |
call_(call), |
- num_variants_(call->ic_data().NumberOfChecks()), |
- variants_(num_variants_), |
- inlined_variants_(num_variants_), |
- non_inlined_variants_(num_variants_), |
+ num_variants_(call->NumberOfChecks()), |
+ variants_(call->targets_), |
+ inlined_variants_(), |
+ non_inlined_variants_(new (zone()) CallTargets()), |
inlined_entries_(num_variants_), |
exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), |
caller_function_(caller_function), |
@@ -1534,8 +1531,8 @@ bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { |
bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { |
- for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) { |
- if (target.raw() == non_inlined_variants_[i].target->raw()) { |
+ for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) { |
+ if (target.raw() == non_inlined_variants_->At(i).target->raw()) { |
return true; |
} |
} |
@@ -1559,8 +1556,8 @@ bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) { |
} |
InlinedCallData call_data(call_, &arguments, caller_function_, |
caller_inlining_id_); |
- if (!owner_->TryInlining(*range.target, |
- call_->instance_call()->argument_names(), |
+ Function& target = Function::ZoneHandle(zone(), range.target->raw()); |
+ if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), |
&call_data)) { |
return false; |
} |
@@ -1708,7 +1705,7 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
// arbitrary CidRangeTarget. Currently we don't go into this branch if the |
// last test is a range test - instead we set the follow_with_deopt flag. |
if (is_last_test && (!test_is_range || call_->complete()) && |
- non_inlined_variants_.is_empty()) { |
+ non_inlined_variants_->is_empty()) { |
// If it is the last variant use a check class id instruction which can |
// deoptimize, followed unconditionally by the body. Omit the check if |
// we know that we have covered all possible classes. |
@@ -1884,7 +1881,7 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
} |
// Handle any non-inlined variants. |
- if (!non_inlined_variants_.is_empty()) { |
+ if (!non_inlined_variants_->is_empty()) { |
// Move push arguments of the call. |
for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
PushArgumentInstr* push = call_->PushArgumentAt(i); |
@@ -1893,29 +1890,10 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
cursor->LinkTo(push); |
cursor = push; |
} |
- const ICData& old_checks = call_->ic_data(); |
- const ICData& new_checks = ICData::ZoneHandle(ICData::New( |
- Function::Handle(old_checks.Owner()), |
- String::Handle(old_checks.target_name()), |
- Array::Handle(old_checks.arguments_descriptor()), old_checks.deopt_id(), |
- 1, // Number of args tested. |
- false)); // is_static_call |
- for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) { |
- // We are adding all the cids in each range. They will be joined |
- // together again by the PolymorphicInstanceCall instruction, which is a |
- // bit messy. |
- intptr_t count = non_inlined_variants_[i].count; |
- |
- for (intptr_t j = non_inlined_variants_[i].cid_start; |
- j <= non_inlined_variants_[i].cid_end; j++) { |
- new_checks.AddReceiverCheck(j, *non_inlined_variants_[i].target, count); |
- count = 0; |
- } |
- } |
PolymorphicInstanceCallInstr* fallback_call = |
- new PolymorphicInstanceCallInstr(call_->instance_call(), new_checks, |
- /* with_checks = */ true, |
- call_->complete()); |
+ new PolymorphicInstanceCallInstr( |
+ call_->instance_call(), *non_inlined_variants_, |
+ /* with_checks = */ true, call_->complete()); |
fallback_call->set_ssa_temp_index( |
owner_->caller_graph()->alloc_ssa_temp_index()); |
fallback_call->InheritDeoptTarget(zone(), call_); |
@@ -1965,13 +1943,12 @@ bool PolymorphicInliner::trace_inlining() const { |
void PolymorphicInliner::Inline() { |
- // Consider the polymorphic variants in order by frequency. |
- FlowGraphCompiler::SortICDataByCount(call_->ic_data(), &variants_, |
- /* drop_smi = */ false); |
+ ASSERT(&variants_ == &call_->targets_); |
+ |
intptr_t total = call_->total_call_count(); |
for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { |
if (variants_.length() > FLAG_max_polymorphic_checks) { |
- non_inlined_variants_.Add(variants_[var_idx]); |
+ non_inlined_variants_->Add(variants_[var_idx]); |
continue; |
} |
@@ -1979,7 +1956,7 @@ void PolymorphicInliner::Inline() { |
// the last two, because it's a big win if we inline all of them (compiler |
// can see all side effects). |
const bool try_harder = (var_idx >= variants_.length() - 2) && |
- non_inlined_variants_.length() == 0; |
+ non_inlined_variants_->length() == 0; |
const Function& target = *variants_[var_idx].target; |
const intptr_t count = variants_[var_idx].count; |
@@ -1992,7 +1969,7 @@ void PolymorphicInliner::Inline() { |
if (!try_harder && count < (total >> 5)) { |
TRACE_INLINING( |
TracePolyInlining(variants_[var_idx], total, "way too infrequent")); |
- non_inlined_variants_.Add(variants_[var_idx]); |
+ non_inlined_variants_->Add(variants_[var_idx]); |
continue; |
} |
@@ -2010,7 +1987,7 @@ void PolymorphicInliner::Inline() { |
if (!try_harder && count < (total >> (small ? 4 : 3))) { |
TRACE_INLINING( |
TracePolyInlining(variants_[var_idx], total, "too infrequent")); |
- non_inlined_variants_.Add(variants_[var_idx]); |
+ non_inlined_variants_->Add(variants_[var_idx]); |
continue; |
} |
@@ -2020,7 +1997,7 @@ void PolymorphicInliner::Inline() { |
if (CheckNonInlinedDuplicate(target)) { |
TRACE_INLINING( |
TracePolyInlining(variants_[var_idx], total, "already not inlined")); |
- non_inlined_variants_.Add(variants_[var_idx]); |
+ non_inlined_variants_->Add(variants_[var_idx]); |
continue; |
} |
@@ -2031,7 +2008,7 @@ void PolymorphicInliner::Inline() { |
} else { |
TRACE_INLINING( |
TracePolyInlining(variants_[var_idx], total, "not inlined")); |
- non_inlined_variants_.Add(variants_[var_idx]); |
+ non_inlined_variants_->Add(variants_[var_idx]); |
} |
} |