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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 Object* function) { | 65 Object* function) { |
66 UniqueFunctionsSet functions_set( | 66 UniqueFunctionsSet functions_set( |
67 isolate->object_store()->unique_dynamic_targets()); | 67 isolate->object_store()->unique_dynamic_targets()); |
68 ASSERT(fname.IsSymbol()); | 68 ASSERT(fname.IsSymbol()); |
69 *function = functions_set.GetOrNull(fname); | 69 *function = functions_set.GetOrNull(fname); |
70 ASSERT(functions_set.Release().raw() == | 70 ASSERT(functions_set.Release().raw() == |
71 isolate->object_store()->unique_dynamic_targets()); | 71 isolate->object_store()->unique_dynamic_targets()); |
72 } | 72 } |
73 | 73 |
74 | 74 |
75 AotOptimizer::AotOptimizer(Precompiler* precompiler, | 75 AotOptimizer::AotOptimizer(FlowGraph* flow_graph, |
76 FlowGraph* flow_graph, | |
77 bool use_speculative_inlining, | 76 bool use_speculative_inlining, |
78 GrowableArray<intptr_t>* inlining_black_list) | 77 GrowableArray<intptr_t>* inlining_black_list) |
79 : FlowGraphVisitor(flow_graph->reverse_postorder()), | 78 : FlowGraphVisitor(flow_graph->reverse_postorder()), |
80 precompiler_(precompiler), | |
81 flow_graph_(flow_graph), | 79 flow_graph_(flow_graph), |
82 use_speculative_inlining_(use_speculative_inlining), | 80 use_speculative_inlining_(use_speculative_inlining), |
83 inlining_black_list_(inlining_black_list), | 81 inlining_black_list_(inlining_black_list), |
84 has_unique_no_such_method_(false) { | 82 has_unique_no_such_method_(false) { |
85 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); | 83 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); |
86 Function& target_function = Function::Handle(); | 84 Function& target_function = Function::Handle(); |
87 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { | 85 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
88 GetUniqueDynamicTarget( | 86 GetUniqueDynamicTarget( |
89 isolate(), Symbols::NoSuchMethod(), &target_function); | 87 isolate(), Symbols::NoSuchMethod(), &target_function); |
90 has_unique_no_such_method_ = !target_function.IsNull(); | 88 has_unique_no_such_method_ = !target_function.IsNull(); |
(...skipping 28 matching lines...) Expand all Loading... |
119 call->checked_argument_count(), false)); | 117 call->checked_argument_count(), false)); |
120 call->set_ic_data(&ic_data); | 118 call->set_ic_data(&ic_data); |
121 } | 119 } |
122 } | 120 } |
123 } | 121 } |
124 current_iterator_ = NULL; | 122 current_iterator_ = NULL; |
125 } | 123 } |
126 } | 124 } |
127 | 125 |
128 | 126 |
129 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) { | |
130 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) { | |
131 return false; | |
132 } | |
133 | |
134 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { | |
135 return false; | |
136 } | |
137 | |
138 // There is only a single function Object.get:runtimeType that can be invoked | |
139 // by this call. Convert dynamic invocation to a static one. | |
140 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); | |
141 const Array& args_desc_array = Array::Handle(Z, | |
142 ArgumentsDescriptor::New(call->ArgumentCount(), | |
143 call->argument_names())); | |
144 ArgumentsDescriptor args_desc(args_desc_array); | |
145 const Function& function = Function::Handle(Z, | |
146 Resolver::ResolveDynamicForReceiverClass( | |
147 cls, | |
148 call->function_name(), | |
149 args_desc)); | |
150 ASSERT(!function.IsNull()); | |
151 | |
152 ZoneGrowableArray<PushArgumentInstr*>* args = | |
153 new (Z) ZoneGrowableArray<PushArgumentInstr*>( | |
154 call->ArgumentCount()); | |
155 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | |
156 args->Add(call->PushArgumentAt(i)); | |
157 } | |
158 StaticCallInstr* static_call = new (Z) StaticCallInstr( | |
159 call->token_pos(), | |
160 Function::ZoneHandle(Z, function.raw()), | |
161 call->argument_names(), | |
162 args, | |
163 call->deopt_id()); | |
164 static_call->set_result_cid(kTypeCid); | |
165 call->ReplaceWith(static_call, current_iterator()); | |
166 return true; | |
167 } | |
168 | |
169 | |
170 // Optimize instance calls using cid. This is called after optimizer | 127 // Optimize instance calls using cid. This is called after optimizer |
171 // converted instance calls to instructions. Any remaining | 128 // converted instance calls to instructions. Any remaining |
172 // instance calls are either megamorphic calls, cannot be optimized or | 129 // instance calls are either megamorphic calls, cannot be optimized or |
173 // have no runtime type feedback collected. | 130 // have no runtime type feedback collected. |
174 // Attempts to convert an instance call (IC call) using propagated class-ids, | 131 // Attempts to convert an instance call (IC call) using propagated class-ids, |
175 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 132 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
176 void AotOptimizer::ApplyClassIds() { | 133 void AotOptimizer::ApplyClassIds() { |
177 ASSERT(current_iterator_ == NULL); | 134 ASSERT(current_iterator_ == NULL); |
178 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 135 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
179 !block_it.Done(); | 136 !block_it.Done(); |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 to_remove_right->RemoveFromGraph(); | 622 to_remove_right->RemoveFromGraph(); |
666 } | 623 } |
667 return true; | 624 return true; |
668 } | 625 } |
669 return false; | 626 return false; |
670 } | 627 } |
671 | 628 |
672 | 629 |
673 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 630 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
674 | 631 |
675 | |
676 static bool IsGetRuntimeType(Definition* defn) { | |
677 StaticCallInstr* call = defn->AsStaticCall(); | |
678 return (call != NULL) && | |
679 (call->function().recognized_kind() == | |
680 MethodRecognizer::kObjectRuntimeType); | |
681 } | |
682 | |
683 | |
684 // Recognize a.runtimeType == b.runtimeType and fold it into | |
685 // Object._haveSameRuntimeType(a, b). | |
686 // Note: this optimization is not speculative. | |
687 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) { | |
688 const ICData& ic_data = *call->ic_data(); | |
689 ASSERT(ic_data.NumArgsTested() == 2); | |
690 | |
691 ASSERT(call->ArgumentCount() == 2); | |
692 Definition* left = call->ArgumentAt(0); | |
693 Definition* right = call->ArgumentAt(1); | |
694 | |
695 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() && | |
696 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) { | |
697 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); | |
698 const Function& have_same_runtime_type = Function::ZoneHandle(Z, | |
699 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); | |
700 ASSERT(!have_same_runtime_type.IsNull()); | |
701 | |
702 ZoneGrowableArray<PushArgumentInstr*>* args = | |
703 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); | |
704 PushArgumentInstr* arg = new (Z) PushArgumentInstr( | |
705 new (Z) Value(left->ArgumentAt(0))); | |
706 InsertBefore(call, arg, NULL, FlowGraph::kEffect); | |
707 args->Add(arg); | |
708 arg = new (Z) PushArgumentInstr( | |
709 new (Z) Value(right->ArgumentAt(0))); | |
710 InsertBefore(call, arg, NULL, FlowGraph::kEffect); | |
711 args->Add(arg); | |
712 StaticCallInstr* static_call = new (Z) StaticCallInstr( | |
713 call->token_pos(), | |
714 have_same_runtime_type, | |
715 Object::null_array(), // argument_names | |
716 args, | |
717 call->deopt_id()); | |
718 static_call->set_result_cid(kBoolCid); | |
719 ReplaceCall(call, static_call); | |
720 return true; | |
721 } | |
722 | |
723 return false; | |
724 } | |
725 | |
726 | |
727 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 632 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
728 Token::Kind op_kind) { | 633 Token::Kind op_kind) { |
729 const ICData& ic_data = *call->ic_data(); | 634 const ICData& ic_data = *call->ic_data(); |
730 ASSERT(ic_data.NumArgsTested() == 2); | 635 ASSERT(ic_data.NumArgsTested() == 2); |
731 | 636 |
732 ASSERT(call->ArgumentCount() == 2); | 637 ASSERT(call->ArgumentCount() == 2); |
733 Definition* left = call->ArgumentAt(0); | 638 Definition* left = call->ArgumentAt(0); |
734 Definition* right = call->ArgumentAt(1); | 639 Definition* right = call->ArgumentAt(1); |
735 | 640 |
736 intptr_t cid = kIllegalCid; | 641 intptr_t cid = kIllegalCid; |
737 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 642 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
738 return TryStringLengthOneEquality(call, op_kind); | 643 if (TryStringLengthOneEquality(call, op_kind)) { |
| 644 return true; |
| 645 } else { |
| 646 return false; |
| 647 } |
739 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 648 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
740 InsertBefore(call, | 649 InsertBefore(call, |
741 new(Z) CheckSmiInstr(new(Z) Value(left), | 650 new(Z) CheckSmiInstr(new(Z) Value(left), |
742 call->deopt_id(), | 651 call->deopt_id(), |
743 call->token_pos()), | 652 call->token_pos()), |
744 call->env(), | 653 call->env(), |
745 FlowGraph::kEffect); | 654 FlowGraph::kEffect); |
746 InsertBefore(call, | 655 InsertBefore(call, |
747 new(Z) CheckSmiInstr(new(Z) Value(right), | 656 new(Z) CheckSmiInstr(new(Z) Value(right), |
748 call->deopt_id(), | 657 call->deopt_id(), |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
794 const ICData& unary_checks_1 = | 703 const ICData& unary_checks_1 = |
795 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); | 704 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
796 AddCheckClass(right, | 705 AddCheckClass(right, |
797 unary_checks_1, | 706 unary_checks_1, |
798 call->deopt_id(), | 707 call->deopt_id(), |
799 call->env(), | 708 call->env(), |
800 call); | 709 call); |
801 cid = kSmiCid; | 710 cid = kSmiCid; |
802 } else { | 711 } else { |
803 // Shortcut for equality with null. | 712 // Shortcut for equality with null. |
804 // TODO(vegorov): this optimization is not speculative and should | |
805 // be hoisted out of this function. | |
806 ConstantInstr* right_const = right->AsConstant(); | 713 ConstantInstr* right_const = right->AsConstant(); |
807 ConstantInstr* left_const = left->AsConstant(); | 714 ConstantInstr* left_const = left->AsConstant(); |
808 if ((right_const != NULL && right_const->value().IsNull()) || | 715 if ((right_const != NULL && right_const->value().IsNull()) || |
809 (left_const != NULL && left_const->value().IsNull())) { | 716 (left_const != NULL && left_const->value().IsNull())) { |
810 StrictCompareInstr* comp = | 717 StrictCompareInstr* comp = |
811 new(Z) StrictCompareInstr(call->token_pos(), | 718 new(Z) StrictCompareInstr(call->token_pos(), |
812 Token::kEQ_STRICT, | 719 Token::kEQ_STRICT, |
813 new(Z) Value(left), | 720 new(Z) Value(left), |
814 new(Z) Value(right), | 721 new(Z) Value(right), |
815 false); // No number check. | 722 false); // No number check. |
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1843 } | 1750 } |
1844 if (Token::IsTypeCastOperator(op_kind)) { | 1751 if (Token::IsTypeCastOperator(op_kind)) { |
1845 ReplaceWithTypeCast(instr); | 1752 ReplaceWithTypeCast(instr); |
1846 return; | 1753 return; |
1847 } | 1754 } |
1848 | 1755 |
1849 if (TryInlineFieldAccess(instr)) { | 1756 if (TryInlineFieldAccess(instr)) { |
1850 return; | 1757 return; |
1851 } | 1758 } |
1852 | 1759 |
1853 if (RecognizeRuntimeTypeGetter(instr)) { | |
1854 return; | |
1855 } | |
1856 | |
1857 if ((op_kind == Token::kEQ) && TryReplaceWithHaveSameRuntimeType(instr)) { | |
1858 return; | |
1859 } | |
1860 | |
1861 const ICData& unary_checks = | 1760 const ICData& unary_checks = |
1862 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | 1761 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
1863 if (IsAllowedForInlining(instr->deopt_id()) && | 1762 if (IsAllowedForInlining(instr->deopt_id()) && |
1864 (unary_checks.NumberOfChecks() > 0)) { | 1763 (unary_checks.NumberOfChecks() > 0)) { |
1865 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | 1764 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { |
1866 return; | 1765 return; |
1867 } | 1766 } |
1868 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | 1767 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { |
1869 return; | 1768 return; |
1870 } | 1769 } |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2328 check->env(), FlowGraph::kEffect); | 2227 check->env(), FlowGraph::kEffect); |
2329 current_iterator()->RemoveCurrentFromGraph(); | 2228 current_iterator()->RemoveCurrentFromGraph(); |
2330 } | 2229 } |
2331 } | 2230 } |
2332 } | 2231 } |
2333 } | 2232 } |
2334 | 2233 |
2335 #endif // DART_PRECOMPILER | 2234 #endif // DART_PRECOMPILER |
2336 | 2235 |
2337 } // namespace dart | 2236 } // namespace dart |
OLD | NEW |