Index: runtime/vm/aot_optimizer.cc |
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc |
index 208a2240fc853d3f771e61e847f7b873398de16c..c938bc3799a82e1860e3385892e05e7e663c503f 100644 |
--- a/runtime/vm/aot_optimizer.cc |
+++ b/runtime/vm/aot_optimizer.cc |
@@ -54,6 +54,42 @@ static bool CanConvertUnboxedMintToDouble() { |
} |
+// Returns named function that is a unique dynamic target, i.e., |
+// - the target is identified by its name alone, since it occurs only once. |
+// - target's class has no subclasses, and neither is subclassed, i.e., |
+// the receiver type can be only the function's class. |
+// Returns Function::null() if there is no unique dynamic target for |
+// given 'fname'. 'fname' must be a symbol. |
+static void GetUniqueDynamicTarget(Isolate* isolate, |
+ const String& fname, |
+ Object* function) { |
+ UniqueFunctionsSet functions_set( |
+ isolate->object_store()->unique_dynamic_targets()); |
+ ASSERT(fname.IsSymbol()); |
+ *function = functions_set.GetOrNull(fname); |
+ ASSERT(functions_set.Release().raw() == |
+ isolate->object_store()->unique_dynamic_targets()); |
+} |
+ |
+ |
+AotOptimizer::AotOptimizer(FlowGraph* flow_graph, |
+ bool use_speculative_inlining, |
+ GrowableArray<intptr_t>* inlining_black_list) |
+ : FlowGraphVisitor(flow_graph->reverse_postorder()), |
+ flow_graph_(flow_graph), |
+ use_speculative_inlining_(use_speculative_inlining), |
+ inlining_black_list_(inlining_black_list), |
+ has_unique_no_such_method_(false) { |
+ ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); |
+ Function& target_function = Function::Handle(); |
+ if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
+ GetUniqueDynamicTarget( |
+ isolate(), Symbols::NoSuchMethod(), &target_function); |
+ has_unique_no_such_method_ = !target_function.IsNull(); |
+ } |
+} |
+ |
+ |
// Optimize instance calls using ICData. |
void AotOptimizer::ApplyICData() { |
VisitBlocks(); |
@@ -123,24 +159,6 @@ static bool IsNumberCid(intptr_t cid) { |
} |
-// Returns named function that is a unique dynamic target, i.e., |
-// - the target is identified by its name alone, since it occurs only once. |
-// - target's class has no subclasses, and neither is subclassed, i.e., |
-// the receiver type can be only the function's class. |
-// Returns Function::null() if there is no unique dynamic target for |
-// given 'fname'. 'fname' must be a symbol. |
-static void GetUniqueDynamicTarget(Isolate* isolate, |
- const String& fname, |
- Object* function) { |
- UniqueFunctionsSet functions_set( |
- isolate->object_store()->unique_dynamic_targets()); |
- ASSERT(fname.IsSymbol()); |
- *function = functions_set.GetOrNull(fname); |
- ASSERT(functions_set.Release().raw() == |
- isolate->object_store()->unique_dynamic_targets()); |
-} |
- |
- |
bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { |
ASSERT(call->HasICData()); |
if (call->ic_data()->NumberOfUsedChecks() > 0) { |
@@ -227,12 +245,17 @@ bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { |
!target_function.HasOptionalNamedParameters() && |
target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, |
/* error_message = */ NULL)) { |
- const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); |
- const ICData& ic_data = ICData::ZoneHandle(Z, |
- ICData::NewFrom(*call->ic_data(), 1)); |
- ic_data.AddReceiverCheck(cid, target_function); |
- call->set_ic_data(&ic_data); |
- return true; |
+ const Class& cls = Class::Handle(Z, target_function.Owner()); |
+ if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) { |
+ const ICData& ic_data = ICData::ZoneHandle(Z, |
+ ICData::NewFrom(*call->ic_data(), 1)); |
+ ic_data.AddReceiverCheck(cls.id(), target_function); |
+ call->set_ic_data(&ic_data); |
+ if (has_unique_no_such_method_) { |
+ call->set_has_unique_selector(true); |
+ } |
+ return true; |
+ } |
} |
} |
@@ -1995,6 +2018,32 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
} |
+void AotOptimizer::VisitPolymorphicInstanceCall( |
+ PolymorphicInstanceCallInstr* call) { |
+ if (call->with_checks()) { |
+ const intptr_t receiver_cid = |
+ call->PushArgumentAt(0)->value()->Type()->ToCid(); |
+ if (receiver_cid != kDynamicCid) { |
+ const Class& receiver_class = Class::Handle(Z, |
+ isolate()->class_table()->At(receiver_cid)); |
+ |
+ const Array& args_desc_array = Array::Handle(Z, |
+ ArgumentsDescriptor::New(call->ArgumentCount(), |
+ call->instance_call()->argument_names())); |
+ ArgumentsDescriptor args_desc(args_desc_array); |
+ const Function& function = Function::Handle(Z, |
+ Resolver::ResolveDynamicForReceiverClass( |
+ receiver_class, |
+ call->instance_call()->function_name(), |
+ args_desc)); |
+ if (!function.IsNull()) { |
+ call->set_with_checks(false); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
if (!IsAllowedForInlining(call->deopt_id())) { |
// Inlining disabled after a speculative inlining attempt. |