Index: runtime/vm/aot_optimizer.cc |
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc |
index 208a2240fc853d3f771e61e847f7b873398de16c..7289960a1a7cbe3652833eb58ede71ffe647e32e 100644 |
--- a/runtime/vm/aot_optimizer.cc |
+++ b/runtime/vm/aot_optimizer.cc |
@@ -88,6 +88,48 @@ void AotOptimizer::PopulateWithICData() { |
} |
+bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) { |
+ if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) { |
+ return false; |
+ } |
+ |
+ if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { |
+ return false; |
+ } |
+ |
+ // There is only a single function Object.get:runtimeType that can be invoked |
+ // by this call. Convert dynamic invocation to a static one. |
+ const Class& cls = |
+ Class::Handle(Z, thread()->isolate()->object_store()->object_class()); |
siva
2016/09/29 02:28:20
there seems to be an I in this file so I->object_s
Vyacheslav Egorov (Google)
2016/09/29 15:01:43
Done.
|
+ 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( |
+ cls, |
+ call->function_name(), |
+ args_desc)); |
+ ASSERT(!function.IsNull()); |
+ |
+ ZoneGrowableArray<PushArgumentInstr*>* args = |
+ new (Z) ZoneGrowableArray<PushArgumentInstr*>( |
+ call->ArgumentCount()); |
+ for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
+ args->Add(call->PushArgumentAt(i)); |
+ } |
+ StaticCallInstr* static_call = new (Z) StaticCallInstr( |
+ call->token_pos(), |
+ Function::ZoneHandle(Z, function.raw()), |
+ call->argument_names(), |
+ args, |
+ call->deopt_id()); |
+ static_call->set_result_cid(kTypeCid); |
+ call->ReplaceWith(static_call, current_iterator()); |
+ return true; |
+} |
+ |
+ |
// Optimize instance calls using cid. This is called after optimizer |
// converted instance calls to instructions. Any remaining |
// instance calls are either megamorphic calls, cannot be optimized or |
@@ -105,7 +147,9 @@ void AotOptimizer::ApplyClassIds() { |
Instruction* instr = it.Current(); |
if (instr->IsInstanceCall()) { |
InstanceCallInstr* call = instr->AsInstanceCall(); |
- if (call->HasICData()) { |
+ if (RecognizeRuntimeTypeGetter(call)) { |
Florian Schneider
2016/09/28 22:49:24
Any reason why this is here and not in AotOptimize
Vyacheslav Egorov (Google)
2016/09/29 00:31:22
Because we will never get into VisitInstanceCall i
Florian Schneider
2016/09/29 18:03:28
Yes, I meant that the ApplyICData phase always vis
Vyacheslav Egorov (Google)
2016/09/30 09:56:28
Fair enough. Moved it into VisitInstanceCall.
|
+ continue; |
+ } else if (call->HasICData()) { |
if (TryCreateICData(call)) { |
VisitInstanceCall(call); |
} |
@@ -606,6 +650,13 @@ bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
static bool SmiFitsInDouble() { return kSmiBits < 53; } |
+static bool IsGetRuntimeType(Definition* defn) { |
+ StaticCallInstr* call = defn->AsStaticCall(); |
+ return (call != NULL) && |
+ (call->function().recognized_kind() == |
+ MethodRecognizer::kObjectRuntimeType); |
+} |
+ |
bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
Token::Kind op_kind) { |
const ICData& ic_data = *call->ic_data(); |
@@ -615,13 +666,40 @@ bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
Definition* left = call->ArgumentAt(0); |
Definition* right = call->ArgumentAt(1); |
+ // Recognize a.runtimeType == b.runtimeType and fold it into |
+ // Object._haveSameRuntimeType(a, b). |
+ if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() && |
+ IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) { |
+ const Class& cls = |
+ Class::Handle(Z, thread()->isolate()->object_store()->object_class()); |
siva
2016/09/29 02:28:20
Ditto comment about I
Vyacheslav Egorov (Google)
2016/09/29 15:01:43
Done.
|
+ const Function& hasSameRuntimeType = Function::ZoneHandle(Z, |
+ cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); |
+ ASSERT(!hasSameRuntimeType.IsNull()); |
+ |
+ ZoneGrowableArray<PushArgumentInstr*>* args = |
+ new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); |
+ PushArgumentInstr* arg = new (Z) PushArgumentInstr( |
+ new (Z) Value(left->ArgumentAt(0))); |
+ InsertBefore(call, arg, NULL, FlowGraph::kEffect); |
+ args->Add(arg); |
+ arg = new (Z) PushArgumentInstr( |
+ new (Z) Value(right->ArgumentAt(0))); |
+ InsertBefore(call, arg, NULL, FlowGraph::kEffect); |
+ args->Add(arg); |
+ StaticCallInstr* static_call = new (Z) StaticCallInstr( |
+ call->token_pos(), |
+ hasSameRuntimeType, |
+ Object::null_array(), // argument_names |
+ args, |
+ call->deopt_id()); |
+ static_call->set_result_cid(kBoolCid); |
+ ReplaceCall(call, static_call); |
+ return true; |
+ } |
+ |
intptr_t cid = kIllegalCid; |
if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
- if (TryStringLengthOneEquality(call, op_kind)) { |
- return true; |
- } else { |
- return false; |
- } |
+ return TryStringLengthOneEquality(call, op_kind); |
} else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
InsertBefore(call, |
new(Z) CheckSmiInstr(new(Z) Value(left), |