blob: fe423012ca4e7a076437d2edcc3b1b57192db675 [file] [log] [blame]
Mingyao Yangb0b051a2016-11-17 09:04:53 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "cha_guard_optimization.h"
18
19namespace art {
20
21// Note we can only do CHA guard elimination/motion in a single pass, since
22// if a guard is not removed, another guard might be removed due to
23// the existence of the first guard. The first guard should not be further
24// removed in another pass. For example, due to further optimizations,
25// a receiver of a guard might turn out to be a parameter value, or defined at
26// a different site, which makes the guard removable as a result. However
27// it's not safe to remove the guard in another pass since another guard might
28// have been removed due to the existence of this guard.
29//
30// As a consequence, we decided not to rely on other passes to remove them
31// (such as GVN or instruction simplifier).
32
33class CHAGuardVisitor : HGraphVisitor {
34 public:
35 explicit CHAGuardVisitor(HGraph* graph)
36 : HGraphVisitor(graph),
37 block_has_cha_guard_(GetGraph()->GetBlocks().size(),
38 0,
39 graph->GetArena()->Adapter(kArenaAllocCHA)) {
40 number_of_guards_to_visit_ = GetGraph()->GetNumberOfCHAGuards();
41 DCHECK_NE(number_of_guards_to_visit_, 0u);
42 // Will recount number of guards during guard optimization.
43 GetGraph()->SetNumberOfCHAGuards(0);
44 }
45
46 void VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) OVERRIDE;
47
48 void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
49
50 private:
51 void RemoveGuard(HShouldDeoptimizeFlag* flag);
52 // Return true if `flag` is removed.
53 bool OptimizeForParameter(HShouldDeoptimizeFlag* flag, HInstruction* receiver);
54 // Return true if `flag` is removed.
55 bool OptimizeWithDominatingGuard(HShouldDeoptimizeFlag* flag, HInstruction* receiver);
56 // Return true if `flag` is hoisted.
57 bool HoistGuard(HShouldDeoptimizeFlag* flag, HInstruction* receiver);
58
59 // Record if each block has any CHA guard. It's updated during the
60 // reverse post order visit. Use int instead of bool since ArenaVector
61 // does not support bool.
62 ArenaVector<int> block_has_cha_guard_;
63
64 // The iterator that's being used for this visitor. Need it to manually
65 // advance the iterator due to removing/moving more than one instruction.
66 HInstructionIterator* instruction_iterator_;
67
68 // Used to short-circuit the pass when there is no more guards left to visit.
69 uint32_t number_of_guards_to_visit_;
70
71 DISALLOW_COPY_AND_ASSIGN(CHAGuardVisitor);
72};
73
74void CHAGuardVisitor::VisitBasicBlock(HBasicBlock* block) {
75 if (number_of_guards_to_visit_ == 0) {
76 return;
77 }
78 // Skip phis, just iterate through instructions.
79 HInstructionIterator it(block->GetInstructions());
80 instruction_iterator_ = &it;
81 for (; !it.Done(); it.Advance()) {
82 DCHECK(it.Current()->IsInBlock());
83 it.Current()->Accept(this);
84 }
85}
86
87void CHAGuardVisitor::RemoveGuard(HShouldDeoptimizeFlag* flag) {
88 HBasicBlock* block = flag->GetBlock();
89 HInstruction* compare = flag->GetNext();
90 DCHECK(compare->IsNotEqual());
91 HInstruction* deopt = compare->GetNext();
92 DCHECK(deopt->IsDeoptimize());
93
94 // Advance instruction iterator first before we remove the guard.
95 // We need to do it twice since we remove three instructions and the
96 // visitor is responsible for advancing it once.
97 instruction_iterator_->Advance();
98 instruction_iterator_->Advance();
99 block->RemoveInstruction(deopt);
100 block->RemoveInstruction(compare);
101 block->RemoveInstruction(flag);
102}
103
104bool CHAGuardVisitor::OptimizeForParameter(HShouldDeoptimizeFlag* flag,
105 HInstruction* receiver) {
106 // If some compiled code is invalidated by CHA due to class loading, the
107 // compiled code will not be entered anymore. So the very fact that the
108 // compiled code is invoked guarantees that a parameter receiver conforms
109 // to all the CHA devirtualization assumptions made by the compiled code,
110 // since all parameter receivers pre-exist any (potential) invalidation of
111 // the compiled code.
112 //
113 // TODO: allow more cases such as a phi whose inputs are all parameters.
114 if (receiver->IsParameterValue()) {
115 RemoveGuard(flag);
116 return true;
117 }
118 return false;
119}
120
121bool CHAGuardVisitor::OptimizeWithDominatingGuard(HShouldDeoptimizeFlag* flag,
122 HInstruction* receiver) {
123 // If there is another guard that dominates the current guard, and
124 // that guard is dominated by receiver's definition, then the current
125 // guard can be eliminated, since receiver must pre-exist that other
126 // guard, and passing that guard guarantees that receiver conforms to
127 // all the CHA devirtualization assumptions.
128 HBasicBlock* dominator = flag->GetBlock();
129 HBasicBlock* receiver_def_block = receiver->GetBlock();
130
131 // Complexity of the following algorithm:
132 // We potentially need to traverse the full dominator chain to receiver_def_block,
133 // plus a (partial) linear search within one block for each guard.
134 // So the worst case for each guard is bounded by the size of the
135 // biggest block plus the depth of the dominating tree.
136
137 while (dominator != receiver_def_block) {
138 if (block_has_cha_guard_[dominator->GetBlockId()] == 1) {
139 RemoveGuard(flag);
140 return true;
141 }
142 dominator = dominator->GetDominator();
143 }
144
145 // At this point dominator is the block where receiver is defined.
146 // We do a linear search within dominator to see if there is a guard after
147 // receiver's definition.
148 HInstruction* instruction;
149 if (dominator == flag->GetBlock()) {
150 // Flag and receiver are defined in the same block. Search backward from
151 // the current guard.
152 instruction = flag->GetPrevious();
153 } else {
154 // Search backward from the last instruction of that dominator.
155 instruction = dominator->GetLastInstruction();
156 }
157 while (instruction != receiver) {
158 if (instruction == nullptr) {
159 // receiver must be defined in this block, we didn't find it
160 // in the instruction list, so it must be a Phi.
161 DCHECK(receiver->IsPhi());
162 break;
163 }
164 if (instruction->IsShouldDeoptimizeFlag()) {
165 RemoveGuard(flag);
166 return true;
167 }
168 instruction = instruction->GetPrevious();
169 }
170 return false;
171}
172
173bool CHAGuardVisitor::HoistGuard(HShouldDeoptimizeFlag* flag,
174 HInstruction* receiver) {
175 // If receiver is loop invariant, we can hoist the guard out of the
176 // loop since passing a guard before entering the loop guarantees that
177 // receiver conforms to all the CHA devirtualization assumptions.
178 // We only hoist guards out of the inner loop since that offers most of the
179 // benefit and it might help remove other guards in the inner loop.
180 HBasicBlock* block = flag->GetBlock();
181 HLoopInformation* loop_info = block->GetLoopInformation();
182 if (loop_info != nullptr &&
183 !loop_info->IsIrreducible() &&
184 loop_info->IsDefinedOutOfTheLoop(receiver)) {
185 HInstruction* compare = flag->GetNext();
186 DCHECK(compare->IsNotEqual());
187 HInstruction* deopt = compare->GetNext();
188 DCHECK(deopt->IsDeoptimize());
189
190 // Advance instruction iterator first before we move the guard.
191 // We need to do it twice since we move three instructions and the
192 // visitor is responsible for advancing it once.
193 instruction_iterator_->Advance();
194 instruction_iterator_->Advance();
195
196 HBasicBlock* pre_header = loop_info->GetPreHeader();
197 flag->MoveBefore(pre_header->GetLastInstruction());
198 compare->MoveBefore(pre_header->GetLastInstruction());
199
200 block->RemoveInstruction(deopt);
201 HInstruction* suspend = loop_info->GetSuspendCheck();
202 // Need a new deoptimize instruction that copies the environment
203 // of the suspend instruction for the loop.
204 HDeoptimize* deoptimize =
205 new (GetGraph()->GetArena()) HDeoptimize(compare, suspend->GetDexPc());
206 pre_header->InsertInstructionBefore(deoptimize, pre_header->GetLastInstruction());
207 deoptimize->CopyEnvironmentFromWithLoopPhiAdjustment(
208 suspend->GetEnvironment(), loop_info->GetHeader());
209 block_has_cha_guard_[pre_header->GetBlockId()] = 1;
210 GetGraph()->IncrementNumberOfCHAGuards();
211 return true;
212 }
213 return false;
214}
215
216void CHAGuardVisitor::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
217 number_of_guards_to_visit_--;
218 HInstruction* receiver = flag->InputAt(0);
219 // Don't need the receiver anymore.
220 flag->RemoveInputAt(0);
221 if (receiver->IsNullCheck()) {
222 receiver = receiver->InputAt(0);
223 }
224
225 if (OptimizeForParameter(flag, receiver)) {
226 DCHECK(!flag->IsInBlock());
227 return;
228 }
229 if (OptimizeWithDominatingGuard(flag, receiver)) {
230 DCHECK(!flag->IsInBlock());
231 return;
232 }
233 if (HoistGuard(flag, receiver)) {
234 DCHECK(flag->IsInBlock());
235 return;
236 }
237
238 // Need to keep the CHA guard in place.
239 block_has_cha_guard_[flag->GetBlock()->GetBlockId()] = 1;
240 GetGraph()->IncrementNumberOfCHAGuards();
241}
242
243void CHAGuardOptimization::Run() {
244 if (graph_->GetNumberOfCHAGuards() == 0) {
245 return;
246 }
247 CHAGuardVisitor visitor(graph_);
248 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
249 visitor.VisitBasicBlock(block);
250 }
251}
252
253} // namespace art