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(FlowGraph* flow_graph, | 75 AotOptimizer::AotOptimizer(Precompiler* precompiler, |
| 76 FlowGraph* flow_graph, |
76 bool use_speculative_inlining, | 77 bool use_speculative_inlining, |
77 GrowableArray<intptr_t>* inlining_black_list) | 78 GrowableArray<intptr_t>* inlining_black_list) |
78 : FlowGraphVisitor(flow_graph->reverse_postorder()), | 79 : FlowGraphVisitor(flow_graph->reverse_postorder()), |
| 80 precompiler_(precompiler), |
79 flow_graph_(flow_graph), | 81 flow_graph_(flow_graph), |
80 use_speculative_inlining_(use_speculative_inlining), | 82 use_speculative_inlining_(use_speculative_inlining), |
81 inlining_black_list_(inlining_black_list), | 83 inlining_black_list_(inlining_black_list), |
82 has_unique_no_such_method_(false) { | 84 has_unique_no_such_method_(false) { |
83 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); | 85 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); |
84 Function& target_function = Function::Handle(); | 86 Function& target_function = Function::Handle(); |
85 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { | 87 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
86 GetUniqueDynamicTarget( | 88 GetUniqueDynamicTarget( |
87 isolate(), Symbols::NoSuchMethod(), &target_function); | 89 isolate(), Symbols::NoSuchMethod(), &target_function); |
88 has_unique_no_such_method_ = !target_function.IsNull(); | 90 has_unique_no_such_method_ = !target_function.IsNull(); |
(...skipping 28 matching lines...) Expand all Loading... |
117 call->checked_argument_count(), false)); | 119 call->checked_argument_count(), false)); |
118 call->set_ic_data(&ic_data); | 120 call->set_ic_data(&ic_data); |
119 } | 121 } |
120 } | 122 } |
121 } | 123 } |
122 current_iterator_ = NULL; | 124 current_iterator_ = NULL; |
123 } | 125 } |
124 } | 126 } |
125 | 127 |
126 | 128 |
| 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 |
127 // Optimize instance calls using cid. This is called after optimizer | 170 // Optimize instance calls using cid. This is called after optimizer |
128 // converted instance calls to instructions. Any remaining | 171 // converted instance calls to instructions. Any remaining |
129 // instance calls are either megamorphic calls, cannot be optimized or | 172 // instance calls are either megamorphic calls, cannot be optimized or |
130 // have no runtime type feedback collected. | 173 // have no runtime type feedback collected. |
131 // Attempts to convert an instance call (IC call) using propagated class-ids, | 174 // Attempts to convert an instance call (IC call) using propagated class-ids, |
132 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 175 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
133 void AotOptimizer::ApplyClassIds() { | 176 void AotOptimizer::ApplyClassIds() { |
134 ASSERT(current_iterator_ == NULL); | 177 ASSERT(current_iterator_ == NULL); |
135 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 178 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
136 !block_it.Done(); | 179 !block_it.Done(); |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 to_remove_right->RemoveFromGraph(); | 665 to_remove_right->RemoveFromGraph(); |
623 } | 666 } |
624 return true; | 667 return true; |
625 } | 668 } |
626 return false; | 669 return false; |
627 } | 670 } |
628 | 671 |
629 | 672 |
630 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 673 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
631 | 674 |
| 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 |
632 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 727 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
633 Token::Kind op_kind) { | 728 Token::Kind op_kind) { |
634 const ICData& ic_data = *call->ic_data(); | 729 const ICData& ic_data = *call->ic_data(); |
635 ASSERT(ic_data.NumArgsTested() == 2); | 730 ASSERT(ic_data.NumArgsTested() == 2); |
636 | 731 |
637 ASSERT(call->ArgumentCount() == 2); | 732 ASSERT(call->ArgumentCount() == 2); |
638 Definition* left = call->ArgumentAt(0); | 733 Definition* left = call->ArgumentAt(0); |
639 Definition* right = call->ArgumentAt(1); | 734 Definition* right = call->ArgumentAt(1); |
640 | 735 |
641 intptr_t cid = kIllegalCid; | 736 intptr_t cid = kIllegalCid; |
642 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 737 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
643 if (TryStringLengthOneEquality(call, op_kind)) { | 738 return TryStringLengthOneEquality(call, op_kind); |
644 return true; | |
645 } else { | |
646 return false; | |
647 } | |
648 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 739 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
649 InsertBefore(call, | 740 InsertBefore(call, |
650 new(Z) CheckSmiInstr(new(Z) Value(left), | 741 new(Z) CheckSmiInstr(new(Z) Value(left), |
651 call->deopt_id(), | 742 call->deopt_id(), |
652 call->token_pos()), | 743 call->token_pos()), |
653 call->env(), | 744 call->env(), |
654 FlowGraph::kEffect); | 745 FlowGraph::kEffect); |
655 InsertBefore(call, | 746 InsertBefore(call, |
656 new(Z) CheckSmiInstr(new(Z) Value(right), | 747 new(Z) CheckSmiInstr(new(Z) Value(right), |
657 call->deopt_id(), | 748 call->deopt_id(), |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
703 const ICData& unary_checks_1 = | 794 const ICData& unary_checks_1 = |
704 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); | 795 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
705 AddCheckClass(right, | 796 AddCheckClass(right, |
706 unary_checks_1, | 797 unary_checks_1, |
707 call->deopt_id(), | 798 call->deopt_id(), |
708 call->env(), | 799 call->env(), |
709 call); | 800 call); |
710 cid = kSmiCid; | 801 cid = kSmiCid; |
711 } else { | 802 } else { |
712 // Shortcut for equality with null. | 803 // Shortcut for equality with null. |
| 804 // TODO(vegorov): this optimization is not speculative and should |
| 805 // be hoisted out of this function. |
713 ConstantInstr* right_const = right->AsConstant(); | 806 ConstantInstr* right_const = right->AsConstant(); |
714 ConstantInstr* left_const = left->AsConstant(); | 807 ConstantInstr* left_const = left->AsConstant(); |
715 if ((right_const != NULL && right_const->value().IsNull()) || | 808 if ((right_const != NULL && right_const->value().IsNull()) || |
716 (left_const != NULL && left_const->value().IsNull())) { | 809 (left_const != NULL && left_const->value().IsNull())) { |
717 StrictCompareInstr* comp = | 810 StrictCompareInstr* comp = |
718 new(Z) StrictCompareInstr(call->token_pos(), | 811 new(Z) StrictCompareInstr(call->token_pos(), |
719 Token::kEQ_STRICT, | 812 Token::kEQ_STRICT, |
720 new(Z) Value(left), | 813 new(Z) Value(left), |
721 new(Z) Value(right), | 814 new(Z) Value(right), |
722 false); // No number check. | 815 false); // No number check. |
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1750 } | 1843 } |
1751 if (Token::IsTypeCastOperator(op_kind)) { | 1844 if (Token::IsTypeCastOperator(op_kind)) { |
1752 ReplaceWithTypeCast(instr); | 1845 ReplaceWithTypeCast(instr); |
1753 return; | 1846 return; |
1754 } | 1847 } |
1755 | 1848 |
1756 if (TryInlineFieldAccess(instr)) { | 1849 if (TryInlineFieldAccess(instr)) { |
1757 return; | 1850 return; |
1758 } | 1851 } |
1759 | 1852 |
| 1853 if (RecognizeRuntimeTypeGetter(instr)) { |
| 1854 return; |
| 1855 } |
| 1856 |
| 1857 if ((op_kind == Token::kEQ) && TryReplaceWithHaveSameRuntimeType(instr)) { |
| 1858 return; |
| 1859 } |
| 1860 |
1760 const ICData& unary_checks = | 1861 const ICData& unary_checks = |
1761 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | 1862 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
1762 if (IsAllowedForInlining(instr->deopt_id()) && | 1863 if (IsAllowedForInlining(instr->deopt_id()) && |
1763 (unary_checks.NumberOfChecks() > 0)) { | 1864 (unary_checks.NumberOfChecks() > 0)) { |
1764 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | 1865 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { |
1765 return; | 1866 return; |
1766 } | 1867 } |
1767 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | 1868 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { |
1768 return; | 1869 return; |
1769 } | 1870 } |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2227 check->env(), FlowGraph::kEffect); | 2328 check->env(), FlowGraph::kEffect); |
2228 current_iterator()->RemoveCurrentFromGraph(); | 2329 current_iterator()->RemoveCurrentFromGraph(); |
2229 } | 2330 } |
2230 } | 2331 } |
2231 } | 2332 } |
2232 } | 2333 } |
2233 | 2334 |
2234 #endif // DART_PRECOMPILER | 2335 #endif // DART_PRECOMPILER |
2235 | 2336 |
2236 } // namespace dart | 2337 } // namespace dart |
OLD | NEW |