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

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

Issue 2379733002: Recognize and optimize a.runtimeType == b.runtimeType pattern. (Closed)
Patch Set: port to all arch, make AOT opt non-speculative Created 4 years, 2 months 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
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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 call->checked_argument_count(), false)); 81 call->checked_argument_count(), false));
82 call->set_ic_data(&ic_data); 82 call->set_ic_data(&ic_data);
83 } 83 }
84 } 84 }
85 } 85 }
86 current_iterator_ = NULL; 86 current_iterator_ = NULL;
87 } 87 }
88 } 88 }
89 89
90 90
91 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) {
92 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) {
93 return false;
94 }
95
96 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) {
97 return false;
98 }
99
100 // There is only a single function Object.get:runtimeType that can be invoked
101 // by this call. Convert dynamic invocation to a static one.
102 const Class& cls = Class::Handle(Z, I->object_store()->object_class());
103 const Array& args_desc_array = Array::Handle(Z,
104 ArgumentsDescriptor::New(call->ArgumentCount(),
105 call->argument_names()));
106 ArgumentsDescriptor args_desc(args_desc_array);
107 const Function& function = Function::Handle(Z,
108 Resolver::ResolveDynamicForReceiverClass(
109 cls,
110 call->function_name(),
111 args_desc));
112 ASSERT(!function.IsNull());
113
114 ZoneGrowableArray<PushArgumentInstr*>* args =
115 new (Z) ZoneGrowableArray<PushArgumentInstr*>(
116 call->ArgumentCount());
117 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
118 args->Add(call->PushArgumentAt(i));
119 }
120 StaticCallInstr* static_call = new (Z) StaticCallInstr(
121 call->token_pos(),
122 Function::ZoneHandle(Z, function.raw()),
123 call->argument_names(),
124 args,
125 call->deopt_id());
126 static_call->set_result_cid(kTypeCid);
127 call->ReplaceWith(static_call, current_iterator());
128 return true;
129 }
130
131
91 // Optimize instance calls using cid. This is called after optimizer 132 // Optimize instance calls using cid. This is called after optimizer
92 // converted instance calls to instructions. Any remaining 133 // converted instance calls to instructions. Any remaining
93 // instance calls are either megamorphic calls, cannot be optimized or 134 // instance calls are either megamorphic calls, cannot be optimized or
94 // have no runtime type feedback collected. 135 // have no runtime type feedback collected.
95 // Attempts to convert an instance call (IC call) using propagated class-ids, 136 // Attempts to convert an instance call (IC call) using propagated class-ids,
96 // e.g., receiver class id, guarded-cid, or by guessing cid-s. 137 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
97 void AotOptimizer::ApplyClassIds() { 138 void AotOptimizer::ApplyClassIds() {
98 ASSERT(current_iterator_ == NULL); 139 ASSERT(current_iterator_ == NULL);
99 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 140 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
100 !block_it.Done(); 141 !block_it.Done();
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 to_remove_right->RemoveFromGraph(); 640 to_remove_right->RemoveFromGraph();
600 } 641 }
601 return true; 642 return true;
602 } 643 }
603 return false; 644 return false;
604 } 645 }
605 646
606 647
607 static bool SmiFitsInDouble() { return kSmiBits < 53; } 648 static bool SmiFitsInDouble() { return kSmiBits < 53; }
608 649
650
651 static bool IsGetRuntimeType(Definition* defn) {
652 StaticCallInstr* call = defn->AsStaticCall();
653 return (call != NULL) &&
654 (call->function().recognized_kind() ==
655 MethodRecognizer::kObjectRuntimeType);
656 }
657
658
659 // Recognize a.runtimeType == b.runtimeType and fold it into
660 // Object._haveSameRuntimeType(a, b).
661 // Note: this optimization is not speculative.
662 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) {
663 const ICData& ic_data = *call->ic_data();
664 ASSERT(ic_data.NumArgsTested() == 2);
665
666 ASSERT(call->ArgumentCount() == 2);
667 Definition* left = call->ArgumentAt(0);
668 Definition* right = call->ArgumentAt(1);
669
670 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() &&
671 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) {
672 const Class& cls = Class::Handle(Z, I->object_store()->object_class());
673 const Function& have_same_runtime_type = Function::ZoneHandle(Z,
674 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType()));
675 ASSERT(!have_same_runtime_type.IsNull());
676
677 ZoneGrowableArray<PushArgumentInstr*>* args =
678 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2);
679 PushArgumentInstr* arg = new (Z) PushArgumentInstr(
680 new (Z) Value(left->ArgumentAt(0)));
681 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
682 args->Add(arg);
683 arg = new (Z) PushArgumentInstr(
684 new (Z) Value(right->ArgumentAt(0)));
685 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
686 args->Add(arg);
687 StaticCallInstr* static_call = new (Z) StaticCallInstr(
688 call->token_pos(),
689 have_same_runtime_type,
690 Object::null_array(), // argument_names
691 args,
692 call->deopt_id());
693 static_call->set_result_cid(kBoolCid);
694 ReplaceCall(call, static_call);
695 return true;
696 }
697
698 return false;
699 }
700
701
609 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, 702 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
610 Token::Kind op_kind) { 703 Token::Kind op_kind) {
611 const ICData& ic_data = *call->ic_data(); 704 const ICData& ic_data = *call->ic_data();
612 ASSERT(ic_data.NumArgsTested() == 2); 705 ASSERT(ic_data.NumArgsTested() == 2);
613 706
614 ASSERT(call->ArgumentCount() == 2); 707 ASSERT(call->ArgumentCount() == 2);
615 Definition* left = call->ArgumentAt(0); 708 Definition* left = call->ArgumentAt(0);
616 Definition* right = call->ArgumentAt(1); 709 Definition* right = call->ArgumentAt(1);
617 710
618 intptr_t cid = kIllegalCid; 711 intptr_t cid = kIllegalCid;
619 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { 712 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
620 if (TryStringLengthOneEquality(call, op_kind)) { 713 return TryStringLengthOneEquality(call, op_kind);
621 return true;
622 } else {
623 return false;
624 }
625 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { 714 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
626 InsertBefore(call, 715 InsertBefore(call,
627 new(Z) CheckSmiInstr(new(Z) Value(left), 716 new(Z) CheckSmiInstr(new(Z) Value(left),
628 call->deopt_id(), 717 call->deopt_id(),
629 call->token_pos()), 718 call->token_pos()),
630 call->env(), 719 call->env(),
631 FlowGraph::kEffect); 720 FlowGraph::kEffect);
632 InsertBefore(call, 721 InsertBefore(call,
633 new(Z) CheckSmiInstr(new(Z) Value(right), 722 new(Z) CheckSmiInstr(new(Z) Value(right),
634 call->deopt_id(), 723 call->deopt_id(),
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
680 const ICData& unary_checks_1 = 769 const ICData& unary_checks_1 =
681 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); 770 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
682 AddCheckClass(right, 771 AddCheckClass(right,
683 unary_checks_1, 772 unary_checks_1,
684 call->deopt_id(), 773 call->deopt_id(),
685 call->env(), 774 call->env(),
686 call); 775 call);
687 cid = kSmiCid; 776 cid = kSmiCid;
688 } else { 777 } else {
689 // Shortcut for equality with null. 778 // Shortcut for equality with null.
779 // TODO(vegorov): this optimization is not speculative and should
780 // be hoisted out of this function.
690 ConstantInstr* right_const = right->AsConstant(); 781 ConstantInstr* right_const = right->AsConstant();
691 ConstantInstr* left_const = left->AsConstant(); 782 ConstantInstr* left_const = left->AsConstant();
692 if ((right_const != NULL && right_const->value().IsNull()) || 783 if ((right_const != NULL && right_const->value().IsNull()) ||
693 (left_const != NULL && left_const->value().IsNull())) { 784 (left_const != NULL && left_const->value().IsNull())) {
694 StrictCompareInstr* comp = 785 StrictCompareInstr* comp =
695 new(Z) StrictCompareInstr(call->token_pos(), 786 new(Z) StrictCompareInstr(call->token_pos(),
696 Token::kEQ_STRICT, 787 Token::kEQ_STRICT,
697 new(Z) Value(left), 788 new(Z) Value(left),
698 new(Z) Value(right), 789 new(Z) Value(right),
699 false); // No number check. 790 false); // No number check.
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after
1727 } 1818 }
1728 if (Token::IsTypeCastOperator(op_kind)) { 1819 if (Token::IsTypeCastOperator(op_kind)) {
1729 ReplaceWithTypeCast(instr); 1820 ReplaceWithTypeCast(instr);
1730 return; 1821 return;
1731 } 1822 }
1732 1823
1733 if (TryInlineFieldAccess(instr)) { 1824 if (TryInlineFieldAccess(instr)) {
1734 return; 1825 return;
1735 } 1826 }
1736 1827
1828 if (RecognizeRuntimeTypeGetter(instr)) {
1829 return;
1830 }
1831
1832 if ((op_kind == Token::kEQ) && TryReplaceWithHaveSameRuntimeType(instr)) {
1833 return;
1834 }
1835
1737 const ICData& unary_checks = 1836 const ICData& unary_checks =
1738 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); 1837 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
1739 if (IsAllowedForInlining(instr->deopt_id()) && 1838 if (IsAllowedForInlining(instr->deopt_id()) &&
1740 (unary_checks.NumberOfChecks() > 0)) { 1839 (unary_checks.NumberOfChecks() > 0)) {
1741 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { 1840 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
1742 return; 1841 return;
1743 } 1842 }
1744 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { 1843 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
1745 return; 1844 return;
1746 } 1845 }
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
2178 check->env(), FlowGraph::kEffect); 2277 check->env(), FlowGraph::kEffect);
2179 current_iterator()->RemoveCurrentFromGraph(); 2278 current_iterator()->RemoveCurrentFromGraph();
2180 } 2279 }
2181 } 2280 }
2182 } 2281 }
2183 } 2282 }
2184 2283
2185 #endif // DART_PRECOMPILER 2284 #endif // DART_PRECOMPILER
2186 2285
2187 } // namespace dart 2286 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698