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

Unified Diff: runtime/vm/aot_optimizer.cc

Issue 2055263002: VM: Improve specialization of calls on receiver in AOT mode. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 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
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/aot_optimizer.cc
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 25074516d074f0c4042effded046301a806dbc92..63a62534eb28675731d897b186275c10dfdb6524 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -2465,58 +2465,104 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
flow_graph_->IsReceiver(callee_receiver)) {
// Call receiver is method receiver.
Class& receiver_class = Class::Handle(Z, function.Owner());
+
GrowableArray<intptr_t> class_ids(6);
if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) {
- if (class_ids.length() <= FLAG_max_exhaustive_polymorphic_checks) {
- if (FLAG_trace_cha) {
- THR_Print(" **(CHA) Only %" Pd " concrete subclasses of %s for %s\n",
- class_ids.length(),
- receiver_class.ToCString(),
- instr->function_name().ToCString());
- }
-
- const Array& args_desc_array = Array::Handle(Z,
- ArgumentsDescriptor::New(instr->ArgumentCount(),
- instr->argument_names()));
- ArgumentsDescriptor args_desc(args_desc_array);
+ // First check if all subclasses end up calling the same method.
+ // If this is the case we will replace instance call with a direct
+ // static call.
+ // Otherwise we will try to create ICData that contains all possible
+ // targets with appropriate checks.
+ Function& single_target = Function::Handle(Z);
+ ICData& ic_data = ICData::Handle(Z);
+
+ const Array& args_desc_array = Array::Handle(Z,
+ ArgumentsDescriptor::New(instr->ArgumentCount(),
+ instr->argument_names()));
+ ArgumentsDescriptor args_desc(args_desc_array);
+
+ Function& target = Function::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ for (intptr_t i = 0; i < class_ids.length(); i++) {
+ const intptr_t cid = class_ids[i];
+ cls = isolate()->class_table()->At(cid);
+ target = Resolver::ResolveDynamicForReceiverClass(
+ cls,
+ instr->function_name(),
+ args_desc);
+
+ if (target.IsNull()) {
+ // Can't resolve the target. It might be a noSuchMethod,
+ // call through getter or closurization.
+ single_target = Function::null();
+ ic_data = ICData::null();
+ break;
+ } else if (ic_data.IsNull()) {
+ // First we are trying to compute a single target for all subclasses.
+ if (single_target.IsNull()) {
+ ASSERT(i == 0);
+ single_target = target.raw();
+ continue;
+ } else if (single_target.raw() == target.raw()) {
+ continue;
+ }
- const ICData& ic_data = ICData::Handle(
- ICData::New(function,
- instr->function_name(),
- args_desc_array,
- Thread::kNoDeoptId,
- /* args_tested = */ 1));
+ // The call does not resolve to a single target within the hierarchy.
+ // If we have too many subclasses abort the optimization.
+ if (class_ids.length() > FLAG_max_exhaustive_polymorphic_checks) {
+ single_target = Function::null();
+ break;
+ }
- Function& target = Function::Handle(Z);
- Class& cls = Class::Handle(Z);
- bool includes_dispatcher_case = false;
- for (intptr_t i = 0; i < class_ids.length(); i++) {
- intptr_t cid = class_ids[i];
- cls = isolate()->class_table()->At(cid);
- target = Resolver::ResolveDynamicForReceiverClass(
- cls,
- instr->function_name(),
- args_desc);
- if (target.IsNull()) {
- // noSuchMethod, call through getter or closurization
- includes_dispatcher_case = true;
- } else {
- ic_data.AddReceiverCheck(cid, target);
+ // Create an ICData and map all previously seen classes (< i) to
+ // the computed single_target.
+ ic_data = ICData::New(function,
+ instr->function_name(),
+ args_desc_array,
+ Thread::kNoDeoptId,
+ /* args_tested = */ 1);
+ for (intptr_t j = 0; j < i; j++) {
+ ic_data.AddReceiverCheck(class_ids[j], single_target);
}
+
+ single_target = Function::null();
}
- if (!includes_dispatcher_case && (ic_data.NumberOfChecks() > 0)) {
- PolymorphicInstanceCallInstr* call =
- new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
- /* with_checks = */ true,
- /* complete = */ true);
- instr->ReplaceWith(call, current_iterator());
- return;
+
+ ASSERT(ic_data.raw() != ICData::null());
+ ASSERT(single_target.raw() == Function::null());
+ ic_data.AddReceiverCheck(cid, target);
+ }
+
+ if (single_target.raw() != Function::null()) {
+ // We have computed that there is only a single target for this call
+ // within the whole hierarchy. Replace InstanceCall with StaticCall.
+ ZoneGrowableArray<PushArgumentInstr*>* args =
+ new (Z) ZoneGrowableArray<PushArgumentInstr*>(
+ instr->ArgumentCount());
+ for (intptr_t i = 0; i < instr->ArgumentCount(); i++) {
+ args->Add(instr->PushArgumentAt(i));
}
+ StaticCallInstr* call = new (Z) StaticCallInstr(
Florian Schneider 2016/06/10 15:30:18 Alternatively, maybe you can combine this with the
Vyacheslav Egorov (Google) 2016/06/10 16:05:06 I considered combining it - but then I need to cre
+ instr->token_pos(),
+ Function::ZoneHandle(Z, single_target.raw()),
+ instr->argument_names(),
+ args,
+ instr->deopt_id());
+ instr->ReplaceWith(call, current_iterator());
+ return;
+ } else if ((ic_data.raw() != ICData::null()) &&
+ (ic_data.NumberOfChecks() > 0)) {
+ PolymorphicInstanceCallInstr* call =
+ new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
+ /* with_checks = */ true,
+ /* complete = */ true);
+ instr->ReplaceWith(call, current_iterator());
+ return;
}
}
}
- // More than one targets. Generate generic polymorphic call without
+ // More than one target. Generate generic polymorphic call without
// deoptimization.
if (instr->ic_data()->NumberOfUsedChecks() > 0) {
ASSERT(!FLAG_polymorphic_with_deopt);
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698