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

Unified Diff: runtime/vm/flow_graph_optimizer.cc

Issue 1410733006: More general CHA-based inlining and devirtualization for precompiled code. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 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_optimizer.cc
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 8a65ee8946d35e3ba3972d77b4aece9e5d032523..45e4d6af3ccc46ab0528608f8352cb7362ee04c7 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -187,8 +187,7 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
- const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid();
- class_ids.Add(cid);
+ class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
}
const Token::Kind op_kind = call->token_kind();
@@ -218,10 +217,6 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
}
if (all_cids_known) {
- const Array& args_desc_array = Array::Handle(Z,
- ArgumentsDescriptor::New(call->ArgumentCount(),
- call->argument_names()));
- ArgumentsDescriptor args_desc(args_desc_array);
const Class& receiver_class = Class::Handle(Z,
isolate()->class_table()->At(class_ids[0]));
if (!receiver_class.is_finalized()) {
@@ -230,6 +225,10 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
// finalized yet.
return false;
}
+ const Array& args_desc_array = Array::Handle(Z,
+ ArgumentsDescriptor::New(call->ArgumentCount(),
+ call->argument_names()));
+ ArgumentsDescriptor args_desc(args_desc_array);
const Function& function = Function::Handle(Z,
Resolver::ResolveDynamicForReceiverClass(
receiver_class,
@@ -4309,37 +4308,109 @@ void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
// TODO(srdjan): Investigate other attempts, as they are not allowed to
// deoptimize.
+
+ // Type test is special as it always gets converted into inlined code.
const Token::Kind op_kind = instr->token_kind();
+ if (Token::IsTypeTestOperator(op_kind)) {
+ ReplaceWithInstanceOf(instr);
+ return;
+ }
+ if (Token::IsTypeCastOperator(op_kind)) {
+ ReplaceWithTypeCast(instr);
+ return;
+ }
+
if ((op_kind == Token::kGET) &&
TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
return;
}
const ICData& unary_checks =
ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
- if ((instr->ic_data()->NumberOfChecks() > 0) &&
+ if ((unary_checks.NumberOfChecks() > 0) &&
(op_kind == Token::kSET) &&
TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
return;
}
- if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) {
+
+ bool has_one_target =
+ (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget();
+ if (has_one_target) {
+ // Check if the single target is a polymorphic target, if it is,
+ // we don't have one target.
+ const Function& target =
+ Function::Handle(Z, unary_checks.GetTargetAt(0));
+ const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
+ has_one_target = !polymorphic_target;
+ }
+
+ if (has_one_target) {
+ RawFunction::Kind function_kind =
+ Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
+ if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
+ PolymorphicInstanceCallInstr* call =
+ new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
+ /* with_checks = */ false);
+ instr->ReplaceWith(call, current_iterator());
+ return;
+ }
+ }
+
+ // More than one targets. Generate generic polymorphic call without
+ // deoptimization.
+ if (instr->ic_data()->NumberOfUsedChecks() > 0) {
ASSERT(!FLAG_polymorphic_with_deopt);
// OK to use checks with PolymorphicInstanceCallInstr since no
// deoptimization is allowed.
PolymorphicInstanceCallInstr* call =
new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
- true /* call_with_checks */);
+ /* with_checks = */ true);
instr->ReplaceWith(call, current_iterator());
return;
}
- // Type test is special as it always gets converted into inlined code.
- if (Token::IsTypeTestOperator(op_kind)) {
- ReplaceWithInstanceOf(instr);
- return;
- }
- if (Token::IsTypeCastOperator(op_kind)) {
- ReplaceWithTypeCast(instr);
- return;
+ // No IC data checks. Try resolve target using the propagated type.
+ // If the propagated type has a method with the target name and there are
+ // no overrides with that name according to CHA, call the method directly.
+ const AbstractType* receiver_type =
+ instr->PushArgumentAt(0)->value()->Type()->ToAbstractType();
+ if (receiver_type->IsDynamicType()) return;
+ if (receiver_type->HasResolvedTypeClass()) {
+ const Class& receiver_class = Class::Handle(Z,
+ receiver_type->type_class());
+ const Array& args_desc_array = Array::Handle(Z,
+ ArgumentsDescriptor::New(instr->ArgumentCount(),
+ instr->argument_names()));
+ ArgumentsDescriptor args_desc(args_desc_array);
+ const Function& function = Function::Handle(Z,
+ Resolver::ResolveDynamicForReceiverClass(
+ receiver_class,
+ instr->function_name(),
+ args_desc));
+ if (function.IsNull()) {
+ return;
+ }
+ if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) {
+ if (FLAG_trace_cha) {
+ THR_Print(" **(CHA) Instance call needs no check, "
+ "no overrides of '%s' '%s'\n",
+ instr->function_name().ToCString(), receiver_class.ToCString());
+ }
+ thread()->cha()->AddToLeafClasses(receiver_class);
+
+ // Create fake IC data with the resolved target.
+ const ICData& ic_data = ICData::Handle(
+ ICData::New(flow_graph_->function(),
+ instr->function_name(),
+ args_desc_array,
+ Thread::kNoDeoptId,
+ 1));
rmacnak 2015/10/21 18:00:30 1 /* args_tested */
Florian Schneider 2015/10/22 13:59:25 Done.
+ ic_data.AddReceiverCheck(receiver_class.id(), function);
+ PolymorphicInstanceCallInstr* call =
+ new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
+ /* with_checks = */ false);
+ instr->ReplaceWith(call, current_iterator());
+ return;
+ }
}
}
@@ -4431,10 +4502,9 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
RawFunction::Kind function_kind =
Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
- const bool call_with_checks = false;
PolymorphicInstanceCallInstr* call =
new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
- call_with_checks);
+ /* call_with_checks = */ false);
instr->ReplaceWith(call, current_iterator());
return;
}

Powered by Google App Engine
This is Rietveld 408576698