Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/aot_optimizer.h" | 5 #include "vm/aot_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 call->checked_argument_count(), false)); | 81 call->checked_argument_count(), false)); |
| 82 call->set_ic_data(&ic_data); | 82 call->set_ic_data(&ic_data); |
| 83 } | 83 } |
| 84 } | 84 } |
| 85 } | 85 } |
| 86 current_iterator_ = NULL; | 86 current_iterator_ = NULL; |
| 87 } | 87 } |
| 88 } | 88 } |
| 89 | 89 |
| 90 | 90 |
| 91 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) { | |
| 92 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) { | |
|
Florian Schneider
2016/09/29 18:03:29
Can we use existing CHA to detect overrides? This
Vyacheslav Egorov (Google)
2016/09/30 09:56:28
See above. CHA does not work with Object.
We coul
Florian Schneider
2016/09/30 17:42:56
I think it would be out of scope for this CL.
I w
| |
| 93 return false; | |
| 94 } | |
| 95 | |
| 96 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { | |
| 97 return false; | |
| 98 } | |
| 99 | |
| 100 // There is only a single function Object.get:runtimeType that can be invoked | |
| 101 // by this call. Convert dynamic invocation to a static one. | |
| 102 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); | |
| 103 const Array& args_desc_array = Array::Handle(Z, | |
| 104 ArgumentsDescriptor::New(call->ArgumentCount(), | |
| 105 call->argument_names())); | |
| 106 ArgumentsDescriptor args_desc(args_desc_array); | |
| 107 const Function& function = Function::Handle(Z, | |
| 108 Resolver::ResolveDynamicForReceiverClass( | |
| 109 cls, | |
| 110 call->function_name(), | |
| 111 args_desc)); | |
| 112 ASSERT(!function.IsNull()); | |
| 113 | |
| 114 ZoneGrowableArray<PushArgumentInstr*>* args = | |
| 115 new (Z) ZoneGrowableArray<PushArgumentInstr*>( | |
| 116 call->ArgumentCount()); | |
| 117 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | |
| 118 args->Add(call->PushArgumentAt(i)); | |
| 119 } | |
| 120 StaticCallInstr* static_call = new (Z) StaticCallInstr( | |
| 121 call->token_pos(), | |
| 122 Function::ZoneHandle(Z, function.raw()), | |
| 123 call->argument_names(), | |
| 124 args, | |
| 125 call->deopt_id()); | |
| 126 static_call->set_result_cid(kTypeCid); | |
| 127 call->ReplaceWith(static_call, current_iterator()); | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 | |
| 91 // Optimize instance calls using cid. This is called after optimizer | 132 // Optimize instance calls using cid. This is called after optimizer |
| 92 // converted instance calls to instructions. Any remaining | 133 // converted instance calls to instructions. Any remaining |
| 93 // instance calls are either megamorphic calls, cannot be optimized or | 134 // instance calls are either megamorphic calls, cannot be optimized or |
| 94 // have no runtime type feedback collected. | 135 // have no runtime type feedback collected. |
| 95 // Attempts to convert an instance call (IC call) using propagated class-ids, | 136 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 96 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 137 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
| 97 void AotOptimizer::ApplyClassIds() { | 138 void AotOptimizer::ApplyClassIds() { |
| 98 ASSERT(current_iterator_ == NULL); | 139 ASSERT(current_iterator_ == NULL); |
| 99 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 140 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 100 !block_it.Done(); | 141 !block_it.Done(); |
| 101 block_it.Advance()) { | 142 block_it.Advance()) { |
| 102 ForwardInstructionIterator it(block_it.Current()); | 143 ForwardInstructionIterator it(block_it.Current()); |
| 103 current_iterator_ = ⁢ | 144 current_iterator_ = ⁢ |
| 104 for (; !it.Done(); it.Advance()) { | 145 for (; !it.Done(); it.Advance()) { |
| 105 Instruction* instr = it.Current(); | 146 Instruction* instr = it.Current(); |
| 106 if (instr->IsInstanceCall()) { | 147 if (instr->IsInstanceCall()) { |
| 107 InstanceCallInstr* call = instr->AsInstanceCall(); | 148 InstanceCallInstr* call = instr->AsInstanceCall(); |
| 108 if (call->HasICData()) { | 149 if (RecognizeRuntimeTypeGetter(call)) { |
| 150 continue; | |
| 151 } else if (call->HasICData()) { | |
| 109 if (TryCreateICData(call)) { | 152 if (TryCreateICData(call)) { |
| 110 VisitInstanceCall(call); | 153 VisitInstanceCall(call); |
| 111 } | 154 } |
| 112 } | 155 } |
| 113 } | 156 } |
| 114 } | 157 } |
| 115 current_iterator_ = NULL; | 158 current_iterator_ = NULL; |
| 116 } | 159 } |
| 117 } | 160 } |
| 118 | 161 |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 599 to_remove_right->RemoveFromGraph(); | 642 to_remove_right->RemoveFromGraph(); |
| 600 } | 643 } |
| 601 return true; | 644 return true; |
| 602 } | 645 } |
| 603 return false; | 646 return false; |
| 604 } | 647 } |
| 605 | 648 |
| 606 | 649 |
| 607 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 650 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 608 | 651 |
| 652 static bool IsGetRuntimeType(Definition* defn) { | |
| 653 StaticCallInstr* call = defn->AsStaticCall(); | |
| 654 return (call != NULL) && | |
| 655 (call->function().recognized_kind() == | |
| 656 MethodRecognizer::kObjectRuntimeType); | |
| 657 } | |
| 658 | |
| 609 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 659 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 610 Token::Kind op_kind) { | 660 Token::Kind op_kind) { |
| 611 const ICData& ic_data = *call->ic_data(); | 661 const ICData& ic_data = *call->ic_data(); |
| 612 ASSERT(ic_data.NumArgsTested() == 2); | 662 ASSERT(ic_data.NumArgsTested() == 2); |
| 613 | 663 |
| 614 ASSERT(call->ArgumentCount() == 2); | 664 ASSERT(call->ArgumentCount() == 2); |
| 615 Definition* left = call->ArgumentAt(0); | 665 Definition* left = call->ArgumentAt(0); |
| 616 Definition* right = call->ArgumentAt(1); | 666 Definition* right = call->ArgumentAt(1); |
| 617 | 667 |
| 668 // Recognize a.runtimeType == b.runtimeType and fold it into | |
| 669 // Object._haveSameRuntimeType(a, b). | |
| 670 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() && | |
| 671 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) { | |
| 672 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); | |
| 673 const Function& have_same_runtime_type = Function::ZoneHandle(Z, | |
| 674 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); | |
| 675 ASSERT(!have_same_runtime_type.IsNull()); | |
| 676 | |
| 677 ZoneGrowableArray<PushArgumentInstr*>* args = | |
| 678 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); | |
| 679 PushArgumentInstr* arg = new (Z) PushArgumentInstr( | |
| 680 new (Z) Value(left->ArgumentAt(0))); | |
| 681 InsertBefore(call, arg, NULL, FlowGraph::kEffect); | |
| 682 args->Add(arg); | |
| 683 arg = new (Z) PushArgumentInstr( | |
| 684 new (Z) Value(right->ArgumentAt(0))); | |
| 685 InsertBefore(call, arg, NULL, FlowGraph::kEffect); | |
| 686 args->Add(arg); | |
| 687 StaticCallInstr* static_call = new (Z) StaticCallInstr( | |
| 688 call->token_pos(), | |
| 689 have_same_runtime_type, | |
| 690 Object::null_array(), // argument_names | |
| 691 args, | |
| 692 call->deopt_id()); | |
| 693 static_call->set_result_cid(kBoolCid); | |
| 694 ReplaceCall(call, static_call); | |
| 695 return true; | |
| 696 } | |
| 697 | |
| 618 intptr_t cid = kIllegalCid; | 698 intptr_t cid = kIllegalCid; |
| 619 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 699 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
| 620 if (TryStringLengthOneEquality(call, op_kind)) { | 700 return TryStringLengthOneEquality(call, op_kind); |
| 621 return true; | |
| 622 } else { | |
| 623 return false; | |
| 624 } | |
| 625 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 701 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 626 InsertBefore(call, | 702 InsertBefore(call, |
| 627 new(Z) CheckSmiInstr(new(Z) Value(left), | 703 new(Z) CheckSmiInstr(new(Z) Value(left), |
| 628 call->deopt_id(), | 704 call->deopt_id(), |
| 629 call->token_pos()), | 705 call->token_pos()), |
| 630 call->env(), | 706 call->env(), |
| 631 FlowGraph::kEffect); | 707 FlowGraph::kEffect); |
| 632 InsertBefore(call, | 708 InsertBefore(call, |
| 633 new(Z) CheckSmiInstr(new(Z) Value(right), | 709 new(Z) CheckSmiInstr(new(Z) Value(right), |
| 634 call->deopt_id(), | 710 call->deopt_id(), |
| (...skipping 1543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2178 check->env(), FlowGraph::kEffect); | 2254 check->env(), FlowGraph::kEffect); |
| 2179 current_iterator()->RemoveCurrentFromGraph(); | 2255 current_iterator()->RemoveCurrentFromGraph(); |
| 2180 } | 2256 } |
| 2181 } | 2257 } |
| 2182 } | 2258 } |
| 2183 } | 2259 } |
| 2184 | 2260 |
| 2185 #endif // DART_PRECOMPILER | 2261 #endif // DART_PRECOMPILER |
| 2186 | 2262 |
| 2187 } // namespace dart | 2263 } // namespace dart |
| OLD | NEW |