Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(379)

Side by Side Diff: runtime/vm/aot_optimizer.cc

Issue 2453463006: Revert "Revert "Recognize and optimize a.runtimeType == b.runtimeType pattern."" (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698