| 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 |