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

Unified Diff: runtime/vm/flow_graph_inliner.cc

Issue 2809583002: 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 side-by-side diff with in-line comments
Download patch
Index: runtime/vm/flow_graph_inliner.cc
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 9601ea3b8c3791541febc72fa2b3cc4e69cde06c..afaf2bb4c4ba435c3680e3d6aca46f61f964cd41 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -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->FirstTarget().raw();
Vyacheslav Egorov (Google) 2017/04/10 10:59:27 Why are we recording only a single target here? Ma
erikcorry 2017/04/19 15:06:40 Agreed, but that's how I found it.
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.
@@ -389,16 +387,14 @@ class CallSites : public ValueObject {
current->AsPolymorphicInstanceCall();
if (!inline_only_recognized_methods ||
instance_call->HasSingleRecognizedTarget() ||
- instance_call->ic_data()
- .HasOnlyDispatcherOrImplicitAccessorTargets()) {
+ 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->FirstTarget();
Vyacheslav Egorov (Google) 2017/04/10 10:59:27 Ditto.
erikcorry 2017/04/19 15:06:39 Acknowledged.
inlined_info->Add(InlinedInfo(caller, target, depth + 1,
instance_call, "Too deep"));
}
@@ -491,10 +487,10 @@ class PolymorphicInliner : public ValueObject {
CallSiteInliner* const owner_;
PolymorphicInstanceCallInstr* const call_;
const intptr_t num_variants_;
- GrowableArray<CidRangeTarget> variants_;
+ const PolymorphicTargets& variants_;
- GrowableArray<CidRangeTarget> inlined_variants_;
- GrowableArray<CidRangeTarget> non_inlined_variants_;
+ PolymorphicTargets* inlined_variants_;
Vyacheslav Egorov (Google) 2017/04/10 10:59:27 Why not embed this by value? Even if object is zon
erikcorry 2017/04/19 15:06:40 I didn't know you could do that. Done for inlined
+ PolymorphicTargets* non_inlined_variants_;
GrowableArray<BlockEntryInstr*> inlined_entries_;
InlineExitCollector* exit_collector_;
@@ -1305,8 +1301,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->FirstTarget();
Vyacheslav Egorov (Google) 2017/04/10 10:59:27 Why are we looking only on the FirstTarget()? Is t
erikcorry 2017/04/19 15:06:40 Made a synonym called MostPopularTarget. HTH.
if (!inliner_->AlwaysInline(target) &&
(call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
if (trace_inlining()) {
@@ -1447,10 +1442,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_(new (zone()) PolymorphicTargets(zone())),
+ non_inlined_variants_(new (zone()) PolymorphicTargets(zone())),
inlined_entries_(num_variants_),
exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)),
caller_function_(caller_function),
@@ -1482,8 +1477,8 @@ intptr_t PolymorphicInliner::AllocateBlockId() const {
//
// * JoinEntry: the inlined body is shared and this is a subsequent variant.
bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) {
- for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
- if ((target.raw() == inlined_variants_[i].target->raw()) &&
+ for (intptr_t i = 0; i < inlined_variants_->length(); ++i) {
+ if ((target.raw() == inlined_variants_->At(i).target->raw()) &&
!MethodRecognizer::PolymorphicTarget(target)) {
// The call target is shared with a previous inlined variant. Share
// the graph. This requires a join block at the entry, and edge-split
@@ -1534,8 +1529,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 +1554,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;
}
@@ -1698,17 +1693,17 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() {
load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index());
cursor = AppendInstruction(cursor, load_cid);
bool follow_with_deopt = false;
- for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
- const CidRangeTarget& variant = inlined_variants_[i];
+ for (intptr_t i = 0; i < inlined_variants_->length(); ++i) {
+ const CidRangeTarget& variant = inlined_variants_->At(i);
bool test_is_range = (variant.cid_start != variant.cid_end);
- bool is_last_test = (i == inlined_variants_.length() - 1);
+ bool is_last_test = (i == inlined_variants_->length() - 1);
// 1. Guard the body with a class id check. We don't need any check if
// it's the last test and global analysis has told us that the call is
// complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an
// 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 +1879,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 +1888,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 +1941,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 +1954,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 +1967,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;
}
@@ -2000,7 +1975,7 @@ void PolymorphicInliner::Inline() {
if (CheckInlinedDuplicate(target)) {
TRACE_INLINING(TracePolyInlining(variants_[var_idx], total,
"duplicate already inlined"));
- inlined_variants_.Add(variants_[var_idx]);
+ inlined_variants_->Add(variants_[var_idx]);
continue;
}
@@ -2010,7 +1985,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,23 +1995,23 @@ 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;
}
// Make an inlining decision.
if (TryInliningPoly(variants_[var_idx])) {
TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined"));
- inlined_variants_.Add(variants_[var_idx]);
+ inlined_variants_->Add(variants_[var_idx]);
} else {
TRACE_INLINING(
TracePolyInlining(variants_[var_idx], total, "not inlined"));
- non_inlined_variants_.Add(variants_[var_idx]);
+ non_inlined_variants_->Add(variants_[var_idx]);
}
}
// If there are no inlined variants, leave the call in place.
- if (inlined_variants_.is_empty()) return;
+ if (inlined_variants_->is_empty()) return;
// Now build a decision tree (a DAG because of shared inline variants) and
// inline it at the call site.

Powered by Google App Engine
This is Rietveld 408576698