1 /*
2  * Copyright (C) 2014 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 #include "nodes.h"
17 
18 #include <cfloat>
19 
20 #include "art_method-inl.h"
21 #include "base/bit_utils.h"
22 #include "base/bit_vector-inl.h"
23 #include "base/stl_util.h"
24 #include "class_linker-inl.h"
25 #include "code_generator.h"
26 #include "common_dominator.h"
27 #include "intrinsics.h"
28 #include "mirror/class-inl.h"
29 #include "scoped_thread_state_change-inl.h"
30 #include "ssa_builder.h"
31 
32 namespace art {
33 
34 // Enable floating-point static evaluation during constant folding
35 // only if all floating-point operations and constants evaluate in the
36 // range and precision of the type used (i.e., 32-bit float, 64-bit
37 // double).
38 static constexpr bool kEnableFloatingPointStaticEvaluation = (FLT_EVAL_METHOD == 0);
39 
InitializeInexactObjectRTI(VariableSizedHandleScope * handles)40 void HGraph::InitializeInexactObjectRTI(VariableSizedHandleScope* handles) {
41   ScopedObjectAccess soa(Thread::Current());
42   // Create the inexact Object reference type and store it in the HGraph.
43   ClassLinker* linker = Runtime::Current()->GetClassLinker();
44   inexact_object_rti_ = ReferenceTypeInfo::Create(
45       handles->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject)),
46       /* is_exact */ false);
47 }
48 
AddBlock(HBasicBlock * block)49 void HGraph::AddBlock(HBasicBlock* block) {
50   block->SetBlockId(blocks_.size());
51   blocks_.push_back(block);
52 }
53 
FindBackEdges(ArenaBitVector * visited)54 void HGraph::FindBackEdges(ArenaBitVector* visited) {
55   // "visited" must be empty on entry, it's an output argument for all visited (i.e. live) blocks.
56   DCHECK_EQ(visited->GetHighestBitSet(), -1);
57 
58   // Allocate memory from local ScopedArenaAllocator.
59   ScopedArenaAllocator allocator(GetArenaStack());
60   // Nodes that we're currently visiting, indexed by block id.
61   ArenaBitVector visiting(
62       &allocator, blocks_.size(), /* expandable */ false, kArenaAllocGraphBuilder);
63   visiting.ClearAllBits();
64   // Number of successors visited from a given node, indexed by block id.
65   ScopedArenaVector<size_t> successors_visited(blocks_.size(),
66                                                0u,
67                                                allocator.Adapter(kArenaAllocGraphBuilder));
68   // Stack of nodes that we're currently visiting (same as marked in "visiting" above).
69   ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder));
70   constexpr size_t kDefaultWorklistSize = 8;
71   worklist.reserve(kDefaultWorklistSize);
72   visited->SetBit(entry_block_->GetBlockId());
73   visiting.SetBit(entry_block_->GetBlockId());
74   worklist.push_back(entry_block_);
75 
76   while (!worklist.empty()) {
77     HBasicBlock* current = worklist.back();
78     uint32_t current_id = current->GetBlockId();
79     if (successors_visited[current_id] == current->GetSuccessors().size()) {
80       visiting.ClearBit(current_id);
81       worklist.pop_back();
82     } else {
83       HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
84       uint32_t successor_id = successor->GetBlockId();
85       if (visiting.IsBitSet(successor_id)) {
86         DCHECK(ContainsElement(worklist, successor));
87         successor->AddBackEdge(current);
88       } else if (!visited->IsBitSet(successor_id)) {
89         visited->SetBit(successor_id);
90         visiting.SetBit(successor_id);
91         worklist.push_back(successor);
92       }
93     }
94   }
95 }
96 
97 // Remove the environment use records of the instruction for users.
RemoveEnvironmentUses(HInstruction * instruction)98 void RemoveEnvironmentUses(HInstruction* instruction) {
99   for (HEnvironment* environment = instruction->GetEnvironment();
100        environment != nullptr;
101        environment = environment->GetParent()) {
102     for (size_t i = 0, e = environment->Size(); i < e; ++i) {
103       if (environment->GetInstructionAt(i) != nullptr) {
104         environment->RemoveAsUserOfInput(i);
105       }
106     }
107   }
108 }
109 
110 // Return whether the instruction has an environment and it's used by others.
HasEnvironmentUsedByOthers(HInstruction * instruction)111 bool HasEnvironmentUsedByOthers(HInstruction* instruction) {
112   for (HEnvironment* environment = instruction->GetEnvironment();
113        environment != nullptr;
114        environment = environment->GetParent()) {
115     for (size_t i = 0, e = environment->Size(); i < e; ++i) {
116       HInstruction* user = environment->GetInstructionAt(i);
117       if (user != nullptr) {
118         return true;
119       }
120     }
121   }
122   return false;
123 }
124 
125 // Reset environment records of the instruction itself.
ResetEnvironmentInputRecords(HInstruction * instruction)126 void ResetEnvironmentInputRecords(HInstruction* instruction) {
127   for (HEnvironment* environment = instruction->GetEnvironment();
128        environment != nullptr;
129        environment = environment->GetParent()) {
130     for (size_t i = 0, e = environment->Size(); i < e; ++i) {
131       DCHECK(environment->GetHolder() == instruction);
132       if (environment->GetInstructionAt(i) != nullptr) {
133         environment->SetRawEnvAt(i, nullptr);
134       }
135     }
136   }
137 }
138 
RemoveAsUser(HInstruction * instruction)139 static void RemoveAsUser(HInstruction* instruction) {
140   instruction->RemoveAsUserOfAllInputs();
141   RemoveEnvironmentUses(instruction);
142 }
143 
RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector & visited) const144 void HGraph::RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const {
145   for (size_t i = 0; i < blocks_.size(); ++i) {
146     if (!visited.IsBitSet(i)) {
147       HBasicBlock* block = blocks_[i];
148       if (block == nullptr) continue;
149       DCHECK(block->GetPhis().IsEmpty()) << "Phis are not inserted at this stage";
150       for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
151         RemoveAsUser(it.Current());
152       }
153     }
154   }
155 }
156 
RemoveDeadBlocks(const ArenaBitVector & visited)157 void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) {
158   for (size_t i = 0; i < blocks_.size(); ++i) {
159     if (!visited.IsBitSet(i)) {
160       HBasicBlock* block = blocks_[i];
161       if (block == nullptr) continue;
162       // We only need to update the successor, which might be live.
163       for (HBasicBlock* successor : block->GetSuccessors()) {
164         successor->RemovePredecessor(block);
165       }
166       // Remove the block from the list of blocks, so that further analyses
167       // never see it.
168       blocks_[i] = nullptr;
169       if (block->IsExitBlock()) {
170         SetExitBlock(nullptr);
171       }
172       // Mark the block as removed. This is used by the HGraphBuilder to discard
173       // the block as a branch target.
174       block->SetGraph(nullptr);
175     }
176   }
177 }
178 
BuildDominatorTree()179 GraphAnalysisResult HGraph::BuildDominatorTree() {
180   // Allocate memory from local ScopedArenaAllocator.
181   ScopedArenaAllocator allocator(GetArenaStack());
182 
183   ArenaBitVector visited(&allocator, blocks_.size(), false, kArenaAllocGraphBuilder);
184   visited.ClearAllBits();
185 
186   // (1) Find the back edges in the graph doing a DFS traversal.
187   FindBackEdges(&visited);
188 
189   // (2) Remove instructions and phis from blocks not visited during
190   //     the initial DFS as users from other instructions, so that
191   //     users can be safely removed before uses later.
192   RemoveInstructionsAsUsersFromDeadBlocks(visited);
193 
194   // (3) Remove blocks not visited during the initial DFS.
195   //     Step (5) requires dead blocks to be removed from the
196   //     predecessors list of live blocks.
197   RemoveDeadBlocks(visited);
198 
199   // (4) Simplify the CFG now, so that we don't need to recompute
200   //     dominators and the reverse post order.
201   SimplifyCFG();
202 
203   // (5) Compute the dominance information and the reverse post order.
204   ComputeDominanceInformation();
205 
206   // (6) Analyze loops discovered through back edge analysis, and
207   //     set the loop information on each block.
208   GraphAnalysisResult result = AnalyzeLoops();
209   if (result != kAnalysisSuccess) {
210     return result;
211   }
212 
213   // (7) Precompute per-block try membership before entering the SSA builder,
214   //     which needs the information to build catch block phis from values of
215   //     locals at throwing instructions inside try blocks.
216   ComputeTryBlockInformation();
217 
218   return kAnalysisSuccess;
219 }
220 
ClearDominanceInformation()221 void HGraph::ClearDominanceInformation() {
222   for (HBasicBlock* block : GetReversePostOrder()) {
223     block->ClearDominanceInformation();
224   }
225   reverse_post_order_.clear();
226 }
227 
ClearLoopInformation()228 void HGraph::ClearLoopInformation() {
229   SetHasIrreducibleLoops(false);
230   for (HBasicBlock* block : GetReversePostOrder()) {
231     block->SetLoopInformation(nullptr);
232   }
233 }
234 
ClearDominanceInformation()235 void HBasicBlock::ClearDominanceInformation() {
236   dominated_blocks_.clear();
237   dominator_ = nullptr;
238 }
239 
GetFirstInstructionDisregardMoves() const240 HInstruction* HBasicBlock::GetFirstInstructionDisregardMoves() const {
241   HInstruction* instruction = GetFirstInstruction();
242   while (instruction->IsParallelMove()) {
243     instruction = instruction->GetNext();
244   }
245   return instruction;
246 }
247 
UpdateDominatorOfSuccessor(HBasicBlock * block,HBasicBlock * successor)248 static bool UpdateDominatorOfSuccessor(HBasicBlock* block, HBasicBlock* successor) {
249   DCHECK(ContainsElement(block->GetSuccessors(), successor));
250 
251   HBasicBlock* old_dominator = successor->GetDominator();
252   HBasicBlock* new_dominator =
253       (old_dominator == nullptr) ? block
254                                  : CommonDominator::ForPair(old_dominator, block);
255 
256   if (old_dominator == new_dominator) {
257     return false;
258   } else {
259     successor->SetDominator(new_dominator);
260     return true;
261   }
262 }
263 
ComputeDominanceInformation()264 void HGraph::ComputeDominanceInformation() {
265   DCHECK(reverse_post_order_.empty());
266   reverse_post_order_.reserve(blocks_.size());
267   reverse_post_order_.push_back(entry_block_);
268 
269   // Allocate memory from local ScopedArenaAllocator.
270   ScopedArenaAllocator allocator(GetArenaStack());
271   // Number of visits of a given node, indexed by block id.
272   ScopedArenaVector<size_t> visits(blocks_.size(), 0u, allocator.Adapter(kArenaAllocGraphBuilder));
273   // Number of successors visited from a given node, indexed by block id.
274   ScopedArenaVector<size_t> successors_visited(blocks_.size(),
275                                                0u,
276                                                allocator.Adapter(kArenaAllocGraphBuilder));
277   // Nodes for which we need to visit successors.
278   ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder));
279   constexpr size_t kDefaultWorklistSize = 8;
280   worklist.reserve(kDefaultWorklistSize);
281   worklist.push_back(entry_block_);
282 
283   while (!worklist.empty()) {
284     HBasicBlock* current = worklist.back();
285     uint32_t current_id = current->GetBlockId();
286     if (successors_visited[current_id] == current->GetSuccessors().size()) {
287       worklist.pop_back();
288     } else {
289       HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
290       UpdateDominatorOfSuccessor(current, successor);
291 
292       // Once all the forward edges have been visited, we know the immediate
293       // dominator of the block. We can then start visiting its successors.
294       if (++visits[successor->GetBlockId()] ==
295           successor->GetPredecessors().size() - successor->NumberOfBackEdges()) {
296         reverse_post_order_.push_back(successor);
297         worklist.push_back(successor);
298       }
299     }
300   }
301 
302   // Check if the graph has back edges not dominated by their respective headers.
303   // If so, we need to update the dominators of those headers and recursively of
304   // their successors. We do that with a fix-point iteration over all blocks.
305   // The algorithm is guaranteed to terminate because it loops only if the sum
306   // of all dominator chains has decreased in the current iteration.
307   bool must_run_fix_point = false;
308   for (HBasicBlock* block : blocks_) {
309     if (block != nullptr &&
310         block->IsLoopHeader() &&
311         block->GetLoopInformation()->HasBackEdgeNotDominatedByHeader()) {
312       must_run_fix_point = true;
313       break;
314     }
315   }
316   if (must_run_fix_point) {
317     bool update_occurred = true;
318     while (update_occurred) {
319       update_occurred = false;
320       for (HBasicBlock* block : GetReversePostOrder()) {
321         for (HBasicBlock* successor : block->GetSuccessors()) {
322           update_occurred |= UpdateDominatorOfSuccessor(block, successor);
323         }
324       }
325     }
326   }
327 
328   // Make sure that there are no remaining blocks whose dominator information
329   // needs to be updated.
330   if (kIsDebugBuild) {
331     for (HBasicBlock* block : GetReversePostOrder()) {
332       for (HBasicBlock* successor : block->GetSuccessors()) {
333         DCHECK(!UpdateDominatorOfSuccessor(block, successor));
334       }
335     }
336   }
337 
338   // Populate `dominated_blocks_` information after computing all dominators.
339   // The potential presence of irreducible loops requires to do it after.
340   for (HBasicBlock* block : GetReversePostOrder()) {
341     if (!block->IsEntryBlock()) {
342       block->GetDominator()->AddDominatedBlock(block);
343     }
344   }
345 }
346 
SplitEdge(HBasicBlock * block,HBasicBlock * successor)347 HBasicBlock* HGraph::SplitEdge(HBasicBlock* block, HBasicBlock* successor) {
348   HBasicBlock* new_block = new (allocator_) HBasicBlock(this, successor->GetDexPc());
349   AddBlock(new_block);
350   // Use `InsertBetween` to ensure the predecessor index and successor index of
351   // `block` and `successor` are preserved.
352   new_block->InsertBetween(block, successor);
353   return new_block;
354 }
355 
SplitCriticalEdge(HBasicBlock * block,HBasicBlock * successor)356 void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
357   // Insert a new node between `block` and `successor` to split the
358   // critical edge.
359   HBasicBlock* new_block = SplitEdge(block, successor);
360   new_block->AddInstruction(new (allocator_) HGoto(successor->GetDexPc()));
361   if (successor->IsLoopHeader()) {
362     // If we split at a back edge boundary, make the new block the back edge.
363     HLoopInformation* info = successor->GetLoopInformation();
364     if (info->IsBackEdge(*block)) {
365       info->RemoveBackEdge(block);
366       info->AddBackEdge(new_block);
367     }
368   }
369 }
370 
371 // Reorder phi inputs to match reordering of the block's predecessors.
FixPhisAfterPredecessorsReodering(HBasicBlock * block,size_t first,size_t second)372 static void FixPhisAfterPredecessorsReodering(HBasicBlock* block, size_t first, size_t second) {
373   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
374     HPhi* phi = it.Current()->AsPhi();
375     HInstruction* first_instr = phi->InputAt(first);
376     HInstruction* second_instr = phi->InputAt(second);
377     phi->ReplaceInput(first_instr, second);
378     phi->ReplaceInput(second_instr, first);
379   }
380 }
381 
382 // Make sure that the first predecessor of a loop header is the incoming block.
OrderLoopHeaderPredecessors(HBasicBlock * header)383 void HGraph::OrderLoopHeaderPredecessors(HBasicBlock* header) {
384   DCHECK(header->IsLoopHeader());
385   HLoopInformation* info = header->GetLoopInformation();
386   if (info->IsBackEdge(*header->GetPredecessors()[0])) {
387     HBasicBlock* to_swap = header->GetPredecessors()[0];
388     for (size_t pred = 1, e = header->GetPredecessors().size(); pred < e; ++pred) {
389       HBasicBlock* predecessor = header->GetPredecessors()[pred];
390       if (!info->IsBackEdge(*predecessor)) {
391         header->predecessors_[pred] = to_swap;
392         header->predecessors_[0] = predecessor;
393         FixPhisAfterPredecessorsReodering(header, 0, pred);
394         break;
395       }
396     }
397   }
398 }
399 
400 // Transform control flow of the loop to a single preheader format (don't touch the data flow).
401 // New_preheader can be already among the header predecessors - this situation will be correctly
402 // processed.
FixControlForNewSinglePreheader(HBasicBlock * header,HBasicBlock * new_preheader)403 static void FixControlForNewSinglePreheader(HBasicBlock* header, HBasicBlock* new_preheader) {
404   HLoopInformation* loop_info = header->GetLoopInformation();
405   for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
406     HBasicBlock* predecessor = header->GetPredecessors()[pred];
407     if (!loop_info->IsBackEdge(*predecessor) && predecessor != new_preheader) {
408       predecessor->ReplaceSuccessor(header, new_preheader);
409       pred--;
410     }
411   }
412 }
413 
414 //             == Before ==                                               == After ==
415 //      _________         _________                               _________         _________
416 //     | B0      |       | B1      |      (old preheaders)       | B0      |       | B1      |
417 //     |=========|       |=========|                             |=========|       |=========|
418 //     | i0 = .. |       | i1 = .. |                             | i0 = .. |       | i1 = .. |
419 //     |_________|       |_________|                             |_________|       |_________|
420 //           \               /                                         \              /
421 //            \             /                                        ___v____________v___
422 //             \           /               (new preheader)          | B20 <- B0, B1      |
423 //              |         |                                         |====================|
424 //              |         |                                         | i20 = phi(i0, i1)  |
425 //              |         |                                         |____________________|
426 //              |         |                                                   |
427 //    /\        |         |        /\                           /\            |              /\
428 //   /  v_______v_________v_______v  \                         /  v___________v_____________v  \
429 //  |  | B10 <- B0, B1, B2, B3     |  |                       |  | B10 <- B20, B2, B3        |  |
430 //  |  |===========================|  |       (header)        |  |===========================|  |
431 //  |  | i10 = phi(i0, i1, i2, i3) |  |                       |  | i10 = phi(i20, i2, i3)    |  |
432 //  |  |___________________________|  |                       |  |___________________________|  |
433 //  |        /               \        |                       |        /               \        |
434 //  |      ...              ...       |                       |      ...              ...       |
435 //  |   _________         _________   |                       |   _________         _________   |
436 //  |  | B2      |       | B3      |  |                       |  | B2      |       | B3      |  |
437 //  |  |=========|       |=========|  |     (back edges)      |  |=========|       |=========|  |
438 //  |  | i2 = .. |       | i3 = .. |  |                       |  | i2 = .. |       | i3 = .. |  |
439 //  |  |_________|       |_________|  |                       |  |_________|       |_________|  |
440 //   \     /                   \     /                         \     /                   \     /
441 //    \___/                     \___/                           \___/                     \___/
442 //
TransformLoopToSinglePreheaderFormat(HBasicBlock * header)443 void HGraph::TransformLoopToSinglePreheaderFormat(HBasicBlock* header) {
444   HLoopInformation* loop_info = header->GetLoopInformation();
445 
446   HBasicBlock* preheader = new (allocator_) HBasicBlock(this, header->GetDexPc());
447   AddBlock(preheader);
448   preheader->AddInstruction(new (allocator_) HGoto(header->GetDexPc()));
449 
450   // If the old header has no Phis then we only need to fix the control flow.
451   if (header->GetPhis().IsEmpty()) {
452     FixControlForNewSinglePreheader(header, preheader);
453     preheader->AddSuccessor(header);
454     return;
455   }
456 
457   // Find the first non-back edge block in the header's predecessors list.
458   size_t first_nonbackedge_pred_pos = 0;
459   bool found = false;
460   for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
461     HBasicBlock* predecessor = header->GetPredecessors()[pred];
462     if (!loop_info->IsBackEdge(*predecessor)) {
463       first_nonbackedge_pred_pos = pred;
464       found = true;
465       break;
466     }
467   }
468 
469   DCHECK(found);
470 
471   // Fix the data-flow.
472   for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) {
473     HPhi* header_phi = it.Current()->AsPhi();
474 
475     HPhi* preheader_phi = new (GetAllocator()) HPhi(GetAllocator(),
476                                                     header_phi->GetRegNumber(),
477                                                     0,
478                                                     header_phi->GetType());
479     if (header_phi->GetType() == DataType::Type::kReference) {
480       preheader_phi->SetReferenceTypeInfo(header_phi->GetReferenceTypeInfo());
481     }
482     preheader->AddPhi(preheader_phi);
483 
484     HInstruction* orig_input = header_phi->InputAt(first_nonbackedge_pred_pos);
485     header_phi->ReplaceInput(preheader_phi, first_nonbackedge_pred_pos);
486     preheader_phi->AddInput(orig_input);
487 
488     for (size_t input_pos = first_nonbackedge_pred_pos + 1;
489          input_pos < header_phi->InputCount();
490          input_pos++) {
491       HInstruction* input = header_phi->InputAt(input_pos);
492       HBasicBlock* pred_block = header->GetPredecessors()[input_pos];
493 
494       if (loop_info->Contains(*pred_block)) {
495         DCHECK(loop_info->IsBackEdge(*pred_block));
496       } else {
497         preheader_phi->AddInput(input);
498         header_phi->RemoveInputAt(input_pos);
499         input_pos--;
500       }
501     }
502   }
503 
504   // Fix the control-flow.
505   HBasicBlock* first_pred = header->GetPredecessors()[first_nonbackedge_pred_pos];
506   preheader->InsertBetween(first_pred, header);
507 
508   FixControlForNewSinglePreheader(header, preheader);
509 }
510 
SimplifyLoop(HBasicBlock * header)511 void HGraph::SimplifyLoop(HBasicBlock* header) {
512   HLoopInformation* info = header->GetLoopInformation();
513 
514   // Make sure the loop has only one pre header. This simplifies SSA building by having
515   // to just look at the pre header to know which locals are initialized at entry of the
516   // loop. Also, don't allow the entry block to be a pre header: this simplifies inlining
517   // this graph.
518   size_t number_of_incomings = header->GetPredecessors().size() - info->NumberOfBackEdges();
519   if (number_of_incomings != 1 || (GetEntryBlock()->GetSingleSuccessor() == header)) {
520     TransformLoopToSinglePreheaderFormat(header);
521   }
522 
523   OrderLoopHeaderPredecessors(header);
524 
525   HInstruction* first_instruction = header->GetFirstInstruction();
526   if (first_instruction != nullptr && first_instruction->IsSuspendCheck()) {
527     // Called from DeadBlockElimination. Update SuspendCheck pointer.
528     info->SetSuspendCheck(first_instruction->AsSuspendCheck());
529   }
530 }
531 
ComputeTryBlockInformation()532 void HGraph::ComputeTryBlockInformation() {
533   // Iterate in reverse post order to propagate try membership information from
534   // predecessors to their successors.
535   for (HBasicBlock* block : GetReversePostOrder()) {
536     if (block->IsEntryBlock() || block->IsCatchBlock()) {
537       // Catch blocks after simplification have only exceptional predecessors
538       // and hence are never in tries.
539       continue;
540     }
541 
542     // Infer try membership from the first predecessor. Having simplified loops,
543     // the first predecessor can never be a back edge and therefore it must have
544     // been visited already and had its try membership set.
545     HBasicBlock* first_predecessor = block->GetPredecessors()[0];
546     DCHECK(!block->IsLoopHeader() || !block->GetLoopInformation()->IsBackEdge(*first_predecessor));
547     const HTryBoundary* try_entry = first_predecessor->ComputeTryEntryOfSuccessors();
548     if (try_entry != nullptr &&
549         (block->GetTryCatchInformation() == nullptr ||
550          try_entry != &block->GetTryCatchInformation()->GetTryEntry())) {
551       // We are either setting try block membership for the first time or it
552       // has changed.
553       block->SetTryCatchInformation(new (allocator_) TryCatchInformation(*try_entry));
554     }
555   }
556 }
557 
SimplifyCFG()558 void HGraph::SimplifyCFG() {
559 // Simplify the CFG for future analysis, and code generation:
560   // (1): Split critical edges.
561   // (2): Simplify loops by having only one preheader.
562   // NOTE: We're appending new blocks inside the loop, so we need to use index because iterators
563   // can be invalidated. We remember the initial size to avoid iterating over the new blocks.
564   for (size_t block_id = 0u, end = blocks_.size(); block_id != end; ++block_id) {
565     HBasicBlock* block = blocks_[block_id];
566     if (block == nullptr) continue;
567     if (block->GetSuccessors().size() > 1) {
568       // Only split normal-flow edges. We cannot split exceptional edges as they
569       // are synthesized (approximate real control flow), and we do not need to
570       // anyway. Moves that would be inserted there are performed by the runtime.
571       ArrayRef<HBasicBlock* const> normal_successors = block->GetNormalSuccessors();
572       for (size_t j = 0, e = normal_successors.size(); j < e; ++j) {
573         HBasicBlock* successor = normal_successors[j];
574         DCHECK(!successor->IsCatchBlock());
575         if (successor == exit_block_) {
576           // (Throw/Return/ReturnVoid)->TryBoundary->Exit. Special case which we
577           // do not want to split because Goto->Exit is not allowed.
578           DCHECK(block->IsSingleTryBoundary());
579         } else if (successor->GetPredecessors().size() > 1) {
580           SplitCriticalEdge(block, successor);
581           // SplitCriticalEdge could have invalidated the `normal_successors`
582           // ArrayRef. We must re-acquire it.
583           normal_successors = block->GetNormalSuccessors();
584           DCHECK_EQ(normal_successors[j]->GetSingleSuccessor(), successor);
585           DCHECK_EQ(e, normal_successors.size());
586         }
587       }
588     }
589     if (block->IsLoopHeader()) {
590       SimplifyLoop(block);
591     } else if (!block->IsEntryBlock() &&
592                block->GetFirstInstruction() != nullptr &&
593                block->GetFirstInstruction()->IsSuspendCheck()) {
594       // We are being called by the dead code elimiation pass, and what used to be
595       // a loop got dismantled. Just remove the suspend check.
596       block->RemoveInstruction(block->GetFirstInstruction());
597     }
598   }
599 }
600 
AnalyzeLoops() const601 GraphAnalysisResult HGraph::AnalyzeLoops() const {
602   // We iterate post order to ensure we visit inner loops before outer loops.
603   // `PopulateRecursive` needs this guarantee to know whether a natural loop
604   // contains an irreducible loop.
605   for (HBasicBlock* block : GetPostOrder()) {
606     if (block->IsLoopHeader()) {
607       if (block->IsCatchBlock()) {
608         // TODO: Dealing with exceptional back edges could be tricky because
609         //       they only approximate the real control flow. Bail out for now.
610         VLOG(compiler) << "Not compiled: Exceptional back edges";
611         return kAnalysisFailThrowCatchLoop;
612       }
613       block->GetLoopInformation()->Populate();
614     }
615   }
616   return kAnalysisSuccess;
617 }
618 
Dump(std::ostream & os)619 void HLoopInformation::Dump(std::ostream& os) {
620   os << "header: " << header_->GetBlockId() << std::endl;
621   os << "pre header: " << GetPreHeader()->GetBlockId() << std::endl;
622   for (HBasicBlock* block : back_edges_) {
623     os << "back edge: " << block->GetBlockId() << std::endl;
624   }
625   for (HBasicBlock* block : header_->GetPredecessors()) {
626     os << "predecessor: " << block->GetBlockId() << std::endl;
627   }
628   for (uint32_t idx : blocks_.Indexes()) {
629     os << "  in loop: " << idx << std::endl;
630   }
631 }
632 
InsertConstant(HConstant * constant)633 void HGraph::InsertConstant(HConstant* constant) {
634   // New constants are inserted before the SuspendCheck at the bottom of the
635   // entry block. Note that this method can be called from the graph builder and
636   // the entry block therefore may not end with SuspendCheck->Goto yet.
637   HInstruction* insert_before = nullptr;
638 
639   HInstruction* gota = entry_block_->GetLastInstruction();
640   if (gota != nullptr && gota->IsGoto()) {
641     HInstruction* suspend_check = gota->GetPrevious();
642     if (suspend_check != nullptr && suspend_check->IsSuspendCheck()) {
643       insert_before = suspend_check;
644     } else {
645       insert_before = gota;
646     }
647   }
648 
649   if (insert_before == nullptr) {
650     entry_block_->AddInstruction(constant);
651   } else {
652     entry_block_->InsertInstructionBefore(constant, insert_before);
653   }
654 }
655 
GetNullConstant(uint32_t dex_pc)656 HNullConstant* HGraph::GetNullConstant(uint32_t dex_pc) {
657   // For simplicity, don't bother reviving the cached null constant if it is
658   // not null and not in a block. Otherwise, we need to clear the instruction
659   // id and/or any invariants the graph is assuming when adding new instructions.
660   if ((cached_null_constant_ == nullptr) || (cached_null_constant_->GetBlock() == nullptr)) {
661     cached_null_constant_ = new (allocator_) HNullConstant(dex_pc);
662     cached_null_constant_->SetReferenceTypeInfo(inexact_object_rti_);
663     InsertConstant(cached_null_constant_);
664   }
665   if (kIsDebugBuild) {
666     ScopedObjectAccess soa(Thread::Current());
667     DCHECK(cached_null_constant_->GetReferenceTypeInfo().IsValid());
668   }
669   return cached_null_constant_;
670 }
671 
GetCurrentMethod()672 HCurrentMethod* HGraph::GetCurrentMethod() {
673   // For simplicity, don't bother reviving the cached current method if it is
674   // not null and not in a block. Otherwise, we need to clear the instruction
675   // id and/or any invariants the graph is assuming when adding new instructions.
676   if ((cached_current_method_ == nullptr) || (cached_current_method_->GetBlock() == nullptr)) {
677     cached_current_method_ = new (allocator_) HCurrentMethod(
678         Is64BitInstructionSet(instruction_set_) ? DataType::Type::kInt64 : DataType::Type::kInt32,
679         entry_block_->GetDexPc());
680     if (entry_block_->GetFirstInstruction() == nullptr) {
681       entry_block_->AddInstruction(cached_current_method_);
682     } else {
683       entry_block_->InsertInstructionBefore(
684           cached_current_method_, entry_block_->GetFirstInstruction());
685     }
686   }
687   return cached_current_method_;
688 }
689 
GetMethodName() const690 const char* HGraph::GetMethodName() const {
691   const DexFile::MethodId& method_id = dex_file_.GetMethodId(method_idx_);
692   return dex_file_.GetMethodName(method_id);
693 }
694 
PrettyMethod(bool with_signature) const695 std::string HGraph::PrettyMethod(bool with_signature) const {
696   return dex_file_.PrettyMethod(method_idx_, with_signature);
697 }
698 
GetConstant(DataType::Type type,int64_t value,uint32_t dex_pc)699 HConstant* HGraph::GetConstant(DataType::Type type, int64_t value, uint32_t dex_pc) {
700   switch (type) {
701     case DataType::Type::kBool:
702       DCHECK(IsUint<1>(value));
703       FALLTHROUGH_INTENDED;
704     case DataType::Type::kUint8:
705     case DataType::Type::kInt8:
706     case DataType::Type::kUint16:
707     case DataType::Type::kInt16:
708     case DataType::Type::kInt32:
709       DCHECK(IsInt(DataType::Size(type) * kBitsPerByte, value));
710       return GetIntConstant(static_cast<int32_t>(value), dex_pc);
711 
712     case DataType::Type::kInt64:
713       return GetLongConstant(value, dex_pc);
714 
715     default:
716       LOG(FATAL) << "Unsupported constant type";
717       UNREACHABLE();
718   }
719 }
720 
CacheFloatConstant(HFloatConstant * constant)721 void HGraph::CacheFloatConstant(HFloatConstant* constant) {
722   int32_t value = bit_cast<int32_t, float>(constant->GetValue());
723   DCHECK(cached_float_constants_.find(value) == cached_float_constants_.end());
724   cached_float_constants_.Overwrite(value, constant);
725 }
726 
CacheDoubleConstant(HDoubleConstant * constant)727 void HGraph::CacheDoubleConstant(HDoubleConstant* constant) {
728   int64_t value = bit_cast<int64_t, double>(constant->GetValue());
729   DCHECK(cached_double_constants_.find(value) == cached_double_constants_.end());
730   cached_double_constants_.Overwrite(value, constant);
731 }
732 
Add(HBasicBlock * block)733 void HLoopInformation::Add(HBasicBlock* block) {
734   blocks_.SetBit(block->GetBlockId());
735 }
736 
Remove(HBasicBlock * block)737 void HLoopInformation::Remove(HBasicBlock* block) {
738   blocks_.ClearBit(block->GetBlockId());
739 }
740 
PopulateRecursive(HBasicBlock * block)741 void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
742   if (blocks_.IsBitSet(block->GetBlockId())) {
743     return;
744   }
745 
746   blocks_.SetBit(block->GetBlockId());
747   block->SetInLoop(this);
748   if (block->IsLoopHeader()) {
749     // We're visiting loops in post-order, so inner loops must have been
750     // populated already.
751     DCHECK(block->GetLoopInformation()->IsPopulated());
752     if (block->GetLoopInformation()->IsIrreducible()) {
753       contains_irreducible_loop_ = true;
754     }
755   }
756   for (HBasicBlock* predecessor : block->GetPredecessors()) {
757     PopulateRecursive(predecessor);
758   }
759 }
760 
PopulateIrreducibleRecursive(HBasicBlock * block,ArenaBitVector * finalized)761 void HLoopInformation::PopulateIrreducibleRecursive(HBasicBlock* block, ArenaBitVector* finalized) {
762   size_t block_id = block->GetBlockId();
763 
764   // If `block` is in `finalized`, we know its membership in the loop has been
765   // decided and it does not need to be revisited.
766   if (finalized->IsBitSet(block_id)) {
767     return;
768   }
769 
770   bool is_finalized = false;
771   if (block->IsLoopHeader()) {
772     // If we hit a loop header in an irreducible loop, we first check if the
773     // pre header of that loop belongs to the currently analyzed loop. If it does,
774     // then we visit the back edges.
775     // Note that we cannot use GetPreHeader, as the loop may have not been populated
776     // yet.
777     HBasicBlock* pre_header = block->GetPredecessors()[0];
778     PopulateIrreducibleRecursive(pre_header, finalized);
779     if (blocks_.IsBitSet(pre_header->GetBlockId())) {
780       block->SetInLoop(this);
781       blocks_.SetBit(block_id);
782       finalized->SetBit(block_id);
783       is_finalized = true;
784 
785       HLoopInformation* info = block->GetLoopInformation();
786       for (HBasicBlock* back_edge : info->GetBackEdges()) {
787         PopulateIrreducibleRecursive(back_edge, finalized);
788       }
789     }
790   } else {
791     // Visit all predecessors. If one predecessor is part of the loop, this
792     // block is also part of this loop.
793     for (HBasicBlock* predecessor : block->GetPredecessors()) {
794       PopulateIrreducibleRecursive(predecessor, finalized);
795       if (!is_finalized && blocks_.IsBitSet(predecessor->GetBlockId())) {
796         block->SetInLoop(this);
797         blocks_.SetBit(block_id);
798         finalized->SetBit(block_id);
799         is_finalized = true;
800       }
801     }
802   }
803 
804   // All predecessors have been recursively visited. Mark finalized if not marked yet.
805   if (!is_finalized) {
806     finalized->SetBit(block_id);
807   }
808 }
809 
Populate()810 void HLoopInformation::Populate() {
811   DCHECK_EQ(blocks_.NumSetBits(), 0u) << "Loop information has already been populated";
812   // Populate this loop: starting with the back edge, recursively add predecessors
813   // that are not already part of that loop. Set the header as part of the loop
814   // to end the recursion.
815   // This is a recursive implementation of the algorithm described in
816   // "Advanced Compiler Design & Implementation" (Muchnick) p192.
817   HGraph* graph = header_->GetGraph();
818   blocks_.SetBit(header_->GetBlockId());
819   header_->SetInLoop(this);
820 
821   bool is_irreducible_loop = HasBackEdgeNotDominatedByHeader();
822 
823   if (is_irreducible_loop) {
824     // Allocate memory from local ScopedArenaAllocator.
825     ScopedArenaAllocator allocator(graph->GetArenaStack());
826     ArenaBitVector visited(&allocator,
827                            graph->GetBlocks().size(),
828                            /* expandable */ false,
829                            kArenaAllocGraphBuilder);
830     visited.ClearAllBits();
831     // Stop marking blocks at the loop header.
832     visited.SetBit(header_->GetBlockId());
833 
834     for (HBasicBlock* back_edge : GetBackEdges()) {
835       PopulateIrreducibleRecursive(back_edge, &visited);
836     }
837   } else {
838     for (HBasicBlock* back_edge : GetBackEdges()) {
839       PopulateRecursive(back_edge);
840     }
841   }
842 
843   if (!is_irreducible_loop && graph->IsCompilingOsr()) {
844     // When compiling in OSR mode, all loops in the compiled method may be entered
845     // from the interpreter. We treat this OSR entry point just like an extra entry
846     // to an irreducible loop, so we need to mark the method's loops as irreducible.
847     // This does not apply to inlined loops which do not act as OSR entry points.
848     if (suspend_check_ == nullptr) {
849       // Just building the graph in OSR mode, this loop is not inlined. We never build an
850       // inner graph in OSR mode as we can do OSR transition only from the outer method.
851       is_irreducible_loop = true;
852     } else {
853       // Look at the suspend check's environment to determine if the loop was inlined.
854       DCHECK(suspend_check_->HasEnvironment());
855       if (!suspend_check_->GetEnvironment()->IsFromInlinedInvoke()) {
856         is_irreducible_loop = true;
857       }
858     }
859   }
860   if (is_irreducible_loop) {
861     irreducible_ = true;
862     contains_irreducible_loop_ = true;
863     graph->SetHasIrreducibleLoops(true);
864   }
865   graph->SetHasLoops(true);
866 }
867 
PopulateInnerLoopUpwards(HLoopInformation * inner_loop)868 void HLoopInformation::PopulateInnerLoopUpwards(HLoopInformation* inner_loop) {
869   DCHECK(inner_loop->GetPreHeader()->GetLoopInformation() == this);
870   blocks_.Union(&inner_loop->blocks_);
871   HLoopInformation* outer_loop = GetPreHeader()->GetLoopInformation();
872   if (outer_loop != nullptr) {
873     outer_loop->PopulateInnerLoopUpwards(this);
874   }
875 }
876 
GetPreHeader() const877 HBasicBlock* HLoopInformation::GetPreHeader() const {
878   HBasicBlock* block = header_->GetPredecessors()[0];
879   DCHECK(irreducible_ || (block == header_->GetDominator()));
880   return block;
881 }
882 
Contains(const HBasicBlock & block) const883 bool HLoopInformation::Contains(const HBasicBlock& block) const {
884   return blocks_.IsBitSet(block.GetBlockId());
885 }
886 
IsIn(const HLoopInformation & other) const887 bool HLoopInformation::IsIn(const HLoopInformation& other) const {
888   return other.blocks_.IsBitSet(header_->GetBlockId());
889 }
890 
IsDefinedOutOfTheLoop(HInstruction * instruction) const891 bool HLoopInformation::IsDefinedOutOfTheLoop(HInstruction* instruction) const {
892   return !blocks_.IsBitSet(instruction->GetBlock()->GetBlockId());
893 }
894 
GetLifetimeEnd() const895 size_t HLoopInformation::GetLifetimeEnd() const {
896   size_t last_position = 0;
897   for (HBasicBlock* back_edge : GetBackEdges()) {
898     last_position = std::max(back_edge->GetLifetimeEnd(), last_position);
899   }
900   return last_position;
901 }
902 
HasBackEdgeNotDominatedByHeader() const903 bool HLoopInformation::HasBackEdgeNotDominatedByHeader() const {
904   for (HBasicBlock* back_edge : GetBackEdges()) {
905     DCHECK(back_edge->GetDominator() != nullptr);
906     if (!header_->Dominates(back_edge)) {
907       return true;
908     }
909   }
910   return false;
911 }
912 
DominatesAllBackEdges(HBasicBlock * block)913 bool HLoopInformation::DominatesAllBackEdges(HBasicBlock* block) {
914   for (HBasicBlock* back_edge : GetBackEdges()) {
915     if (!block->Dominates(back_edge)) {
916       return false;
917     }
918   }
919   return true;
920 }
921 
922 
HasExitEdge() const923 bool HLoopInformation::HasExitEdge() const {
924   // Determine if this loop has at least one exit edge.
925   HBlocksInLoopReversePostOrderIterator it_loop(*this);
926   for (; !it_loop.Done(); it_loop.Advance()) {
927     for (HBasicBlock* successor : it_loop.Current()->GetSuccessors()) {
928       if (!Contains(*successor)) {
929         return true;
930       }
931     }
932   }
933   return false;
934 }
935 
Dominates(HBasicBlock * other) const936 bool HBasicBlock::Dominates(HBasicBlock* other) const {
937   // Walk up the dominator tree from `other`, to find out if `this`
938   // is an ancestor.
939   HBasicBlock* current = other;
940   while (current != nullptr) {
941     if (current == this) {
942       return true;
943     }
944     current = current->GetDominator();
945   }
946   return false;
947 }
948 
UpdateInputsUsers(HInstruction * instruction)949 static void UpdateInputsUsers(HInstruction* instruction) {
950   HInputsRef inputs = instruction->GetInputs();
951   for (size_t i = 0; i < inputs.size(); ++i) {
952     inputs[i]->AddUseAt(instruction, i);
953   }
954   // Environment should be created later.
955   DCHECK(!instruction->HasEnvironment());
956 }
957 
ReplaceAndRemovePhiWith(HPhi * initial,HPhi * replacement)958 void HBasicBlock::ReplaceAndRemovePhiWith(HPhi* initial, HPhi* replacement) {
959   DCHECK(initial->GetBlock() == this);
960   InsertPhiAfter(replacement, initial);
961   initial->ReplaceWith(replacement);
962   RemovePhi(initial);
963 }
964 
ReplaceAndRemoveInstructionWith(HInstruction * initial,HInstruction * replacement)965 void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
966                                                   HInstruction* replacement) {
967   DCHECK(initial->GetBlock() == this);
968   if (initial->IsControlFlow()) {
969     // We can only replace a control flow instruction with another control flow instruction.
970     DCHECK(replacement->IsControlFlow());
971     DCHECK_EQ(replacement->GetId(), -1);
972     DCHECK_EQ(replacement->GetType(), DataType::Type::kVoid);
973     DCHECK_EQ(initial->GetBlock(), this);
974     DCHECK_EQ(initial->GetType(), DataType::Type::kVoid);
975     DCHECK(initial->GetUses().empty());
976     DCHECK(initial->GetEnvUses().empty());
977     replacement->SetBlock(this);
978     replacement->SetId(GetGraph()->GetNextInstructionId());
979     instructions_.InsertInstructionBefore(replacement, initial);
980     UpdateInputsUsers(replacement);
981   } else {
982     InsertInstructionBefore(replacement, initial);
983     initial->ReplaceWith(replacement);
984   }
985   RemoveInstruction(initial);
986 }
987 
Add(HInstructionList * instruction_list,HBasicBlock * block,HInstruction * instruction)988 static void Add(HInstructionList* instruction_list,
989                 HBasicBlock* block,
990                 HInstruction* instruction) {
991   DCHECK(instruction->GetBlock() == nullptr);
992   DCHECK_EQ(instruction->GetId(), -1);
993   instruction->SetBlock(block);
994   instruction->SetId(block->GetGraph()->GetNextInstructionId());
995   UpdateInputsUsers(instruction);
996   instruction_list->AddInstruction(instruction);
997 }
998 
AddInstruction(HInstruction * instruction)999 void HBasicBlock::AddInstruction(HInstruction* instruction) {
1000   Add(&instructions_, this, instruction);
1001 }
1002 
AddPhi(HPhi * phi)1003 void HBasicBlock::AddPhi(HPhi* phi) {
1004   Add(&phis_, this, phi);
1005 }
1006 
InsertInstructionBefore(HInstruction * instruction,HInstruction * cursor)1007 void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
1008   DCHECK(!cursor->IsPhi());
1009   DCHECK(!instruction->IsPhi());
1010   DCHECK_EQ(instruction->GetId(), -1);
1011   DCHECK_NE(cursor->GetId(), -1);
1012   DCHECK_EQ(cursor->GetBlock(), this);
1013   DCHECK(!instruction->IsControlFlow());
1014   instruction->SetBlock(this);
1015   instruction->SetId(GetGraph()->GetNextInstructionId());
1016   UpdateInputsUsers(instruction);
1017   instructions_.InsertInstructionBefore(instruction, cursor);
1018 }
1019 
InsertInstructionAfter(HInstruction * instruction,HInstruction * cursor)1020 void HBasicBlock::InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor) {
1021   DCHECK(!cursor->IsPhi());
1022   DCHECK(!instruction->IsPhi());
1023   DCHECK_EQ(instruction->GetId(), -1);
1024   DCHECK_NE(cursor->GetId(), -1);
1025   DCHECK_EQ(cursor->GetBlock(), this);
1026   DCHECK(!instruction->IsControlFlow());
1027   DCHECK(!cursor->IsControlFlow());
1028   instruction->SetBlock(this);
1029   instruction->SetId(GetGraph()->GetNextInstructionId());
1030   UpdateInputsUsers(instruction);
1031   instructions_.InsertInstructionAfter(instruction, cursor);
1032 }
1033 
InsertPhiAfter(HPhi * phi,HPhi * cursor)1034 void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
1035   DCHECK_EQ(phi->GetId(), -1);
1036   DCHECK_NE(cursor->GetId(), -1);
1037   DCHECK_EQ(cursor->GetBlock(), this);
1038   phi->SetBlock(this);
1039   phi->SetId(GetGraph()->GetNextInstructionId());
1040   UpdateInputsUsers(phi);
1041   phis_.InsertInstructionAfter(phi, cursor);
1042 }
1043 
Remove(HInstructionList * instruction_list,HBasicBlock * block,HInstruction * instruction,bool ensure_safety)1044 static void Remove(HInstructionList* instruction_list,
1045                    HBasicBlock* block,
1046                    HInstruction* instruction,
1047                    bool ensure_safety) {
1048   DCHECK_EQ(block, instruction->GetBlock());
1049   instruction->SetBlock(nullptr);
1050   instruction_list->RemoveInstruction(instruction);
1051   if (ensure_safety) {
1052     DCHECK(instruction->GetUses().empty());
1053     DCHECK(instruction->GetEnvUses().empty());
1054     RemoveAsUser(instruction);
1055   }
1056 }
1057 
RemoveInstruction(HInstruction * instruction,bool ensure_safety)1058 void HBasicBlock::RemoveInstruction(HInstruction* instruction, bool ensure_safety) {
1059   DCHECK(!instruction->IsPhi());
1060   Remove(&instructions_, this, instruction, ensure_safety);
1061 }
1062 
RemovePhi(HPhi * phi,bool ensure_safety)1063 void HBasicBlock::RemovePhi(HPhi* phi, bool ensure_safety) {
1064   Remove(&phis_, this, phi, ensure_safety);
1065 }
1066 
RemoveInstructionOrPhi(HInstruction * instruction,bool ensure_safety)1067 void HBasicBlock::RemoveInstructionOrPhi(HInstruction* instruction, bool ensure_safety) {
1068   if (instruction->IsPhi()) {
1069     RemovePhi(instruction->AsPhi(), ensure_safety);
1070   } else {
1071     RemoveInstruction(instruction, ensure_safety);
1072   }
1073 }
1074 
CopyFrom(ArrayRef<HInstruction * const> locals)1075 void HEnvironment::CopyFrom(ArrayRef<HInstruction* const> locals) {
1076   for (size_t i = 0; i < locals.size(); i++) {
1077     HInstruction* instruction = locals[i];
1078     SetRawEnvAt(i, instruction);
1079     if (instruction != nullptr) {
1080       instruction->AddEnvUseAt(this, i);
1081     }
1082   }
1083 }
1084 
CopyFrom(HEnvironment * env)1085 void HEnvironment::CopyFrom(HEnvironment* env) {
1086   for (size_t i = 0; i < env->Size(); i++) {
1087     HInstruction* instruction = env->GetInstructionAt(i);
1088     SetRawEnvAt(i, instruction);
1089     if (instruction != nullptr) {
1090       instruction->AddEnvUseAt(this, i);
1091     }
1092   }
1093 }
1094 
CopyFromWithLoopPhiAdjustment(HEnvironment * env,HBasicBlock * loop_header)1095 void HEnvironment::CopyFromWithLoopPhiAdjustment(HEnvironment* env,
1096                                                  HBasicBlock* loop_header) {
1097   DCHECK(loop_header->IsLoopHeader());
1098   for (size_t i = 0; i < env->Size(); i++) {
1099     HInstruction* instruction = env->GetInstructionAt(i);
1100     SetRawEnvAt(i, instruction);
1101     if (instruction == nullptr) {
1102       continue;
1103     }
1104     if (instruction->IsLoopHeaderPhi() && (instruction->GetBlock() == loop_header)) {
1105       // At the end of the loop pre-header, the corresponding value for instruction
1106       // is the first input of the phi.
1107       HInstruction* initial = instruction->AsPhi()->InputAt(0);
1108       SetRawEnvAt(i, initial);
1109       initial->AddEnvUseAt(this, i);
1110     } else {
1111       instruction->AddEnvUseAt(this, i);
1112     }
1113   }
1114 }
1115 
RemoveAsUserOfInput(size_t index) const1116 void HEnvironment::RemoveAsUserOfInput(size_t index) const {
1117   const HUserRecord<HEnvironment*>& env_use = vregs_[index];
1118   HInstruction* user = env_use.GetInstruction();
1119   auto before_env_use_node = env_use.GetBeforeUseNode();
1120   user->env_uses_.erase_after(before_env_use_node);
1121   user->FixUpUserRecordsAfterEnvUseRemoval(before_env_use_node);
1122 }
1123 
GetNextDisregardingMoves() const1124 HInstruction* HInstruction::GetNextDisregardingMoves() const {
1125   HInstruction* next = GetNext();
1126   while (next != nullptr && next->IsParallelMove()) {
1127     next = next->GetNext();
1128   }
1129   return next;
1130 }
1131 
GetPreviousDisregardingMoves() const1132 HInstruction* HInstruction::GetPreviousDisregardingMoves() const {
1133   HInstruction* previous = GetPrevious();
1134   while (previous != nullptr && previous->IsParallelMove()) {
1135     previous = previous->GetPrevious();
1136   }
1137   return previous;
1138 }
1139 
AddInstruction(HInstruction * instruction)1140 void HInstructionList::AddInstruction(HInstruction* instruction) {
1141   if (first_instruction_ == nullptr) {
1142     DCHECK(last_instruction_ == nullptr);
1143     first_instruction_ = last_instruction_ = instruction;
1144   } else {
1145     DCHECK(last_instruction_ != nullptr);
1146     last_instruction_->next_ = instruction;
1147     instruction->previous_ = last_instruction_;
1148     last_instruction_ = instruction;
1149   }
1150 }
1151 
InsertInstructionBefore(HInstruction * instruction,HInstruction * cursor)1152 void HInstructionList::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
1153   DCHECK(Contains(cursor));
1154   if (cursor == first_instruction_) {
1155     cursor->previous_ = instruction;
1156     instruction->next_ = cursor;
1157     first_instruction_ = instruction;
1158   } else {
1159     instruction->previous_ = cursor->previous_;
1160     instruction->next_ = cursor;
1161     cursor->previous_ = instruction;
1162     instruction->previous_->next_ = instruction;
1163   }
1164 }
1165 
InsertInstructionAfter(HInstruction * instruction,HInstruction * cursor)1166 void HInstructionList::InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor) {
1167   DCHECK(Contains(cursor));
1168   if (cursor == last_instruction_) {
1169     cursor->next_ = instruction;
1170     instruction->previous_ = cursor;
1171     last_instruction_ = instruction;
1172   } else {
1173     instruction->next_ = cursor->next_;
1174     instruction->previous_ = cursor;
1175     cursor->next_ = instruction;
1176     instruction->next_->previous_ = instruction;
1177   }
1178 }
1179 
RemoveInstruction(HInstruction * instruction)1180 void HInstructionList::RemoveInstruction(HInstruction* instruction) {
1181   if (instruction->previous_ != nullptr) {
1182     instruction->previous_->next_ = instruction->next_;
1183   }
1184   if (instruction->next_ != nullptr) {
1185     instruction->next_->previous_ = instruction->previous_;
1186   }
1187   if (instruction == first_instruction_) {
1188     first_instruction_ = instruction->next_;
1189   }
1190   if (instruction == last_instruction_) {
1191     last_instruction_ = instruction->previous_;
1192   }
1193 }
1194 
Contains(HInstruction * instruction) const1195 bool HInstructionList::Contains(HInstruction* instruction) const {
1196   for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
1197     if (it.Current() == instruction) {
1198       return true;
1199     }
1200   }
1201   return false;
1202 }
1203 
FoundBefore(const HInstruction * instruction1,const HInstruction * instruction2) const1204 bool HInstructionList::FoundBefore(const HInstruction* instruction1,
1205                                    const HInstruction* instruction2) const {
1206   DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
1207   for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
1208     if (it.Current() == instruction1) {
1209       return true;
1210     }
1211     if (it.Current() == instruction2) {
1212       return false;
1213     }
1214   }
1215   LOG(FATAL) << "Did not find an order between two instructions of the same block.";
1216   return true;
1217 }
1218 
StrictlyDominates(HInstruction * other_instruction) const1219 bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
1220   if (other_instruction == this) {
1221     // An instruction does not strictly dominate itself.
1222     return false;
1223   }
1224   HBasicBlock* block = GetBlock();
1225   HBasicBlock* other_block = other_instruction->GetBlock();
1226   if (block != other_block) {
1227     return GetBlock()->Dominates(other_instruction->GetBlock());
1228   } else {
1229     // If both instructions are in the same block, ensure this
1230     // instruction comes before `other_instruction`.
1231     if (IsPhi()) {
1232       if (!other_instruction->IsPhi()) {
1233         // Phis appear before non phi-instructions so this instruction
1234         // dominates `other_instruction`.
1235         return true;
1236       } else {
1237         // There is no order among phis.
1238         LOG(FATAL) << "There is no dominance between phis of a same block.";
1239         return false;
1240       }
1241     } else {
1242       // `this` is not a phi.
1243       if (other_instruction->IsPhi()) {
1244         // Phis appear before non phi-instructions so this instruction
1245         // does not dominate `other_instruction`.
1246         return false;
1247       } else {
1248         // Check whether this instruction comes before
1249         // `other_instruction` in the instruction list.
1250         return block->GetInstructions().FoundBefore(this, other_instruction);
1251       }
1252     }
1253   }
1254 }
1255 
RemoveEnvironment()1256 void HInstruction::RemoveEnvironment() {
1257   RemoveEnvironmentUses(this);
1258   environment_ = nullptr;
1259 }
1260 
ReplaceWith(HInstruction * other)1261 void HInstruction::ReplaceWith(HInstruction* other) {
1262   DCHECK(other != nullptr);
1263   // Note: fixup_end remains valid across splice_after().
1264   auto fixup_end = other->uses_.empty() ? other->uses_.begin() : ++other->uses_.begin();
1265   other->uses_.splice_after(other->uses_.before_begin(), uses_);
1266   other->FixUpUserRecordsAfterUseInsertion(fixup_end);
1267 
1268   // Note: env_fixup_end remains valid across splice_after().
1269   auto env_fixup_end =
1270       other->env_uses_.empty() ? other->env_uses_.begin() : ++other->env_uses_.begin();
1271   other->env_uses_.splice_after(other->env_uses_.before_begin(), env_uses_);
1272   other->FixUpUserRecordsAfterEnvUseInsertion(env_fixup_end);
1273 
1274   DCHECK(uses_.empty());
1275   DCHECK(env_uses_.empty());
1276 }
1277 
ReplaceUsesDominatedBy(HInstruction * dominator,HInstruction * replacement)1278 void HInstruction::ReplaceUsesDominatedBy(HInstruction* dominator, HInstruction* replacement) {
1279   const HUseList<HInstruction*>& uses = GetUses();
1280   for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
1281     HInstruction* user = it->GetUser();
1282     size_t index = it->GetIndex();
1283     // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
1284     ++it;
1285     if (dominator->StrictlyDominates(user)) {
1286       user->ReplaceInput(replacement, index);
1287     }
1288   }
1289 }
1290 
ReplaceInput(HInstruction * replacement,size_t index)1291 void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
1292   HUserRecord<HInstruction*> input_use = InputRecordAt(index);
1293   if (input_use.GetInstruction() == replacement) {
1294     // Nothing to do.
1295     return;
1296   }
1297   HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode();
1298   // Note: fixup_end remains valid across splice_after().
1299   auto fixup_end =
1300       replacement->uses_.empty() ? replacement->uses_.begin() : ++replacement->uses_.begin();
1301   replacement->uses_.splice_after(replacement->uses_.before_begin(),
1302                                   input_use.GetInstruction()->uses_,
1303                                   before_use_node);
1304   replacement->FixUpUserRecordsAfterUseInsertion(fixup_end);
1305   input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node);
1306 }
1307 
EnvironmentSize() const1308 size_t HInstruction::EnvironmentSize() const {
1309   return HasEnvironment() ? environment_->Size() : 0;
1310 }
1311 
AddInput(HInstruction * input)1312 void HVariableInputSizeInstruction::AddInput(HInstruction* input) {
1313   DCHECK(input->GetBlock() != nullptr);
1314   inputs_.push_back(HUserRecord<HInstruction*>(input));
1315   input->AddUseAt(this, inputs_.size() - 1);
1316 }
1317 
InsertInputAt(size_t index,HInstruction * input)1318 void HVariableInputSizeInstruction::InsertInputAt(size_t index, HInstruction* input) {
1319   inputs_.insert(inputs_.begin() + index, HUserRecord<HInstruction*>(input));
1320   input->AddUseAt(this, index);
1321   // Update indexes in use nodes of inputs that have been pushed further back by the insert().
1322   for (size_t i = index + 1u, e = inputs_.size(); i < e; ++i) {
1323     DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i - 1u);
1324     inputs_[i].GetUseNode()->SetIndex(i);
1325   }
1326 }
1327 
RemoveInputAt(size_t index)1328 void HVariableInputSizeInstruction::RemoveInputAt(size_t index) {
1329   RemoveAsUserOfInput(index);
1330   inputs_.erase(inputs_.begin() + index);
1331   // Update indexes in use nodes of inputs that have been pulled forward by the erase().
1332   for (size_t i = index, e = inputs_.size(); i < e; ++i) {
1333     DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i + 1u);
1334     inputs_[i].GetUseNode()->SetIndex(i);
1335   }
1336 }
1337 
RemoveAllInputs()1338 void HVariableInputSizeInstruction::RemoveAllInputs() {
1339   RemoveAsUserOfAllInputs();
1340   DCHECK(!HasNonEnvironmentUses());
1341 
1342   inputs_.clear();
1343   DCHECK_EQ(0u, InputCount());
1344 }
1345 
RemoveConstructorFences(HInstruction * instruction)1346 size_t HConstructorFence::RemoveConstructorFences(HInstruction* instruction) {
1347   DCHECK(instruction->GetBlock() != nullptr);
1348   // Removing constructor fences only makes sense for instructions with an object return type.
1349   DCHECK_EQ(DataType::Type::kReference, instruction->GetType());
1350 
1351   // Return how many instructions were removed for statistic purposes.
1352   size_t remove_count = 0;
1353 
1354   // Efficient implementation that simultaneously (in one pass):
1355   // * Scans the uses list for all constructor fences.
1356   // * Deletes that constructor fence from the uses list of `instruction`.
1357   // * Deletes `instruction` from the constructor fence's inputs.
1358   // * Deletes the constructor fence if it now has 0 inputs.
1359 
1360   const HUseList<HInstruction*>& uses = instruction->GetUses();
1361   // Warning: Although this is "const", we might mutate the list when calling RemoveInputAt.
1362   for (auto it = uses.begin(), end = uses.end(); it != end; ) {
1363     const HUseListNode<HInstruction*>& use_node = *it;
1364     HInstruction* const use_instruction = use_node.GetUser();
1365 
1366     // Advance the iterator immediately once we fetch the use_node.
1367     // Warning: If the input is removed, the current iterator becomes invalid.
1368     ++it;
1369 
1370     if (use_instruction->IsConstructorFence()) {
1371       HConstructorFence* ctor_fence = use_instruction->AsConstructorFence();
1372       size_t input_index = use_node.GetIndex();
1373 
1374       // Process the candidate instruction for removal
1375       // from the graph.
1376 
1377       // Constructor fence instructions are never
1378       // used by other instructions.
1379       //
1380       // If we wanted to make this more generic, it
1381       // could be a runtime if statement.
1382       DCHECK(!ctor_fence->HasUses());
1383 
1384       // A constructor fence's return type is "kPrimVoid"
1385       // and therefore it can't have any environment uses.
1386       DCHECK(!ctor_fence->HasEnvironmentUses());
1387 
1388       // Remove the inputs first, otherwise removing the instruction
1389       // will try to remove its uses while we are already removing uses
1390       // and this operation will fail.
1391       DCHECK_EQ(instruction, ctor_fence->InputAt(input_index));
1392 
1393       // Removing the input will also remove the `use_node`.
1394       // (Do not look at `use_node` after this, it will be a dangling reference).
1395       ctor_fence->RemoveInputAt(input_index);
1396 
1397       // Once all inputs are removed, the fence is considered dead and
1398       // is removed.
1399       if (ctor_fence->InputCount() == 0u) {
1400         ctor_fence->GetBlock()->RemoveInstruction(ctor_fence);
1401         ++remove_count;
1402       }
1403     }
1404   }
1405 
1406   if (kIsDebugBuild) {
1407     // Post-condition checks:
1408     // * None of the uses of `instruction` are a constructor fence.
1409     // * The `instruction` itself did not get removed from a block.
1410     for (const HUseListNode<HInstruction*>& use_node : instruction->GetUses()) {
1411       CHECK(!use_node.GetUser()->IsConstructorFence());
1412     }
1413     CHECK(instruction->GetBlock() != nullptr);
1414   }
1415 
1416   return remove_count;
1417 }
1418 
Merge(HConstructorFence * other)1419 void HConstructorFence::Merge(HConstructorFence* other) {
1420   // Do not delete yourself from the graph.
1421   DCHECK(this != other);
1422   // Don't try to merge with an instruction not associated with a block.
1423   DCHECK(other->GetBlock() != nullptr);
1424   // A constructor fence's return type is "kPrimVoid"
1425   // and therefore it cannot have any environment uses.
1426   DCHECK(!other->HasEnvironmentUses());
1427 
1428   auto has_input = [](HInstruction* haystack, HInstruction* needle) {
1429     // Check if `haystack` has `needle` as any of its inputs.
1430     for (size_t input_count = 0; input_count < haystack->InputCount(); ++input_count) {
1431       if (haystack->InputAt(input_count) == needle) {
1432         return true;
1433       }
1434     }
1435     return false;
1436   };
1437 
1438   // Add any inputs from `other` into `this` if it wasn't already an input.
1439   for (size_t input_count = 0; input_count < other->InputCount(); ++input_count) {
1440     HInstruction* other_input = other->InputAt(input_count);
1441     if (!has_input(this, other_input)) {
1442       AddInput(other_input);
1443     }
1444   }
1445 
1446   other->GetBlock()->RemoveInstruction(other);
1447 }
1448 
GetAssociatedAllocation(bool ignore_inputs)1449 HInstruction* HConstructorFence::GetAssociatedAllocation(bool ignore_inputs) {
1450   HInstruction* new_instance_inst = GetPrevious();
1451   // Check if the immediately preceding instruction is a new-instance/new-array.
1452   // Otherwise this fence is for protecting final fields.
1453   if (new_instance_inst != nullptr &&
1454       (new_instance_inst->IsNewInstance() || new_instance_inst->IsNewArray())) {
1455     if (ignore_inputs) {
1456       // If inputs are ignored, simply check if the predecessor is
1457       // *any* HNewInstance/HNewArray.
1458       //
1459       // Inputs are normally only ignored for prepare_for_register_allocation,
1460       // at which point *any* prior HNewInstance/Array can be considered
1461       // associated.
1462       return new_instance_inst;
1463     } else {
1464       // Normal case: There must be exactly 1 input and the previous instruction
1465       // must be that input.
1466       if (InputCount() == 1u && InputAt(0) == new_instance_inst) {
1467         return new_instance_inst;
1468       }
1469     }
1470   }
1471   return nullptr;
1472 }
1473 
1474 #define DEFINE_ACCEPT(name, super)                                             \
1475 void H##name::Accept(HGraphVisitor* visitor) {                                 \
1476   visitor->Visit##name(this);                                                  \
1477 }
1478 
FOR_EACH_CONCRETE_INSTRUCTION(DEFINE_ACCEPT)1479 FOR_EACH_CONCRETE_INSTRUCTION(DEFINE_ACCEPT)
1480 
1481 #undef DEFINE_ACCEPT
1482 
1483 void HGraphVisitor::VisitInsertionOrder() {
1484   const ArenaVector<HBasicBlock*>& blocks = graph_->GetBlocks();
1485   for (HBasicBlock* block : blocks) {
1486     if (block != nullptr) {
1487       VisitBasicBlock(block);
1488     }
1489   }
1490 }
1491 
VisitReversePostOrder()1492 void HGraphVisitor::VisitReversePostOrder() {
1493   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
1494     VisitBasicBlock(block);
1495   }
1496 }
1497 
VisitBasicBlock(HBasicBlock * block)1498 void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
1499   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
1500     it.Current()->Accept(this);
1501   }
1502   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
1503     it.Current()->Accept(this);
1504   }
1505 }
1506 
TryStaticEvaluation() const1507 HConstant* HTypeConversion::TryStaticEvaluation() const {
1508   HGraph* graph = GetBlock()->GetGraph();
1509   if (GetInput()->IsIntConstant()) {
1510     int32_t value = GetInput()->AsIntConstant()->GetValue();
1511     switch (GetResultType()) {
1512       case DataType::Type::kInt8:
1513         return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc());
1514       case DataType::Type::kUint8:
1515         return graph->GetIntConstant(static_cast<uint8_t>(value), GetDexPc());
1516       case DataType::Type::kInt16:
1517         return graph->GetIntConstant(static_cast<int16_t>(value), GetDexPc());
1518       case DataType::Type::kUint16:
1519         return graph->GetIntConstant(static_cast<uint16_t>(value), GetDexPc());
1520       case DataType::Type::kInt64:
1521         return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
1522       case DataType::Type::kFloat32:
1523         return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
1524       case DataType::Type::kFloat64:
1525         return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
1526       default:
1527         return nullptr;
1528     }
1529   } else if (GetInput()->IsLongConstant()) {
1530     int64_t value = GetInput()->AsLongConstant()->GetValue();
1531     switch (GetResultType()) {
1532       case DataType::Type::kInt8:
1533         return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc());
1534       case DataType::Type::kUint8:
1535         return graph->GetIntConstant(static_cast<uint8_t>(value), GetDexPc());
1536       case DataType::Type::kInt16:
1537         return graph->GetIntConstant(static_cast<int16_t>(value), GetDexPc());
1538       case DataType::Type::kUint16:
1539         return graph->GetIntConstant(static_cast<uint16_t>(value), GetDexPc());
1540       case DataType::Type::kInt32:
1541         return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
1542       case DataType::Type::kFloat32:
1543         return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
1544       case DataType::Type::kFloat64:
1545         return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
1546       default:
1547         return nullptr;
1548     }
1549   } else if (GetInput()->IsFloatConstant()) {
1550     float value = GetInput()->AsFloatConstant()->GetValue();
1551     switch (GetResultType()) {
1552       case DataType::Type::kInt32:
1553         if (std::isnan(value))
1554           return graph->GetIntConstant(0, GetDexPc());
1555         if (value >= kPrimIntMax)
1556           return graph->GetIntConstant(kPrimIntMax, GetDexPc());
1557         if (value <= kPrimIntMin)
1558           return graph->GetIntConstant(kPrimIntMin, GetDexPc());
1559         return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
1560       case DataType::Type::kInt64:
1561         if (std::isnan(value))
1562           return graph->GetLongConstant(0, GetDexPc());
1563         if (value >= kPrimLongMax)
1564           return graph->GetLongConstant(kPrimLongMax, GetDexPc());
1565         if (value <= kPrimLongMin)
1566           return graph->GetLongConstant(kPrimLongMin, GetDexPc());
1567         return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
1568       case DataType::Type::kFloat64:
1569         return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
1570       default:
1571         return nullptr;
1572     }
1573   } else if (GetInput()->IsDoubleConstant()) {
1574     double value = GetInput()->AsDoubleConstant()->GetValue();
1575     switch (GetResultType()) {
1576       case DataType::Type::kInt32:
1577         if (std::isnan(value))
1578           return graph->GetIntConstant(0, GetDexPc());
1579         if (value >= kPrimIntMax)
1580           return graph->GetIntConstant(kPrimIntMax, GetDexPc());
1581         if (value <= kPrimLongMin)
1582           return graph->GetIntConstant(kPrimIntMin, GetDexPc());
1583         return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
1584       case DataType::Type::kInt64:
1585         if (std::isnan(value))
1586           return graph->GetLongConstant(0, GetDexPc());
1587         if (value >= kPrimLongMax)
1588           return graph->GetLongConstant(kPrimLongMax, GetDexPc());
1589         if (value <= kPrimLongMin)
1590           return graph->GetLongConstant(kPrimLongMin, GetDexPc());
1591         return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
1592       case DataType::Type::kFloat32:
1593         return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
1594       default:
1595         return nullptr;
1596     }
1597   }
1598   return nullptr;
1599 }
1600 
TryStaticEvaluation() const1601 HConstant* HUnaryOperation::TryStaticEvaluation() const {
1602   if (GetInput()->IsIntConstant()) {
1603     return Evaluate(GetInput()->AsIntConstant());
1604   } else if (GetInput()->IsLongConstant()) {
1605     return Evaluate(GetInput()->AsLongConstant());
1606   } else if (kEnableFloatingPointStaticEvaluation) {
1607     if (GetInput()->IsFloatConstant()) {
1608       return Evaluate(GetInput()->AsFloatConstant());
1609     } else if (GetInput()->IsDoubleConstant()) {
1610       return Evaluate(GetInput()->AsDoubleConstant());
1611     }
1612   }
1613   return nullptr;
1614 }
1615 
TryStaticEvaluation() const1616 HConstant* HBinaryOperation::TryStaticEvaluation() const {
1617   if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
1618     return Evaluate(GetLeft()->AsIntConstant(), GetRight()->AsIntConstant());
1619   } else if (GetLeft()->IsLongConstant()) {
1620     if (GetRight()->IsIntConstant()) {
1621       // The binop(long, int) case is only valid for shifts and rotations.
1622       DCHECK(IsShl() || IsShr() || IsUShr() || IsRor()) << DebugName();
1623       return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsIntConstant());
1624     } else if (GetRight()->IsLongConstant()) {
1625       return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsLongConstant());
1626     }
1627   } else if (GetLeft()->IsNullConstant() && GetRight()->IsNullConstant()) {
1628     // The binop(null, null) case is only valid for equal and not-equal conditions.
1629     DCHECK(IsEqual() || IsNotEqual()) << DebugName();
1630     return Evaluate(GetLeft()->AsNullConstant(), GetRight()->AsNullConstant());
1631   } else if (kEnableFloatingPointStaticEvaluation) {
1632     if (GetLeft()->IsFloatConstant() && GetRight()->IsFloatConstant()) {
1633       return Evaluate(GetLeft()->AsFloatConstant(), GetRight()->AsFloatConstant());
1634     } else if (GetLeft()->IsDoubleConstant() && GetRight()->IsDoubleConstant()) {
1635       return Evaluate(GetLeft()->AsDoubleConstant(), GetRight()->AsDoubleConstant());
1636     }
1637   }
1638   return nullptr;
1639 }
1640 
GetConstantRight() const1641 HConstant* HBinaryOperation::GetConstantRight() const {
1642   if (GetRight()->IsConstant()) {
1643     return GetRight()->AsConstant();
1644   } else if (IsCommutative() && GetLeft()->IsConstant()) {
1645     return GetLeft()->AsConstant();
1646   } else {
1647     return nullptr;
1648   }
1649 }
1650 
1651 // If `GetConstantRight()` returns one of the input, this returns the other
1652 // one. Otherwise it returns null.
GetLeastConstantLeft() const1653 HInstruction* HBinaryOperation::GetLeastConstantLeft() const {
1654   HInstruction* most_constant_right = GetConstantRight();
1655   if (most_constant_right == nullptr) {
1656     return nullptr;
1657   } else if (most_constant_right == GetLeft()) {
1658     return GetRight();
1659   } else {
1660     return GetLeft();
1661   }
1662 }
1663 
operator <<(std::ostream & os,const ComparisonBias & rhs)1664 std::ostream& operator<<(std::ostream& os, const ComparisonBias& rhs) {
1665   switch (rhs) {
1666     case ComparisonBias::kNoBias:
1667       return os << "no_bias";
1668     case ComparisonBias::kGtBias:
1669       return os << "gt_bias";
1670     case ComparisonBias::kLtBias:
1671       return os << "lt_bias";
1672     default:
1673       LOG(FATAL) << "Unknown ComparisonBias: " << static_cast<int>(rhs);
1674       UNREACHABLE();
1675   }
1676 }
1677 
IsBeforeWhenDisregardMoves(HInstruction * instruction) const1678 bool HCondition::IsBeforeWhenDisregardMoves(HInstruction* instruction) const {
1679   return this == instruction->GetPreviousDisregardingMoves();
1680 }
1681 
Equals(const HInstruction * other) const1682 bool HInstruction::Equals(const HInstruction* other) const {
1683   if (!InstructionTypeEquals(other)) return false;
1684   DCHECK_EQ(GetKind(), other->GetKind());
1685   if (!InstructionDataEquals(other)) return false;
1686   if (GetType() != other->GetType()) return false;
1687   HConstInputsRef inputs = GetInputs();
1688   HConstInputsRef other_inputs = other->GetInputs();
1689   if (inputs.size() != other_inputs.size()) return false;
1690   for (size_t i = 0; i != inputs.size(); ++i) {
1691     if (inputs[i] != other_inputs[i]) return false;
1692   }
1693 
1694   DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
1695   return true;
1696 }
1697 
operator <<(std::ostream & os,const HInstruction::InstructionKind & rhs)1698 std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs) {
1699 #define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
1700   switch (rhs) {
1701     FOR_EACH_INSTRUCTION(DECLARE_CASE)
1702     default:
1703       os << "Unknown instruction kind " << static_cast<int>(rhs);
1704       break;
1705   }
1706 #undef DECLARE_CASE
1707   return os;
1708 }
1709 
MoveBefore(HInstruction * cursor,bool do_checks)1710 void HInstruction::MoveBefore(HInstruction* cursor, bool do_checks) {
1711   if (do_checks) {
1712     DCHECK(!IsPhi());
1713     DCHECK(!IsControlFlow());
1714     DCHECK(CanBeMoved() ||
1715            // HShouldDeoptimizeFlag can only be moved by CHAGuardOptimization.
1716            IsShouldDeoptimizeFlag());
1717     DCHECK(!cursor->IsPhi());
1718   }
1719 
1720   next_->previous_ = previous_;
1721   if (previous_ != nullptr) {
1722     previous_->next_ = next_;
1723   }
1724   if (block_->instructions_.first_instruction_ == this) {
1725     block_->instructions_.first_instruction_ = next_;
1726   }
1727   DCHECK_NE(block_->instructions_.last_instruction_, this);
1728 
1729   previous_ = cursor->previous_;
1730   if (previous_ != nullptr) {
1731     previous_->next_ = this;
1732   }
1733   next_ = cursor;
1734   cursor->previous_ = this;
1735   block_ = cursor->block_;
1736 
1737   if (block_->instructions_.first_instruction_ == cursor) {
1738     block_->instructions_.first_instruction_ = this;
1739   }
1740 }
1741 
MoveBeforeFirstUserAndOutOfLoops()1742 void HInstruction::MoveBeforeFirstUserAndOutOfLoops() {
1743   DCHECK(!CanThrow());
1744   DCHECK(!HasSideEffects());
1745   DCHECK(!HasEnvironmentUses());
1746   DCHECK(HasNonEnvironmentUses());
1747   DCHECK(!IsPhi());  // Makes no sense for Phi.
1748   DCHECK_EQ(InputCount(), 0u);
1749 
1750   // Find the target block.
1751   auto uses_it = GetUses().begin();
1752   auto uses_end = GetUses().end();
1753   HBasicBlock* target_block = uses_it->GetUser()->GetBlock();
1754   ++uses_it;
1755   while (uses_it != uses_end && uses_it->GetUser()->GetBlock() == target_block) {
1756     ++uses_it;
1757   }
1758   if (uses_it != uses_end) {
1759     // This instruction has uses in two or more blocks. Find the common dominator.
1760     CommonDominator finder(target_block);
1761     for (; uses_it != uses_end; ++uses_it) {
1762       finder.Update(uses_it->GetUser()->GetBlock());
1763     }
1764     target_block = finder.Get();
1765     DCHECK(target_block != nullptr);
1766   }
1767   // Move to the first dominator not in a loop.
1768   while (target_block->IsInLoop()) {
1769     target_block = target_block->GetDominator();
1770     DCHECK(target_block != nullptr);
1771   }
1772 
1773   // Find insertion position.
1774   HInstruction* insert_pos = nullptr;
1775   for (const HUseListNode<HInstruction*>& use : GetUses()) {
1776     if (use.GetUser()->GetBlock() == target_block &&
1777         (insert_pos == nullptr || use.GetUser()->StrictlyDominates(insert_pos))) {
1778       insert_pos = use.GetUser();
1779     }
1780   }
1781   if (insert_pos == nullptr) {
1782     // No user in `target_block`, insert before the control flow instruction.
1783     insert_pos = target_block->GetLastInstruction();
1784     DCHECK(insert_pos->IsControlFlow());
1785     // Avoid splitting HCondition from HIf to prevent unnecessary materialization.
1786     if (insert_pos->IsIf()) {
1787       HInstruction* if_input = insert_pos->AsIf()->InputAt(0);
1788       if (if_input == insert_pos->GetPrevious()) {
1789         insert_pos = if_input;
1790       }
1791     }
1792   }
1793   MoveBefore(insert_pos);
1794 }
1795 
SplitBefore(HInstruction * cursor)1796 HBasicBlock* HBasicBlock::SplitBefore(HInstruction* cursor) {
1797   DCHECK(!graph_->IsInSsaForm()) << "Support for SSA form not implemented.";
1798   DCHECK_EQ(cursor->GetBlock(), this);
1799 
1800   HBasicBlock* new_block =
1801       new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), cursor->GetDexPc());
1802   new_block->instructions_.first_instruction_ = cursor;
1803   new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
1804   instructions_.last_instruction_ = cursor->previous_;
1805   if (cursor->previous_ == nullptr) {
1806     instructions_.first_instruction_ = nullptr;
1807   } else {
1808     cursor->previous_->next_ = nullptr;
1809     cursor->previous_ = nullptr;
1810   }
1811 
1812   new_block->instructions_.SetBlockOfInstructions(new_block);
1813   AddInstruction(new (GetGraph()->GetAllocator()) HGoto(new_block->GetDexPc()));
1814 
1815   for (HBasicBlock* successor : GetSuccessors()) {
1816     successor->predecessors_[successor->GetPredecessorIndexOf(this)] = new_block;
1817   }
1818   new_block->successors_.swap(successors_);
1819   DCHECK(successors_.empty());
1820   AddSuccessor(new_block);
1821 
1822   GetGraph()->AddBlock(new_block);
1823   return new_block;
1824 }
1825 
CreateImmediateDominator()1826 HBasicBlock* HBasicBlock::CreateImmediateDominator() {
1827   DCHECK(!graph_->IsInSsaForm()) << "Support for SSA form not implemented.";
1828   DCHECK(!IsCatchBlock()) << "Support for updating try/catch information not implemented.";
1829 
1830   HBasicBlock* new_block = new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), GetDexPc());
1831 
1832   for (HBasicBlock* predecessor : GetPredecessors()) {
1833     predecessor->successors_[predecessor->GetSuccessorIndexOf(this)] = new_block;
1834   }
1835   new_block->predecessors_.swap(predecessors_);
1836   DCHECK(predecessors_.empty());
1837   AddPredecessor(new_block);
1838 
1839   GetGraph()->AddBlock(new_block);
1840   return new_block;
1841 }
1842 
SplitBeforeForInlining(HInstruction * cursor)1843 HBasicBlock* HBasicBlock::SplitBeforeForInlining(HInstruction* cursor) {
1844   DCHECK_EQ(cursor->GetBlock(), this);
1845 
1846   HBasicBlock* new_block =
1847       new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), cursor->GetDexPc());
1848   new_block->instructions_.first_instruction_ = cursor;
1849   new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
1850   instructions_.last_instruction_ = cursor->previous_;
1851   if (cursor->previous_ == nullptr) {
1852     instructions_.first_instruction_ = nullptr;
1853   } else {
1854     cursor->previous_->next_ = nullptr;
1855     cursor->previous_ = nullptr;
1856   }
1857 
1858   new_block->instructions_.SetBlockOfInstructions(new_block);
1859 
1860   for (HBasicBlock* successor : GetSuccessors()) {
1861     successor->predecessors_[successor->GetPredecessorIndexOf(this)] = new_block;
1862   }
1863   new_block->successors_.swap(successors_);
1864   DCHECK(successors_.empty());
1865 
1866   for (HBasicBlock* dominated : GetDominatedBlocks()) {
1867     dominated->dominator_ = new_block;
1868   }
1869   new_block->dominated_blocks_.swap(dominated_blocks_);
1870   DCHECK(dominated_blocks_.empty());
1871   return new_block;
1872 }
1873 
SplitAfterForInlining(HInstruction * cursor)1874 HBasicBlock* HBasicBlock::SplitAfterForInlining(HInstruction* cursor) {
1875   DCHECK(!cursor->IsControlFlow());
1876   DCHECK_NE(instructions_.last_instruction_, cursor);
1877   DCHECK_EQ(cursor->GetBlock(), this);
1878 
1879   HBasicBlock* new_block = new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), GetDexPc());
1880   new_block->instructions_.first_instruction_ = cursor->GetNext();
1881   new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
1882   cursor->next_->previous_ = nullptr;
1883   cursor->next_ = nullptr;
1884   instructions_.last_instruction_ = cursor;
1885 
1886   new_block->instructions_.SetBlockOfInstructions(new_block);
1887   for (HBasicBlock* successor : GetSuccessors()) {
1888     successor->predecessors_[successor->GetPredecessorIndexOf(this)] = new_block;
1889   }
1890   new_block->successors_.swap(successors_);
1891   DCHECK(successors_.empty());
1892 
1893   for (HBasicBlock* dominated : GetDominatedBlocks()) {
1894     dominated->dominator_ = new_block;
1895   }
1896   new_block->dominated_blocks_.swap(dominated_blocks_);
1897   DCHECK(dominated_blocks_.empty());
1898   return new_block;
1899 }
1900 
ComputeTryEntryOfSuccessors() const1901 const HTryBoundary* HBasicBlock::ComputeTryEntryOfSuccessors() const {
1902   if (EndsWithTryBoundary()) {
1903     HTryBoundary* try_boundary = GetLastInstruction()->AsTryBoundary();
1904     if (try_boundary->IsEntry()) {
1905       DCHECK(!IsTryBlock());
1906       return try_boundary;
1907     } else {
1908       DCHECK(IsTryBlock());
1909       DCHECK(try_catch_information_->GetTryEntry().HasSameExceptionHandlersAs(*try_boundary));
1910       return nullptr;
1911     }
1912   } else if (IsTryBlock()) {
1913     return &try_catch_information_->GetTryEntry();
1914   } else {
1915     return nullptr;
1916   }
1917 }
1918 
HasThrowingInstructions() const1919 bool HBasicBlock::HasThrowingInstructions() const {
1920   for (HInstructionIterator it(GetInstructions()); !it.Done(); it.Advance()) {
1921     if (it.Current()->CanThrow()) {
1922       return true;
1923     }
1924   }
1925   return false;
1926 }
1927 
HasOnlyOneInstruction(const HBasicBlock & block)1928 static bool HasOnlyOneInstruction(const HBasicBlock& block) {
1929   return block.GetPhis().IsEmpty()
1930       && !block.GetInstructions().IsEmpty()
1931       && block.GetFirstInstruction() == block.GetLastInstruction();
1932 }
1933 
IsSingleGoto() const1934 bool HBasicBlock::IsSingleGoto() const {
1935   return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsGoto();
1936 }
1937 
IsSingleReturn() const1938 bool HBasicBlock::IsSingleReturn() const {
1939   return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsReturn();
1940 }
1941 
IsSingleReturnOrReturnVoidAllowingPhis() const1942 bool HBasicBlock::IsSingleReturnOrReturnVoidAllowingPhis() const {
1943   return (GetFirstInstruction() == GetLastInstruction()) &&
1944          (GetLastInstruction()->IsReturn() || GetLastInstruction()->IsReturnVoid());
1945 }
1946 
IsSingleTryBoundary() const1947 bool HBasicBlock::IsSingleTryBoundary() const {
1948   return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsTryBoundary();
1949 }
1950 
EndsWithControlFlowInstruction() const1951 bool HBasicBlock::EndsWithControlFlowInstruction() const {
1952   return !GetInstructions().IsEmpty() && GetLastInstruction()->IsControlFlow();
1953 }
1954 
EndsWithIf() const1955 bool HBasicBlock::EndsWithIf() const {
1956   return !GetInstructions().IsEmpty() && GetLastInstruction()->IsIf();
1957 }
1958 
EndsWithTryBoundary() const1959 bool HBasicBlock::EndsWithTryBoundary() const {
1960   return !GetInstructions().IsEmpty() && GetLastInstruction()->IsTryBoundary();
1961 }
1962 
HasSinglePhi() const1963 bool HBasicBlock::HasSinglePhi() const {
1964   return !GetPhis().IsEmpty() && GetFirstPhi()->GetNext() == nullptr;
1965 }
1966 
GetNormalSuccessors() const1967 ArrayRef<HBasicBlock* const> HBasicBlock::GetNormalSuccessors() const {
1968   if (EndsWithTryBoundary()) {
1969     // The normal-flow successor of HTryBoundary is always stored at index zero.
1970     DCHECK_EQ(successors_[0], GetLastInstruction()->AsTryBoundary()->GetNormalFlowSuccessor());
1971     return ArrayRef<HBasicBlock* const>(successors_).SubArray(0u, 1u);
1972   } else {
1973     // All successors of blocks not ending with TryBoundary are normal.
1974     return ArrayRef<HBasicBlock* const>(successors_);
1975   }
1976 }
1977 
GetExceptionalSuccessors() const1978 ArrayRef<HBasicBlock* const> HBasicBlock::GetExceptionalSuccessors() const {
1979   if (EndsWithTryBoundary()) {
1980     return GetLastInstruction()->AsTryBoundary()->GetExceptionHandlers();
1981   } else {
1982     // Blocks not ending with TryBoundary do not have exceptional successors.
1983     return ArrayRef<HBasicBlock* const>();
1984   }
1985 }
1986 
HasSameExceptionHandlersAs(const HTryBoundary & other) const1987 bool HTryBoundary::HasSameExceptionHandlersAs(const HTryBoundary& other) const {
1988   ArrayRef<HBasicBlock* const> handlers1 = GetExceptionHandlers();
1989   ArrayRef<HBasicBlock* const> handlers2 = other.GetExceptionHandlers();
1990 
1991   size_t length = handlers1.size();
1992   if (length != handlers2.size()) {
1993     return false;
1994   }
1995 
1996   // Exception handlers need to be stored in the same order.
1997   for (size_t i = 0; i < length; ++i) {
1998     if (handlers1[i] != handlers2[i]) {
1999       return false;
2000     }
2001   }
2002   return true;
2003 }
2004 
CountSize() const2005 size_t HInstructionList::CountSize() const {
2006   size_t size = 0;
2007   HInstruction* current = first_instruction_;
2008   for (; current != nullptr; current = current->GetNext()) {
2009     size++;
2010   }
2011   return size;
2012 }
2013 
SetBlockOfInstructions(HBasicBlock * block) const2014 void HInstructionList::SetBlockOfInstructions(HBasicBlock* block) const {
2015   for (HInstruction* current = first_instruction_;
2016        current != nullptr;
2017        current = current->GetNext()) {
2018     current->SetBlock(block);
2019   }
2020 }
2021 
AddAfter(HInstruction * cursor,const HInstructionList & instruction_list)2022 void HInstructionList::AddAfter(HInstruction* cursor, const HInstructionList& instruction_list) {
2023   DCHECK(Contains(cursor));
2024   if (!instruction_list.IsEmpty()) {
2025     if (cursor == last_instruction_) {
2026       last_instruction_ = instruction_list.last_instruction_;
2027     } else {
2028       cursor->next_->previous_ = instruction_list.last_instruction_;
2029     }
2030     instruction_list.last_instruction_->next_ = cursor->next_;
2031     cursor->next_ = instruction_list.first_instruction_;
2032     instruction_list.first_instruction_->previous_ = cursor;
2033   }
2034 }
2035 
AddBefore(HInstruction * cursor,const HInstructionList & instruction_list)2036 void HInstructionList::AddBefore(HInstruction* cursor, const HInstructionList& instruction_list) {
2037   DCHECK(Contains(cursor));
2038   if (!instruction_list.IsEmpty()) {
2039     if (cursor == first_instruction_) {
2040       first_instruction_ = instruction_list.first_instruction_;
2041     } else {
2042       cursor->previous_->next_ = instruction_list.first_instruction_;
2043     }
2044     instruction_list.last_instruction_->next_ = cursor;
2045     instruction_list.first_instruction_->previous_ = cursor->previous_;
2046     cursor->previous_ = instruction_list.last_instruction_;
2047   }
2048 }
2049 
Add(const HInstructionList & instruction_list)2050 void HInstructionList::Add(const HInstructionList& instruction_list) {
2051   if (IsEmpty()) {
2052     first_instruction_ = instruction_list.first_instruction_;
2053     last_instruction_ = instruction_list.last_instruction_;
2054   } else {
2055     AddAfter(last_instruction_, instruction_list);
2056   }
2057 }
2058 
2059 // Should be called on instructions in a dead block in post order. This method
2060 // assumes `insn` has been removed from all users with the exception of catch
2061 // phis because of missing exceptional edges in the graph. It removes the
2062 // instruction from catch phi uses, together with inputs of other catch phis in
2063 // the catch block at the same index, as these must be dead too.
RemoveUsesOfDeadInstruction(HInstruction * insn)2064 static void RemoveUsesOfDeadInstruction(HInstruction* insn) {
2065   DCHECK(!insn->HasEnvironmentUses());
2066   while (insn->HasNonEnvironmentUses()) {
2067     const HUseListNode<HInstruction*>& use = insn->GetUses().front();
2068     size_t use_index = use.GetIndex();
2069     HBasicBlock* user_block =  use.GetUser()->GetBlock();
2070     DCHECK(use.GetUser()->IsPhi() && user_block->IsCatchBlock());
2071     for (HInstructionIterator phi_it(user_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
2072       phi_it.Current()->AsPhi()->RemoveInputAt(use_index);
2073     }
2074   }
2075 }
2076 
DisconnectAndDelete()2077 void HBasicBlock::DisconnectAndDelete() {
2078   // Dominators must be removed after all the blocks they dominate. This way
2079   // a loop header is removed last, a requirement for correct loop information
2080   // iteration.
2081   DCHECK(dominated_blocks_.empty());
2082 
2083   // The following steps gradually remove the block from all its dependants in
2084   // post order (b/27683071).
2085 
2086   // (1) Store a basic block that we'll use in step (5) to find loops to be updated.
2087   //     We need to do this before step (4) which destroys the predecessor list.
2088   HBasicBlock* loop_update_start = this;
2089   if (IsLoopHeader()) {
2090     HLoopInformation* loop_info = GetLoopInformation();
2091     // All other blocks in this loop should have been removed because the header
2092     // was their dominator.
2093     // Note that we do not remove `this` from `loop_info` as it is unreachable.
2094     DCHECK(!loop_info->IsIrreducible());
2095     DCHECK_EQ(loop_info->GetBlocks().NumSetBits(), 1u);
2096     DCHECK_EQ(static_cast<uint32_t>(loop_info->GetBlocks().GetHighestBitSet()), GetBlockId());
2097     loop_update_start = loop_info->GetPreHeader();
2098   }
2099 
2100   // (2) Disconnect the block from its successors and update their phis.
2101   for (HBasicBlock* successor : successors_) {
2102     // Delete this block from the list of predecessors.
2103     size_t this_index = successor->GetPredecessorIndexOf(this);
2104     successor->predecessors_.erase(successor->predecessors_.begin() + this_index);
2105 
2106     // Check that `successor` has other predecessors, otherwise `this` is the
2107     // dominator of `successor` which violates the order DCHECKed at the top.
2108     DCHECK(!successor->predecessors_.empty());
2109 
2110     // Remove this block's entries in the successor's phis. Skip exceptional
2111     // successors because catch phi inputs do not correspond to predecessor
2112     // blocks but throwing instructions. The inputs of the catch phis will be
2113     // updated in step (3).
2114     if (!successor->IsCatchBlock()) {
2115       if (successor->predecessors_.size() == 1u) {
2116         // The successor has just one predecessor left. Replace phis with the only
2117         // remaining input.
2118         for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
2119           HPhi* phi = phi_it.Current()->AsPhi();
2120           phi->ReplaceWith(phi->InputAt(1 - this_index));
2121           successor->RemovePhi(phi);
2122         }
2123       } else {
2124         for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
2125           phi_it.Current()->AsPhi()->RemoveInputAt(this_index);
2126         }
2127       }
2128     }
2129   }
2130   successors_.clear();
2131 
2132   // (3) Remove instructions and phis. Instructions should have no remaining uses
2133   //     except in catch phis. If an instruction is used by a catch phi at `index`,
2134   //     remove `index`-th input of all phis in the catch block since they are
2135   //     guaranteed dead. Note that we may miss dead inputs this way but the
2136   //     graph will always remain consistent.
2137   for (HBackwardInstructionIterator it(GetInstructions()); !it.Done(); it.Advance()) {
2138     HInstruction* insn = it.Current();
2139     RemoveUsesOfDeadInstruction(insn);
2140     RemoveInstruction(insn);
2141   }
2142   for (HInstructionIterator it(GetPhis()); !it.Done(); it.Advance()) {
2143     HPhi* insn = it.Current()->AsPhi();
2144     RemoveUsesOfDeadInstruction(insn);
2145     RemovePhi(insn);
2146   }
2147 
2148   // (4) Disconnect the block from its predecessors and update their
2149   //     control-flow instructions.
2150   for (HBasicBlock* predecessor : predecessors_) {
2151     // We should not see any back edges as they would have been removed by step (3).
2152     DCHECK(!IsInLoop() || !GetLoopInformation()->IsBackEdge(*predecessor));
2153 
2154     HInstruction* last_instruction = predecessor->GetLastInstruction();
2155     if (last_instruction->IsTryBoundary() && !IsCatchBlock()) {
2156       // This block is the only normal-flow successor of the TryBoundary which
2157       // makes `predecessor` dead. Since DCE removes blocks in post order,
2158       // exception handlers of this TryBoundary were already visited and any
2159       // remaining handlers therefore must be live. We remove `predecessor` from
2160       // their list of predecessors.
2161       DCHECK_EQ(last_instruction->AsTryBoundary()->GetNormalFlowSuccessor(), this);
2162       while (predecessor->GetSuccessors().size() > 1) {
2163         HBasicBlock* handler = predecessor->GetSuccessors()[1];
2164         DCHECK(handler->IsCatchBlock());
2165         predecessor->RemoveSuccessor(handler);
2166         handler->RemovePredecessor(predecessor);
2167       }
2168     }
2169 
2170     predecessor->RemoveSuccessor(this);
2171     uint32_t num_pred_successors = predecessor->GetSuccessors().size();
2172     if (num_pred_successors == 1u) {
2173       // If we have one successor after removing one, then we must have
2174       // had an HIf, HPackedSwitch or HTryBoundary, as they have more than one
2175       // successor. Replace those with a HGoto.
2176       DCHECK(last_instruction->IsIf() ||
2177              last_instruction->IsPackedSwitch() ||
2178              (last_instruction->IsTryBoundary() && IsCatchBlock()));
2179       predecessor->RemoveInstruction(last_instruction);
2180       predecessor->AddInstruction(new (graph_->GetAllocator()) HGoto(last_instruction->GetDexPc()));
2181     } else if (num_pred_successors == 0u) {
2182       // The predecessor has no remaining successors and therefore must be dead.
2183       // We deliberately leave it without a control-flow instruction so that the
2184       // GraphChecker fails unless it is not removed during the pass too.
2185       predecessor->RemoveInstruction(last_instruction);
2186     } else {
2187       // There are multiple successors left. The removed block might be a successor
2188       // of a PackedSwitch which will be completely removed (perhaps replaced with
2189       // a Goto), or we are deleting a catch block from a TryBoundary. In either
2190       // case, leave `last_instruction` as is for now.
2191       DCHECK(last_instruction->IsPackedSwitch() ||
2192              (last_instruction->IsTryBoundary() && IsCatchBlock()));
2193     }
2194   }
2195   predecessors_.clear();
2196 
2197   // (5) Remove the block from all loops it is included in. Skip the inner-most
2198   //     loop if this is the loop header (see definition of `loop_update_start`)
2199   //     because the loop header's predecessor list has been destroyed in step (4).
2200   for (HLoopInformationOutwardIterator it(*loop_update_start); !it.Done(); it.Advance()) {
2201     HLoopInformation* loop_info = it.Current();
2202     loop_info->Remove(this);
2203     if (loop_info->IsBackEdge(*this)) {
2204       // If this was the last back edge of the loop, we deliberately leave the
2205       // loop in an inconsistent state and will fail GraphChecker unless the
2206       // entire loop is removed during the pass.
2207       loop_info->RemoveBackEdge(this);
2208     }
2209   }
2210 
2211   // (6) Disconnect from the dominator.
2212   dominator_->RemoveDominatedBlock(this);
2213   SetDominator(nullptr);
2214 
2215   // (7) Delete from the graph, update reverse post order.
2216   graph_->DeleteDeadEmptyBlock(this);
2217   SetGraph(nullptr);
2218 }
2219 
MergeInstructionsWith(HBasicBlock * other)2220 void HBasicBlock::MergeInstructionsWith(HBasicBlock* other) {
2221   DCHECK(EndsWithControlFlowInstruction());
2222   RemoveInstruction(GetLastInstruction());
2223   instructions_.Add(other->GetInstructions());
2224   other->instructions_.SetBlockOfInstructions(this);
2225   other->instructions_.Clear();
2226 }
2227 
MergeWith(HBasicBlock * other)2228 void HBasicBlock::MergeWith(HBasicBlock* other) {
2229   DCHECK_EQ(GetGraph(), other->GetGraph());
2230   DCHECK(ContainsElement(dominated_blocks_, other));
2231   DCHECK_EQ(GetSingleSuccessor(), other);
2232   DCHECK_EQ(other->GetSinglePredecessor(), this);
2233   DCHECK(other->GetPhis().IsEmpty());
2234 
2235   // Move instructions from `other` to `this`.
2236   MergeInstructionsWith(other);
2237 
2238   // Remove `other` from the loops it is included in.
2239   for (HLoopInformationOutwardIterator it(*other); !it.Done(); it.Advance()) {
2240     HLoopInformation* loop_info = it.Current();
2241     loop_info->Remove(other);
2242     if (loop_info->IsBackEdge(*other)) {
2243       loop_info->ReplaceBackEdge(other, this);
2244     }
2245   }
2246 
2247   // Update links to the successors of `other`.
2248   successors_.clear();
2249   for (HBasicBlock* successor : other->GetSuccessors()) {
2250     successor->predecessors_[successor->GetPredecessorIndexOf(other)] = this;
2251   }
2252   successors_.swap(other->successors_);
2253   DCHECK(other->successors_.empty());
2254 
2255   // Update the dominator tree.
2256   RemoveDominatedBlock(other);
2257   for (HBasicBlock* dominated : other->GetDominatedBlocks()) {
2258     dominated->SetDominator(this);
2259   }
2260   dominated_blocks_.insert(
2261       dominated_blocks_.end(), other->dominated_blocks_.begin(), other->dominated_blocks_.end());
2262   other->dominated_blocks_.clear();
2263   other->dominator_ = nullptr;
2264 
2265   // Clear the list of predecessors of `other` in preparation of deleting it.
2266   other->predecessors_.clear();
2267 
2268   // Delete `other` from the graph. The function updates reverse post order.
2269   graph_->DeleteDeadEmptyBlock(other);
2270   other->SetGraph(nullptr);
2271 }
2272 
MergeWithInlined(HBasicBlock * other)2273 void HBasicBlock::MergeWithInlined(HBasicBlock* other) {
2274   DCHECK_NE(GetGraph(), other->GetGraph());
2275   DCHECK(GetDominatedBlocks().empty());
2276   DCHECK(GetSuccessors().empty());
2277   DCHECK(!EndsWithControlFlowInstruction());
2278   DCHECK(other->GetSinglePredecessor()->IsEntryBlock());
2279   DCHECK(other->GetPhis().IsEmpty());
2280   DCHECK(!other->IsInLoop());
2281 
2282   // Move instructions from `other` to `this`.
2283   instructions_.Add(other->GetInstructions());
2284   other->instructions_.SetBlockOfInstructions(this);
2285 
2286   // Update links to the successors of `other`.
2287   successors_.clear();
2288   for (HBasicBlock* successor : other->GetSuccessors()) {
2289     successor->predecessors_[successor->GetPredecessorIndexOf(other)] = this;
2290   }
2291   successors_.swap(other->successors_);
2292   DCHECK(other->successors_.empty());
2293 
2294   // Update the dominator tree.
2295   for (HBasicBlock* dominated : other->GetDominatedBlocks()) {
2296     dominated->SetDominator(this);
2297   }
2298   dominated_blocks_.insert(
2299       dominated_blocks_.end(), other->dominated_blocks_.begin(), other->dominated_blocks_.end());
2300   other->dominated_blocks_.clear();
2301   other->dominator_ = nullptr;
2302   other->graph_ = nullptr;
2303 }
2304 
ReplaceWith(HBasicBlock * other)2305 void HBasicBlock::ReplaceWith(HBasicBlock* other) {
2306   while (!GetPredecessors().empty()) {
2307     HBasicBlock* predecessor = GetPredecessors()[0];
2308     predecessor->ReplaceSuccessor(this, other);
2309   }
2310   while (!GetSuccessors().empty()) {
2311     HBasicBlock* successor = GetSuccessors()[0];
2312     successor->ReplacePredecessor(this, other);
2313   }
2314   for (HBasicBlock* dominated : GetDominatedBlocks()) {
2315     other->AddDominatedBlock(dominated);
2316   }
2317   GetDominator()->ReplaceDominatedBlock(this, other);
2318   other->SetDominator(GetDominator());
2319   dominator_ = nullptr;
2320   graph_ = nullptr;
2321 }
2322 
DeleteDeadEmptyBlock(HBasicBlock * block)2323 void HGraph::DeleteDeadEmptyBlock(HBasicBlock* block) {
2324   DCHECK_EQ(block->GetGraph(), this);
2325   DCHECK(block->GetSuccessors().empty());
2326   DCHECK(block->GetPredecessors().empty());
2327   DCHECK(block->GetDominatedBlocks().empty());
2328   DCHECK(block->GetDominator() == nullptr);
2329   DCHECK(block->GetInstructions().IsEmpty());
2330   DCHECK(block->GetPhis().IsEmpty());
2331 
2332   if (block->IsExitBlock()) {
2333     SetExitBlock(nullptr);
2334   }
2335 
2336   RemoveElement(reverse_post_order_, block);
2337   blocks_[block->GetBlockId()] = nullptr;
2338   block->SetGraph(nullptr);
2339 }
2340 
UpdateLoopAndTryInformationOfNewBlock(HBasicBlock * block,HBasicBlock * reference,bool replace_if_back_edge)2341 void HGraph::UpdateLoopAndTryInformationOfNewBlock(HBasicBlock* block,
2342                                                    HBasicBlock* reference,
2343                                                    bool replace_if_back_edge) {
2344   if (block->IsLoopHeader()) {
2345     // Clear the information of which blocks are contained in that loop. Since the
2346     // information is stored as a bit vector based on block ids, we have to update
2347     // it, as those block ids were specific to the callee graph and we are now adding
2348     // these blocks to the caller graph.
2349     block->GetLoopInformation()->ClearAllBlocks();
2350   }
2351 
2352   // If not already in a loop, update the loop information.
2353   if (!block->IsInLoop()) {
2354     block->SetLoopInformation(reference->GetLoopInformation());
2355   }
2356 
2357   // If the block is in a loop, update all its outward loops.
2358   HLoopInformation* loop_info = block->GetLoopInformation();
2359   if (loop_info != nullptr) {
2360     for (HLoopInformationOutwardIterator loop_it(*block);
2361          !loop_it.Done();
2362          loop_it.Advance()) {
2363       loop_it.Current()->Add(block);
2364     }
2365     if (replace_if_back_edge && loop_info->IsBackEdge(*reference)) {
2366       loop_info->ReplaceBackEdge(reference, block);
2367     }
2368   }
2369 
2370   // Copy TryCatchInformation if `reference` is a try block, not if it is a catch block.
2371   TryCatchInformation* try_catch_info = reference->IsTryBlock()
2372       ? reference->GetTryCatchInformation()
2373       : nullptr;
2374   block->SetTryCatchInformation(try_catch_info);
2375 }
2376 
InlineInto(HGraph * outer_graph,HInvoke * invoke)2377 HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
2378   DCHECK(HasExitBlock()) << "Unimplemented scenario";
2379   // Update the environments in this graph to have the invoke's environment
2380   // as parent.
2381   {
2382     // Skip the entry block, we do not need to update the entry's suspend check.
2383     for (HBasicBlock* block : GetReversePostOrderSkipEntryBlock()) {
2384       for (HInstructionIterator instr_it(block->GetInstructions());
2385            !instr_it.Done();
2386            instr_it.Advance()) {
2387         HInstruction* current = instr_it.Current();
2388         if (current->NeedsEnvironment()) {
2389           DCHECK(current->HasEnvironment());
2390           current->GetEnvironment()->SetAndCopyParentChain(
2391               outer_graph->GetAllocator(), invoke->GetEnvironment());
2392         }
2393       }
2394     }
2395   }
2396   outer_graph->UpdateMaximumNumberOfOutVRegs(GetMaximumNumberOfOutVRegs());
2397 
2398   if (HasBoundsChecks()) {
2399     outer_graph->SetHasBoundsChecks(true);
2400   }
2401   if (HasLoops()) {
2402     outer_graph->SetHasLoops(true);
2403   }
2404   if (HasIrreducibleLoops()) {
2405     outer_graph->SetHasIrreducibleLoops(true);
2406   }
2407   if (HasTryCatch()) {
2408     outer_graph->SetHasTryCatch(true);
2409   }
2410   if (HasSIMD()) {
2411     outer_graph->SetHasSIMD(true);
2412   }
2413 
2414   HInstruction* return_value = nullptr;
2415   if (GetBlocks().size() == 3) {
2416     // Inliner already made sure we don't inline methods that always throw.
2417     DCHECK(!GetBlocks()[1]->GetLastInstruction()->IsThrow());
2418     // Simple case of an entry block, a body block, and an exit block.
2419     // Put the body block's instruction into `invoke`'s block.
2420     HBasicBlock* body = GetBlocks()[1];
2421     DCHECK(GetBlocks()[0]->IsEntryBlock());
2422     DCHECK(GetBlocks()[2]->IsExitBlock());
2423     DCHECK(!body->IsExitBlock());
2424     DCHECK(!body->IsInLoop());
2425     HInstruction* last = body->GetLastInstruction();
2426 
2427     // Note that we add instructions before the invoke only to simplify polymorphic inlining.
2428     invoke->GetBlock()->instructions_.AddBefore(invoke, body->GetInstructions());
2429     body->GetInstructions().SetBlockOfInstructions(invoke->GetBlock());
2430 
2431     // Replace the invoke with the return value of the inlined graph.
2432     if (last->IsReturn()) {
2433       return_value = last->InputAt(0);
2434     } else {
2435       DCHECK(last->IsReturnVoid());
2436     }
2437 
2438     invoke->GetBlock()->RemoveInstruction(last);
2439   } else {
2440     // Need to inline multiple blocks. We split `invoke`'s block
2441     // into two blocks, merge the first block of the inlined graph into
2442     // the first half, and replace the exit block of the inlined graph
2443     // with the second half.
2444     ArenaAllocator* allocator = outer_graph->GetAllocator();
2445     HBasicBlock* at = invoke->GetBlock();
2446     // Note that we split before the invoke only to simplify polymorphic inlining.
2447     HBasicBlock* to = at->SplitBeforeForInlining(invoke);
2448 
2449     HBasicBlock* first = entry_block_->GetSuccessors()[0];
2450     DCHECK(!first->IsInLoop());
2451     at->MergeWithInlined(first);
2452     exit_block_->ReplaceWith(to);
2453 
2454     // Update the meta information surrounding blocks:
2455     // (1) the graph they are now in,
2456     // (2) the reverse post order of that graph,
2457     // (3) their potential loop information, inner and outer,
2458     // (4) try block membership.
2459     // Note that we do not need to update catch phi inputs because they
2460     // correspond to the register file of the outer method which the inlinee
2461     // cannot modify.
2462 
2463     // We don't add the entry block, the exit block, and the first block, which
2464     // has been merged with `at`.
2465     static constexpr int kNumberOfSkippedBlocksInCallee = 3;
2466 
2467     // We add the `to` block.
2468     static constexpr int kNumberOfNewBlocksInCaller = 1;
2469     size_t blocks_added = (reverse_post_order_.size() - kNumberOfSkippedBlocksInCallee)
2470         + kNumberOfNewBlocksInCaller;
2471 
2472     // Find the location of `at` in the outer graph's reverse post order. The new
2473     // blocks will be added after it.
2474     size_t index_of_at = IndexOfElement(outer_graph->reverse_post_order_, at);
2475     MakeRoomFor(&outer_graph->reverse_post_order_, blocks_added, index_of_at);
2476 
2477     // Do a reverse post order of the blocks in the callee and do (1), (2), (3)
2478     // and (4) to the blocks that apply.
2479     for (HBasicBlock* current : GetReversePostOrder()) {
2480       if (current != exit_block_ && current != entry_block_ && current != first) {
2481         DCHECK(current->GetTryCatchInformation() == nullptr);
2482         DCHECK(current->GetGraph() == this);
2483         current->SetGraph(outer_graph);
2484         outer_graph->AddBlock(current);
2485         outer_graph->reverse_post_order_[++index_of_at] = current;
2486         UpdateLoopAndTryInformationOfNewBlock(current, at,  /* replace_if_back_edge */ false);
2487       }
2488     }
2489 
2490     // Do (1), (2), (3) and (4) to `to`.
2491     to->SetGraph(outer_graph);
2492     outer_graph->AddBlock(to);
2493     outer_graph->reverse_post_order_[++index_of_at] = to;
2494     // Only `to` can become a back edge, as the inlined blocks
2495     // are predecessors of `to`.
2496     UpdateLoopAndTryInformationOfNewBlock(to, at, /* replace_if_back_edge */ true);
2497 
2498     // Update all predecessors of the exit block (now the `to` block)
2499     // to not `HReturn` but `HGoto` instead. Special case throwing blocks
2500     // to now get the outer graph exit block as successor. Note that the inliner
2501     // currently doesn't support inlining methods with try/catch.
2502     HPhi* return_value_phi = nullptr;
2503     bool rerun_dominance = false;
2504     bool rerun_loop_analysis = false;
2505     for (size_t pred = 0; pred < to->GetPredecessors().size(); ++pred) {
2506       HBasicBlock* predecessor = to->GetPredecessors()[pred];
2507       HInstruction* last = predecessor->GetLastInstruction();
2508       if (last->IsThrow()) {
2509         DCHECK(!at->IsTryBlock());
2510         predecessor->ReplaceSuccessor(to, outer_graph->GetExitBlock());
2511         --pred;
2512         // We need to re-run dominance information, as the exit block now has
2513         // a new dominator.
2514         rerun_dominance = true;
2515         if (predecessor->GetLoopInformation() != nullptr) {
2516           // The exit block and blocks post dominated by the exit block do not belong
2517           // to any loop. Because we do not compute the post dominators, we need to re-run
2518           // loop analysis to get the loop information correct.
2519           rerun_loop_analysis = true;
2520         }
2521       } else {
2522         if (last->IsReturnVoid()) {
2523           DCHECK(return_value == nullptr);
2524           DCHECK(return_value_phi == nullptr);
2525         } else {
2526           DCHECK(last->IsReturn());
2527           if (return_value_phi != nullptr) {
2528             return_value_phi->AddInput(last->InputAt(0));
2529           } else if (return_value == nullptr) {
2530             return_value = last->InputAt(0);
2531           } else {
2532             // There will be multiple returns.
2533             return_value_phi = new (allocator) HPhi(
2534                 allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc());
2535             to->AddPhi(return_value_phi);
2536             return_value_phi->AddInput(return_value);
2537             return_value_phi->AddInput(last->InputAt(0));
2538             return_value = return_value_phi;
2539           }
2540         }
2541         predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
2542         predecessor->RemoveInstruction(last);
2543       }
2544     }
2545     if (rerun_loop_analysis) {
2546       DCHECK(!outer_graph->HasIrreducibleLoops())
2547           << "Recomputing loop information in graphs with irreducible loops "
2548           << "is unsupported, as it could lead to loop header changes";
2549       outer_graph->ClearLoopInformation();
2550       outer_graph->ClearDominanceInformation();
2551       outer_graph->BuildDominatorTree();
2552     } else if (rerun_dominance) {
2553       outer_graph->ClearDominanceInformation();
2554       outer_graph->ComputeDominanceInformation();
2555     }
2556   }
2557 
2558   // Walk over the entry block and:
2559   // - Move constants from the entry block to the outer_graph's entry block,
2560   // - Replace HParameterValue instructions with their real value.
2561   // - Remove suspend checks, that hold an environment.
2562   // We must do this after the other blocks have been inlined, otherwise ids of
2563   // constants could overlap with the inner graph.
2564   size_t parameter_index = 0;
2565   for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
2566     HInstruction* current = it.Current();
2567     HInstruction* replacement = nullptr;
2568     if (current->IsNullConstant()) {
2569       replacement = outer_graph->GetNullConstant(current->GetDexPc());
2570     } else if (current->IsIntConstant()) {
2571       replacement = outer_graph->GetIntConstant(
2572           current->AsIntConstant()->GetValue(), current->GetDexPc());
2573     } else if (current->IsLongConstant()) {
2574       replacement = outer_graph->GetLongConstant(
2575           current->AsLongConstant()->GetValue(), current->GetDexPc());
2576     } else if (current->IsFloatConstant()) {
2577       replacement = outer_graph->GetFloatConstant(
2578           current->AsFloatConstant()->GetValue(), current->GetDexPc());
2579     } else if (current->IsDoubleConstant()) {
2580       replacement = outer_graph->GetDoubleConstant(
2581           current->AsDoubleConstant()->GetValue(), current->GetDexPc());
2582     } else if (current->IsParameterValue()) {
2583       if (kIsDebugBuild
2584           && invoke->IsInvokeStaticOrDirect()
2585           && invoke->AsInvokeStaticOrDirect()->IsStaticWithExplicitClinitCheck()) {
2586         // Ensure we do not use the last input of `invoke`, as it
2587         // contains a clinit check which is not an actual argument.
2588         size_t last_input_index = invoke->InputCount() - 1;
2589         DCHECK(parameter_index != last_input_index);
2590       }
2591       replacement = invoke->InputAt(parameter_index++);
2592     } else if (current->IsCurrentMethod()) {
2593       replacement = outer_graph->GetCurrentMethod();
2594     } else {
2595       DCHECK(current->IsGoto() || current->IsSuspendCheck());
2596       entry_block_->RemoveInstruction(current);
2597     }
2598     if (replacement != nullptr) {
2599       current->ReplaceWith(replacement);
2600       // If the current is the return value then we need to update the latter.
2601       if (current == return_value) {
2602         DCHECK_EQ(entry_block_, return_value->GetBlock());
2603         return_value = replacement;
2604       }
2605     }
2606   }
2607 
2608   return return_value;
2609 }
2610 
2611 /*
2612  * Loop will be transformed to:
2613  *       old_pre_header
2614  *             |
2615  *          if_block
2616  *           /    \
2617  *  true_block   false_block
2618  *           \    /
2619  *       new_pre_header
2620  *             |
2621  *           header
2622  */
TransformLoopHeaderForBCE(HBasicBlock * header)2623 void HGraph::TransformLoopHeaderForBCE(HBasicBlock* header) {
2624   DCHECK(header->IsLoopHeader());
2625   HBasicBlock* old_pre_header = header->GetDominator();
2626 
2627   // Need extra block to avoid critical edge.
2628   HBasicBlock* if_block = new (allocator_) HBasicBlock(this, header->GetDexPc());
2629   HBasicBlock* true_block = new (allocator_) HBasicBlock(this, header->GetDexPc());
2630   HBasicBlock* false_block = new (allocator_) HBasicBlock(this, header->GetDexPc());
2631   HBasicBlock* new_pre_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
2632   AddBlock(if_block);
2633   AddBlock(true_block);
2634   AddBlock(false_block);
2635   AddBlock(new_pre_header);
2636 
2637   header->ReplacePredecessor(old_pre_header, new_pre_header);
2638   old_pre_header->successors_.clear();
2639   old_pre_header->dominated_blocks_.clear();
2640 
2641   old_pre_header->AddSuccessor(if_block);
2642   if_block->AddSuccessor(true_block);  // True successor
2643   if_block->AddSuccessor(false_block);  // False successor
2644   true_block->AddSuccessor(new_pre_header);
2645   false_block->AddSuccessor(new_pre_header);
2646 
2647   old_pre_header->dominated_blocks_.push_back(if_block);
2648   if_block->SetDominator(old_pre_header);
2649   if_block->dominated_blocks_.push_back(true_block);
2650   true_block->SetDominator(if_block);
2651   if_block->dominated_blocks_.push_back(false_block);
2652   false_block->SetDominator(if_block);
2653   if_block->dominated_blocks_.push_back(new_pre_header);
2654   new_pre_header->SetDominator(if_block);
2655   new_pre_header->dominated_blocks_.push_back(header);
2656   header->SetDominator(new_pre_header);
2657 
2658   // Fix reverse post order.
2659   size_t index_of_header = IndexOfElement(reverse_post_order_, header);
2660   MakeRoomFor(&reverse_post_order_, 4, index_of_header - 1);
2661   reverse_post_order_[index_of_header++] = if_block;
2662   reverse_post_order_[index_of_header++] = true_block;
2663   reverse_post_order_[index_of_header++] = false_block;
2664   reverse_post_order_[index_of_header++] = new_pre_header;
2665 
2666   // The pre_header can never be a back edge of a loop.
2667   DCHECK((old_pre_header->GetLoopInformation() == nullptr) ||
2668          !old_pre_header->GetLoopInformation()->IsBackEdge(*old_pre_header));
2669   UpdateLoopAndTryInformationOfNewBlock(
2670       if_block, old_pre_header, /* replace_if_back_edge */ false);
2671   UpdateLoopAndTryInformationOfNewBlock(
2672       true_block, old_pre_header, /* replace_if_back_edge */ false);
2673   UpdateLoopAndTryInformationOfNewBlock(
2674       false_block, old_pre_header, /* replace_if_back_edge */ false);
2675   UpdateLoopAndTryInformationOfNewBlock(
2676       new_pre_header, old_pre_header, /* replace_if_back_edge */ false);
2677 }
2678 
TransformLoopForVectorization(HBasicBlock * header,HBasicBlock * body,HBasicBlock * exit)2679 HBasicBlock* HGraph::TransformLoopForVectorization(HBasicBlock* header,
2680                                                    HBasicBlock* body,
2681                                                    HBasicBlock* exit) {
2682   DCHECK(header->IsLoopHeader());
2683   HLoopInformation* loop = header->GetLoopInformation();
2684 
2685   // Add new loop blocks.
2686   HBasicBlock* new_pre_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
2687   HBasicBlock* new_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
2688   HBasicBlock* new_body = new (allocator_) HBasicBlock(this, header->GetDexPc());
2689   AddBlock(new_pre_header);
2690   AddBlock(new_header);
2691   AddBlock(new_body);
2692 
2693   // Set up control flow.
2694   header->ReplaceSuccessor(exit, new_pre_header);
2695   new_pre_header->AddSuccessor(new_header);
2696   new_header->AddSuccessor(exit);
2697   new_header->AddSuccessor(new_body);
2698   new_body->AddSuccessor(new_header);
2699 
2700   // Set up dominators.
2701   header->ReplaceDominatedBlock(exit, new_pre_header);
2702   new_pre_header->SetDominator(header);
2703   new_pre_header->dominated_blocks_.push_back(new_header);
2704   new_header->SetDominator(new_pre_header);
2705   new_header->dominated_blocks_.push_back(new_body);
2706   new_body->SetDominator(new_header);
2707   new_header->dominated_blocks_.push_back(exit);
2708   exit->SetDominator(new_header);
2709 
2710   // Fix reverse post order.
2711   size_t index_of_header = IndexOfElement(reverse_post_order_, header);
2712   MakeRoomFor(&reverse_post_order_, 2, index_of_header);
2713   reverse_post_order_[++index_of_header] = new_pre_header;
2714   reverse_post_order_[++index_of_header] = new_header;
2715   size_t index_of_body = IndexOfElement(reverse_post_order_, body);
2716   MakeRoomFor(&reverse_post_order_, 1, index_of_body - 1);
2717   reverse_post_order_[index_of_body] = new_body;
2718 
2719   // Add gotos and suspend check (client must add conditional in header).
2720   new_pre_header->AddInstruction(new (allocator_) HGoto());
2721   HSuspendCheck* suspend_check = new (allocator_) HSuspendCheck(header->GetDexPc());
2722   new_header->AddInstruction(suspend_check);
2723   new_body->AddInstruction(new (allocator_) HGoto());
2724   suspend_check->CopyEnvironmentFromWithLoopPhiAdjustment(
2725       loop->GetSuspendCheck()->GetEnvironment(), header);
2726 
2727   // Update loop information.
2728   new_header->AddBackEdge(new_body);
2729   new_header->GetLoopInformation()->SetSuspendCheck(suspend_check);
2730   new_header->GetLoopInformation()->Populate();
2731   new_pre_header->SetLoopInformation(loop->GetPreHeader()->GetLoopInformation());  // outward
2732   HLoopInformationOutwardIterator it(*new_header);
2733   for (it.Advance(); !it.Done(); it.Advance()) {
2734     it.Current()->Add(new_pre_header);
2735     it.Current()->Add(new_header);
2736     it.Current()->Add(new_body);
2737   }
2738   return new_pre_header;
2739 }
2740 
CheckAgainstUpperBound(ReferenceTypeInfo rti,ReferenceTypeInfo upper_bound_rti)2741 static void CheckAgainstUpperBound(ReferenceTypeInfo rti, ReferenceTypeInfo upper_bound_rti)
2742     REQUIRES_SHARED(Locks::mutator_lock_) {
2743   if (rti.IsValid()) {
2744     DCHECK(upper_bound_rti.IsSupertypeOf(rti))
2745         << " upper_bound_rti: " << upper_bound_rti
2746         << " rti: " << rti;
2747     DCHECK(!upper_bound_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes() || rti.IsExact())
2748         << " upper_bound_rti: " << upper_bound_rti
2749         << " rti: " << rti;
2750   }
2751 }
2752 
SetReferenceTypeInfo(ReferenceTypeInfo rti)2753 void HInstruction::SetReferenceTypeInfo(ReferenceTypeInfo rti) {
2754   if (kIsDebugBuild) {
2755     DCHECK_EQ(GetType(), DataType::Type::kReference);
2756     ScopedObjectAccess soa(Thread::Current());
2757     DCHECK(rti.IsValid()) << "Invalid RTI for " << DebugName();
2758     if (IsBoundType()) {
2759       // Having the test here spares us from making the method virtual just for
2760       // the sake of a DCHECK.
2761       CheckAgainstUpperBound(rti, AsBoundType()->GetUpperBound());
2762     }
2763   }
2764   reference_type_handle_ = rti.GetTypeHandle();
2765   SetPackedFlag<kFlagReferenceTypeIsExact>(rti.IsExact());
2766 }
2767 
SetUpperBound(const ReferenceTypeInfo & upper_bound,bool can_be_null)2768 void HBoundType::SetUpperBound(const ReferenceTypeInfo& upper_bound, bool can_be_null) {
2769   if (kIsDebugBuild) {
2770     ScopedObjectAccess soa(Thread::Current());
2771     DCHECK(upper_bound.IsValid());
2772     DCHECK(!upper_bound_.IsValid()) << "Upper bound should only be set once.";
2773     CheckAgainstUpperBound(GetReferenceTypeInfo(), upper_bound);
2774   }
2775   upper_bound_ = upper_bound;
2776   SetPackedFlag<kFlagUpperCanBeNull>(can_be_null);
2777 }
2778 
Create(TypeHandle type_handle,bool is_exact)2779 ReferenceTypeInfo ReferenceTypeInfo::Create(TypeHandle type_handle, bool is_exact) {
2780   if (kIsDebugBuild) {
2781     ScopedObjectAccess soa(Thread::Current());
2782     DCHECK(IsValidHandle(type_handle));
2783     if (!is_exact) {
2784       DCHECK(!type_handle->CannotBeAssignedFromOtherTypes())
2785           << "Callers of ReferenceTypeInfo::Create should ensure is_exact is properly computed";
2786     }
2787   }
2788   return ReferenceTypeInfo(type_handle, is_exact);
2789 }
2790 
operator <<(std::ostream & os,const ReferenceTypeInfo & rhs)2791 std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs) {
2792   ScopedObjectAccess soa(Thread::Current());
2793   os << "["
2794      << " is_valid=" << rhs.IsValid()
2795      << " type=" << (!rhs.IsValid() ? "?" : mirror::Class::PrettyClass(rhs.GetTypeHandle().Get()))
2796      << " is_exact=" << rhs.IsExact()
2797      << " ]";
2798   return os;
2799 }
2800 
HasAnyEnvironmentUseBefore(HInstruction * other)2801 bool HInstruction::HasAnyEnvironmentUseBefore(HInstruction* other) {
2802   // For now, assume that instructions in different blocks may use the
2803   // environment.
2804   // TODO: Use the control flow to decide if this is true.
2805   if (GetBlock() != other->GetBlock()) {
2806     return true;
2807   }
2808 
2809   // We know that we are in the same block. Walk from 'this' to 'other',
2810   // checking to see if there is any instruction with an environment.
2811   HInstruction* current = this;
2812   for (; current != other && current != nullptr; current = current->GetNext()) {
2813     // This is a conservative check, as the instruction result may not be in
2814     // the referenced environment.
2815     if (current->HasEnvironment()) {
2816       return true;
2817     }
2818   }
2819 
2820   // We should have been called with 'this' before 'other' in the block.
2821   // Just confirm this.
2822   DCHECK(current != nullptr);
2823   return false;
2824 }
2825 
SetIntrinsic(Intrinsics intrinsic,IntrinsicNeedsEnvironmentOrCache needs_env_or_cache,IntrinsicSideEffects side_effects,IntrinsicExceptions exceptions)2826 void HInvoke::SetIntrinsic(Intrinsics intrinsic,
2827                            IntrinsicNeedsEnvironmentOrCache needs_env_or_cache,
2828                            IntrinsicSideEffects side_effects,
2829                            IntrinsicExceptions exceptions) {
2830   intrinsic_ = intrinsic;
2831   IntrinsicOptimizations opt(this);
2832 
2833   // Adjust method's side effects from intrinsic table.
2834   switch (side_effects) {
2835     case kNoSideEffects: SetSideEffects(SideEffects::None()); break;
2836     case kReadSideEffects: SetSideEffects(SideEffects::AllReads()); break;
2837     case kWriteSideEffects: SetSideEffects(SideEffects::AllWrites()); break;
2838     case kAllSideEffects: SetSideEffects(SideEffects::AllExceptGCDependency()); break;
2839   }
2840 
2841   if (needs_env_or_cache == kNoEnvironmentOrCache) {
2842     opt.SetDoesNotNeedDexCache();
2843     opt.SetDoesNotNeedEnvironment();
2844   } else {
2845     // If we need an environment, that means there will be a call, which can trigger GC.
2846     SetSideEffects(GetSideEffects().Union(SideEffects::CanTriggerGC()));
2847   }
2848   // Adjust method's exception status from intrinsic table.
2849   SetCanThrow(exceptions == kCanThrow);
2850 }
2851 
IsStringAlloc() const2852 bool HNewInstance::IsStringAlloc() const {
2853   ScopedObjectAccess soa(Thread::Current());
2854   return GetReferenceTypeInfo().IsStringClass();
2855 }
2856 
NeedsEnvironment() const2857 bool HInvoke::NeedsEnvironment() const {
2858   if (!IsIntrinsic()) {
2859     return true;
2860   }
2861   IntrinsicOptimizations opt(*this);
2862   return !opt.GetDoesNotNeedEnvironment();
2863 }
2864 
GetDexFileForPcRelativeDexCache() const2865 const DexFile& HInvokeStaticOrDirect::GetDexFileForPcRelativeDexCache() const {
2866   ArtMethod* caller = GetEnvironment()->GetMethod();
2867   ScopedObjectAccess soa(Thread::Current());
2868   // `caller` is null for a top-level graph representing a method whose declaring
2869   // class was not resolved.
2870   return caller == nullptr ? GetBlock()->GetGraph()->GetDexFile() : *caller->GetDexFile();
2871 }
2872 
NeedsDexCacheOfDeclaringClass() const2873 bool HInvokeStaticOrDirect::NeedsDexCacheOfDeclaringClass() const {
2874   if (GetMethodLoadKind() != MethodLoadKind::kRuntimeCall) {
2875     return false;
2876   }
2877   if (!IsIntrinsic()) {
2878     return true;
2879   }
2880   IntrinsicOptimizations opt(*this);
2881   return !opt.GetDoesNotNeedDexCache();
2882 }
2883 
operator <<(std::ostream & os,HInvokeStaticOrDirect::MethodLoadKind rhs)2884 std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs) {
2885   switch (rhs) {
2886     case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
2887       return os << "StringInit";
2888     case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
2889       return os << "Recursive";
2890     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative:
2891       return os << "BootImageLinkTimePcRelative";
2892     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
2893       return os << "DirectAddress";
2894     case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry:
2895       return os << "BssEntry";
2896     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall:
2897       return os << "RuntimeCall";
2898     default:
2899       LOG(FATAL) << "Unknown MethodLoadKind: " << static_cast<int>(rhs);
2900       UNREACHABLE();
2901   }
2902 }
2903 
operator <<(std::ostream & os,HInvokeStaticOrDirect::ClinitCheckRequirement rhs)2904 std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckRequirement rhs) {
2905   switch (rhs) {
2906     case HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit:
2907       return os << "explicit";
2908     case HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit:
2909       return os << "implicit";
2910     case HInvokeStaticOrDirect::ClinitCheckRequirement::kNone:
2911       return os << "none";
2912     default:
2913       LOG(FATAL) << "Unknown ClinitCheckRequirement: " << static_cast<int>(rhs);
2914       UNREACHABLE();
2915   }
2916 }
2917 
InstructionDataEquals(const HInstruction * other) const2918 bool HLoadClass::InstructionDataEquals(const HInstruction* other) const {
2919   const HLoadClass* other_load_class = other->AsLoadClass();
2920   // TODO: To allow GVN for HLoadClass from different dex files, we should compare the type
2921   // names rather than type indexes. However, we shall also have to re-think the hash code.
2922   if (type_index_ != other_load_class->type_index_ ||
2923       GetPackedFields() != other_load_class->GetPackedFields()) {
2924     return false;
2925   }
2926   switch (GetLoadKind()) {
2927     case LoadKind::kBootImageAddress:
2928     case LoadKind::kBootImageClassTable:
2929     case LoadKind::kJitTableAddress: {
2930       ScopedObjectAccess soa(Thread::Current());
2931       return GetClass().Get() == other_load_class->GetClass().Get();
2932     }
2933     default:
2934       DCHECK(HasTypeReference(GetLoadKind()));
2935       return IsSameDexFile(GetDexFile(), other_load_class->GetDexFile());
2936   }
2937 }
2938 
operator <<(std::ostream & os,HLoadClass::LoadKind rhs)2939 std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs) {
2940   switch (rhs) {
2941     case HLoadClass::LoadKind::kReferrersClass:
2942       return os << "ReferrersClass";
2943     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
2944       return os << "BootImageLinkTimePcRelative";
2945     case HLoadClass::LoadKind::kBootImageAddress:
2946       return os << "BootImageAddress";
2947     case HLoadClass::LoadKind::kBootImageClassTable:
2948       return os << "BootImageClassTable";
2949     case HLoadClass::LoadKind::kBssEntry:
2950       return os << "BssEntry";
2951     case HLoadClass::LoadKind::kJitTableAddress:
2952       return os << "JitTableAddress";
2953     case HLoadClass::LoadKind::kRuntimeCall:
2954       return os << "RuntimeCall";
2955     default:
2956       LOG(FATAL) << "Unknown HLoadClass::LoadKind: " << static_cast<int>(rhs);
2957       UNREACHABLE();
2958   }
2959 }
2960 
InstructionDataEquals(const HInstruction * other) const2961 bool HLoadString::InstructionDataEquals(const HInstruction* other) const {
2962   const HLoadString* other_load_string = other->AsLoadString();
2963   // TODO: To allow GVN for HLoadString from different dex files, we should compare the strings
2964   // rather than their indexes. However, we shall also have to re-think the hash code.
2965   if (string_index_ != other_load_string->string_index_ ||
2966       GetPackedFields() != other_load_string->GetPackedFields()) {
2967     return false;
2968   }
2969   switch (GetLoadKind()) {
2970     case LoadKind::kBootImageAddress:
2971     case LoadKind::kBootImageInternTable:
2972     case LoadKind::kJitTableAddress: {
2973       ScopedObjectAccess soa(Thread::Current());
2974       return GetString().Get() == other_load_string->GetString().Get();
2975     }
2976     default:
2977       return IsSameDexFile(GetDexFile(), other_load_string->GetDexFile());
2978   }
2979 }
2980 
operator <<(std::ostream & os,HLoadString::LoadKind rhs)2981 std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs) {
2982   switch (rhs) {
2983     case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
2984       return os << "BootImageLinkTimePcRelative";
2985     case HLoadString::LoadKind::kBootImageAddress:
2986       return os << "BootImageAddress";
2987     case HLoadString::LoadKind::kBootImageInternTable:
2988       return os << "BootImageInternTable";
2989     case HLoadString::LoadKind::kBssEntry:
2990       return os << "BssEntry";
2991     case HLoadString::LoadKind::kJitTableAddress:
2992       return os << "JitTableAddress";
2993     case HLoadString::LoadKind::kRuntimeCall:
2994       return os << "RuntimeCall";
2995     default:
2996       LOG(FATAL) << "Unknown HLoadString::LoadKind: " << static_cast<int>(rhs);
2997       UNREACHABLE();
2998   }
2999 }
3000 
RemoveEnvironmentUsers()3001 void HInstruction::RemoveEnvironmentUsers() {
3002   for (const HUseListNode<HEnvironment*>& use : GetEnvUses()) {
3003     HEnvironment* user = use.GetUser();
3004     user->SetRawEnvAt(use.GetIndex(), nullptr);
3005   }
3006   env_uses_.clear();
3007 }
3008 
ReplaceInstrOrPhiByClone(HInstruction * instr)3009 HInstruction* ReplaceInstrOrPhiByClone(HInstruction* instr) {
3010   HInstruction* clone = instr->Clone(instr->GetBlock()->GetGraph()->GetAllocator());
3011   HBasicBlock* block = instr->GetBlock();
3012 
3013   if (instr->IsPhi()) {
3014     HPhi* phi = instr->AsPhi();
3015     DCHECK(!phi->HasEnvironment());
3016     HPhi* phi_clone = clone->AsPhi();
3017     block->ReplaceAndRemovePhiWith(phi, phi_clone);
3018   } else {
3019     block->ReplaceAndRemoveInstructionWith(instr, clone);
3020     if (instr->HasEnvironment()) {
3021       clone->CopyEnvironmentFrom(instr->GetEnvironment());
3022       HLoopInformation* loop_info = block->GetLoopInformation();
3023       if (instr->IsSuspendCheck() && loop_info != nullptr) {
3024         loop_info->SetSuspendCheck(clone->AsSuspendCheck());
3025       }
3026     }
3027   }
3028   return clone;
3029 }
3030 
3031 // Returns an instruction with the opposite Boolean value from 'cond'.
InsertOppositeCondition(HInstruction * cond,HInstruction * cursor)3032 HInstruction* HGraph::InsertOppositeCondition(HInstruction* cond, HInstruction* cursor) {
3033   ArenaAllocator* allocator = GetAllocator();
3034 
3035   if (cond->IsCondition() &&
3036       !DataType::IsFloatingPointType(cond->InputAt(0)->GetType())) {
3037     // Can't reverse floating point conditions.  We have to use HBooleanNot in that case.
3038     HInstruction* lhs = cond->InputAt(0);
3039     HInstruction* rhs = cond->InputAt(1);
3040     HInstruction* replacement = nullptr;
3041     switch (cond->AsCondition()->GetOppositeCondition()) {  // get *opposite*
3042       case kCondEQ: replacement = new (allocator) HEqual(lhs, rhs); break;
3043       case kCondNE: replacement = new (allocator) HNotEqual(lhs, rhs); break;
3044       case kCondLT: replacement = new (allocator) HLessThan(lhs, rhs); break;
3045       case kCondLE: replacement = new (allocator) HLessThanOrEqual(lhs, rhs); break;
3046       case kCondGT: replacement = new (allocator) HGreaterThan(lhs, rhs); break;
3047       case kCondGE: replacement = new (allocator) HGreaterThanOrEqual(lhs, rhs); break;
3048       case kCondB:  replacement = new (allocator) HBelow(lhs, rhs); break;
3049       case kCondBE: replacement = new (allocator) HBelowOrEqual(lhs, rhs); break;
3050       case kCondA:  replacement = new (allocator) HAbove(lhs, rhs); break;
3051       case kCondAE: replacement = new (allocator) HAboveOrEqual(lhs, rhs); break;
3052       default:
3053         LOG(FATAL) << "Unexpected condition";
3054         UNREACHABLE();
3055     }
3056     cursor->GetBlock()->InsertInstructionBefore(replacement, cursor);
3057     return replacement;
3058   } else if (cond->IsIntConstant()) {
3059     HIntConstant* int_const = cond->AsIntConstant();
3060     if (int_const->IsFalse()) {
3061       return GetIntConstant(1);
3062     } else {
3063       DCHECK(int_const->IsTrue()) << int_const->GetValue();
3064       return GetIntConstant(0);
3065     }
3066   } else {
3067     HInstruction* replacement = new (allocator) HBooleanNot(cond);
3068     cursor->GetBlock()->InsertInstructionBefore(replacement, cursor);
3069     return replacement;
3070   }
3071 }
3072 
operator <<(std::ostream & os,const MoveOperands & rhs)3073 std::ostream& operator<<(std::ostream& os, const MoveOperands& rhs) {
3074   os << "["
3075      << " source=" << rhs.GetSource()
3076      << " destination=" << rhs.GetDestination()
3077      << " type=" << rhs.GetType()
3078      << " instruction=";
3079   if (rhs.GetInstruction() != nullptr) {
3080     os << rhs.GetInstruction()->DebugName() << ' ' << rhs.GetInstruction()->GetId();
3081   } else {
3082     os << "null";
3083   }
3084   os << " ]";
3085   return os;
3086 }
3087 
operator <<(std::ostream & os,TypeCheckKind rhs)3088 std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs) {
3089   switch (rhs) {
3090     case TypeCheckKind::kUnresolvedCheck:
3091       return os << "unresolved_check";
3092     case TypeCheckKind::kExactCheck:
3093       return os << "exact_check";
3094     case TypeCheckKind::kClassHierarchyCheck:
3095       return os << "class_hierarchy_check";
3096     case TypeCheckKind::kAbstractClassCheck:
3097       return os << "abstract_class_check";
3098     case TypeCheckKind::kInterfaceCheck:
3099       return os << "interface_check";
3100     case TypeCheckKind::kArrayObjectCheck:
3101       return os << "array_object_check";
3102     case TypeCheckKind::kArrayCheck:
3103       return os << "array_check";
3104     default:
3105       LOG(FATAL) << "Unknown TypeCheckKind: " << static_cast<int>(rhs);
3106       UNREACHABLE();
3107   }
3108 }
3109 
operator <<(std::ostream & os,const MemBarrierKind & kind)3110 std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind) {
3111   switch (kind) {
3112     case MemBarrierKind::kAnyStore:
3113       return os << "AnyStore";
3114     case MemBarrierKind::kLoadAny:
3115       return os << "LoadAny";
3116     case MemBarrierKind::kStoreStore:
3117       return os << "StoreStore";
3118     case MemBarrierKind::kAnyAny:
3119       return os << "AnyAny";
3120     case MemBarrierKind::kNTStoreStore:
3121       return os << "NTStoreStore";
3122 
3123     default:
3124       LOG(FATAL) << "Unknown MemBarrierKind: " << static_cast<int>(kind);
3125       UNREACHABLE();
3126   }
3127 }
3128 
3129 }  // namespace art
3130