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