| Index: runtime/vm/aot_optimizer.cc
|
| diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
|
| index c39f74c88523fa12516a60d60113924011f46102..7d005b138fb5762444b59cd7c7b91299a07d6acb 100644
|
| --- a/runtime/vm/aot_optimizer.cc
|
| +++ b/runtime/vm/aot_optimizer.cc
|
| @@ -29,6 +29,10 @@
|
|
|
| namespace dart {
|
|
|
| +DEFINE_FLAG(int, max_exhaustive_polymorphic_checks, 5,
|
| + "If a call receiver is known to be of at most this many classes, "
|
| + "generate exhaustive class tests instead of a megamorphic call");
|
| +
|
| // Quick access to the current isolate and zone.
|
| #define I (isolate())
|
| #define Z (zone())
|
| @@ -281,11 +285,11 @@ void AotOptimizer::SpecializePolymorphicInstanceCall(
|
| return;
|
| }
|
|
|
| - const bool with_checks = false;
|
| PolymorphicInstanceCallInstr* specialized =
|
| new(Z) PolymorphicInstanceCallInstr(call->instance_call(),
|
| ic_data,
|
| - with_checks);
|
| + /* with_checks = */ false,
|
| + /* complete = */ false);
|
| call->ReplaceWith(specialized, current_iterator());
|
| }
|
|
|
| @@ -2441,7 +2445,8 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| instr, function_kind)) {
|
| PolymorphicInstanceCallInstr* call =
|
| new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
|
| - /* with_checks = */ false);
|
| + /* with_checks = */ false,
|
| + /* complete = */ true);
|
| instr->ReplaceWith(call, current_iterator());
|
| return;
|
| }
|
| @@ -2514,13 +2519,71 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| ic_data.AddReceiverCheck(receiver_class.id(), function);
|
| PolymorphicInstanceCallInstr* call =
|
| new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
|
| - /* with_checks = */ false);
|
| + /* with_checks = */ false,
|
| + /* complete = */ true);
|
| instr->ReplaceWith(call, current_iterator());
|
| return;
|
| }
|
| }
|
| }
|
|
|
| + Definition* callee_receiver = instr->ArgumentAt(0);
|
| + const Function& function = flow_graph_->function();
|
| + if (function.IsDynamicFunction() &&
|
| + 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);
|
| +
|
| + const ICData& ic_data = ICData::Handle(
|
| + ICData::New(function,
|
| + instr->function_name(),
|
| + args_desc_array,
|
| + Thread::kNoDeoptId,
|
| + /* args_tested = */ 1));
|
| +
|
| + 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);
|
| + }
|
| + }
|
| + 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;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| // More than one targets. Generate generic polymorphic call without
|
| // deoptimization.
|
| if (instr->ic_data()->NumberOfUsedChecks() > 0) {
|
| @@ -2529,7 +2592,8 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| // deoptimization is allowed.
|
| PolymorphicInstanceCallInstr* call =
|
| new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
|
| - /* with_checks = */ true);
|
| + /* with_checks = */ true,
|
| + /* complete = */ false);
|
| instr->ReplaceWith(call, current_iterator());
|
| return;
|
| }
|
|
|