• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package com.android.tools.r8.ir.code;
5 
6 import com.android.tools.r8.errors.CompilationError;
7 import com.android.tools.r8.graph.DebugLocalInfo;
8 import com.android.tools.r8.graph.DexType;
9 import com.android.tools.r8.ir.conversion.DexBuilder;
10 import com.android.tools.r8.ir.conversion.IRBuilder;
11 import com.android.tools.r8.utils.CfgPrinter;
12 import com.android.tools.r8.utils.ListUtils;
13 import com.android.tools.r8.utils.StringUtils;
14 import com.android.tools.r8.utils.StringUtils.BraceType;
15 import com.google.common.collect.ImmutableList;
16 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.LinkedList;
23 import java.util.List;
24 import java.util.ListIterator;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28 import java.util.TreeSet;
29 import java.util.function.Consumer;
30 import java.util.function.Function;
31 
32 /**
33  * Basic block abstraction.
34  */
35 public class BasicBlock {
36 
37   private Int2ReferenceMap<DebugLocalInfo> localsAtEntry;
38 
setLocalsAtEntry(Int2ReferenceMap<DebugLocalInfo> localsAtEntry)39   public void setLocalsAtEntry(Int2ReferenceMap<DebugLocalInfo> localsAtEntry) {
40     this.localsAtEntry = localsAtEntry;
41   }
42 
getLocalsAtEntry()43   public Int2ReferenceMap<DebugLocalInfo> getLocalsAtEntry() {
44     return localsAtEntry;
45   }
46 
47   public enum ThrowingInfo {
48     NO_THROW, CAN_THROW
49   }
50 
51   public enum EdgeType {
52     NON_EDGE,
53     NORMAL,
54     EXCEPTIONAL
55   }
56 
57   public static class Pair implements Comparable<Pair> {
58 
59     public BasicBlock first;
60     public BasicBlock second;
61 
Pair(BasicBlock first, BasicBlock second)62     public Pair(BasicBlock first, BasicBlock second) {
63       this.first = first;
64       this.second = second;
65     }
66 
67     @Override
compareTo(Pair o)68     public int compareTo(Pair o) {
69       if (first != o.first) {
70         return first.getNumber() - o.first.getNumber();
71       }
72       if (second != o.second) {
73         return second.getNumber() - o.second.getNumber();
74       }
75       return 0;
76     }
77   }
78 
79   private final List<BasicBlock> successors = new ArrayList<>();
80   private final List<BasicBlock> predecessors = new ArrayList<>();
81 
82   // Catch handler information about which successors are catch handlers and what their guards are.
83   private CatchHandlers<Integer> catchHandlers = CatchHandlers.EMPTY_INDICES;
84 
85   private LinkedList<Instruction> instructions = new LinkedList<>();
86   private int number = -1;
87   private List<Phi> phis = new ArrayList<>();
88 
89   // State used during SSA construction. The SSA construction is based on the paper:
90   //
91   // "Simple and Efficient Construction of Static Single Assignment Form"
92   // http://compilers.cs.uni-saarland.de/papers/bbhlmz13cc.pdf
93   //
94   // A basic block is filled when local value numbering is complete for that block.
95   // A basic block is sealed when all predecessor blocks have been filled.
96   //
97   // Therefore, for a sealed block we can always search backwards to find reaching values
98   // in predecessor blocks.
99   private boolean filled = false;
100   private boolean sealed = false;
101   private Map<Integer, Phi> incompletePhis = new HashMap<>();
102   private int estimatedPredecessorsCount = 0;
103   private int unfilledPredecessorsCount = 0;
104 
105   // State used for basic block sorting and tracing.
106   private int color = 0;
107 
108   // Map of registers to current SSA value. Used during SSA numbering and cleared once filled.
109   private Map<Integer, Value> currentDefinitions = new HashMap<>();
110 
getSuccessors()111   public List<BasicBlock> getSuccessors() {
112     return successors;
113   }
114 
getNormalSucessors()115   public List<BasicBlock> getNormalSucessors() {
116     if (!hasCatchHandlers()) {
117       return successors;
118     }
119     Set<Integer> handlers = catchHandlers.getUniqueTargets();
120     ImmutableList.Builder<BasicBlock> normals = ImmutableList.builder();
121     for (int i = 0; i < successors.size(); i++) {
122       if (!handlers.contains(i)) {
123         normals.add(successors.get(i));
124       }
125     }
126     return normals.build();
127   }
128 
getPredecessors()129   public List<BasicBlock> getPredecessors() {
130     return predecessors;
131   }
132 
getNormalPredecessors()133   public List<BasicBlock> getNormalPredecessors() {
134     ImmutableList.Builder<BasicBlock> normals = ImmutableList.builder();
135     for (BasicBlock predecessor : predecessors) {
136       if (!predecessor.hasCatchSuccessor(this)) {
137         normals.add(predecessor);
138       }
139     }
140     return normals.build();
141   }
142 
removeSuccessor(BasicBlock block)143   public void removeSuccessor(BasicBlock block) {
144     int index = successors.indexOf(block);
145     assert index >= 0 : "removeSuccessor did not find the successor to remove";
146     removeSuccessorsByIndex(Arrays.asList(index));
147   }
148 
removePredecessor(BasicBlock block)149   public void removePredecessor(BasicBlock block) {
150     int index = predecessors.indexOf(block);
151     assert index >= 0 : "removePredecessor did not find the predecessor to remove";
152     predecessors.remove(index);
153     if (phis != null) {
154       for (Phi phi : getPhis()) {
155         phi.removeOperand(index);
156       }
157       // Collect and remove trivial phis after block removal.
158       List<Phi> trivials = new ArrayList<>();
159       for (Phi phi : getPhis()) {
160         if (phi.isTrivialPhi()) {
161           trivials.add(phi);
162         }
163       }
164       for (Phi phi : trivials) {
165         phi.removeTrivialPhi();
166       }
167     }
168   }
169 
swapSuccessors(int x, int y)170   private void swapSuccessors(int x, int y) {
171     assert x != y;
172     if (hasCatchHandlers()) {
173       List<Integer> targets = new ArrayList<>(catchHandlers.getAllTargets());
174       for (int i = 0; i < targets.size(); i++) {
175         if (targets.get(i) == x) {
176           targets.set(i, y);
177         } else if (targets.get(i) == y) {
178           targets.set(i, x);
179         }
180       }
181       catchHandlers = new CatchHandlers<>(catchHandlers.getGuards(), targets);
182     }
183     BasicBlock tmp = successors.get(x);
184     successors.set(x, successors.get(y));
185     successors.set(y, tmp);
186   }
187 
replaceSuccessor(BasicBlock block, BasicBlock newBlock)188   public void replaceSuccessor(BasicBlock block, BasicBlock newBlock) {
189     assert successors.contains(block) : "attempt to replace non-existent successor";
190 
191     if (successors.contains(newBlock)) {
192       int indexOfOldBlock = successors.indexOf(block);
193       int indexOfNewBlock = successors.indexOf(newBlock);
194 
195       // Always rewrite catch handlers.
196       if (hasCatchHandlers()) {
197         List<Integer> targets = new ArrayList<>(catchHandlers.getAllTargets());
198         for (int i = 0; i < targets.size(); i++) {
199           if (targets.get(i) == indexOfOldBlock) {
200             targets.set(i, indexOfNewBlock);
201           }
202           if (targets.get(i) > indexOfOldBlock) {
203             targets.set(i, targets.get(i) - 1);
204           }
205         }
206         catchHandlers = new CatchHandlers<>(catchHandlers.getGuards(), targets);
207       }
208 
209       // Check if the replacement influences jump targets and rewrite as needed.
210       if (exit().isGoto()) {
211         if (indexOfOldBlock == successors.size() - 1 && indexOfNewBlock != successors.size() - 2) {
212           // Replacing the goto target and the new block will not become the goto target.
213           // We perform a swap to get the new block into the goto target position.
214           swapSuccessors(indexOfOldBlock - 1, indexOfNewBlock);
215         }
216       } else if (exit().isIf()) {
217         if (indexOfNewBlock >= successors.size() - 2 && indexOfOldBlock >= successors.size() - 2) {
218           // New and old are true target and fallthrough, replace last instruction with a goto.
219           Instruction instruction = getInstructions().removeLast();
220           for (Value value : instruction.inValues()) {
221             if (value.hasUsersInfo()) {
222               value.removeUser(instruction);
223             }
224           }
225           Instruction exit = new Goto();
226           exit.setBlock(this);
227           getInstructions().addLast(exit);
228         } else if (indexOfOldBlock >= successors.size() - 2) {
229           // Old is either true or fallthrough and we need to swap the new block into the right
230           // position to become that target.
231           swapSuccessors(indexOfOldBlock - 1, indexOfNewBlock);
232         }
233       } else if (exit().isSwitch()) {
234         // Rewrite fallthrough and case target indices.
235         Switch exit = exit().asSwitch();
236         if (exit.getFallthroughBlockIndex() == indexOfOldBlock) {
237           exit.setFallthroughBlockIndex(indexOfNewBlock);
238         }
239         if (exit.getFallthroughBlockIndex() > indexOfOldBlock) {
240           exit.setFallthroughBlockIndex(exit.getFallthroughBlockIndex() - 1);
241         }
242         int[] indices = exit.targetBlockIndices();
243         for (int i = 0; i < indices.length; i++) {
244           if (indices[i] == indexOfOldBlock) {
245             indices[i] = indexOfNewBlock;
246           }
247           if (indices[i] > indexOfOldBlock) {
248             indices[i] = indices[i] - 1;
249           }
250         }
251       }
252 
253       // Remove the replaced successor.
254       boolean removed = successors.remove(block);
255       assert removed;
256     } else {
257       // If the new block is not a successor we don't have to rewrite indices or instructions
258       // and we can just replace the old successor with the new one.
259       for (int i = 0; i < successors.size(); i++) {
260         if (successors.get(i) == block) {
261           successors.set(i, newBlock);
262           return;
263         }
264       }
265     }
266   }
267 
replacePredecessor(BasicBlock block, BasicBlock newBlock)268   public void replacePredecessor(BasicBlock block, BasicBlock newBlock) {
269     for (int i = 0; i < predecessors.size(); i++) {
270       if (predecessors.get(i) == block) {
271         predecessors.set(i, newBlock);
272         return;
273       }
274     }
275     assert false : "replaceSuccessor did not find the predecessor to replace";
276   }
277 
swapSuccessorsByIndex(int index1, int index2)278   public void swapSuccessorsByIndex(int index1, int index2) {
279     BasicBlock t = successors.get(index1);
280     successors.set(index1, successors.get(index2));
281     successors.set(index2, t);
282   }
283 
removeSuccessorsByIndex(List<Integer> successorsToRemove)284   public void removeSuccessorsByIndex(List<Integer> successorsToRemove) {
285     if (successorsToRemove.isEmpty()) {
286       return;
287     }
288     List<BasicBlock> copy = new ArrayList<>(successors);
289     successors.clear();
290     int current = 0;
291     for (int i : successorsToRemove) {
292       successors.addAll(copy.subList(current, i));
293       current = i + 1;
294     }
295     successors.addAll(copy.subList(current, copy.size()));
296 
297     if (hasCatchHandlers()) {
298       int size = catchHandlers.size();
299       List<DexType> guards = new ArrayList<>(size);
300       List<Integer> targets = new ArrayList<>(size);
301       current = 0;
302       for (int i = 0; i < catchHandlers.getAllTargets().size(); i++) {
303         if (successorsToRemove.contains(catchHandlers.getAllTargets().get(i))) {
304           guards.addAll(catchHandlers.getGuards().subList(current, i));
305           targets.addAll(catchHandlers.getAllTargets().subList(current, i));
306           current = i + 1;
307         }
308       }
309       if (guards.isEmpty()) {
310         catchHandlers = CatchHandlers.EMPTY_INDICES;
311       } else {
312         catchHandlers = new CatchHandlers<>(guards, targets);
313       }
314     }
315   }
316 
removePredecessorsByIndex(List<Integer> predecessorsToRemove)317   public void removePredecessorsByIndex(List<Integer> predecessorsToRemove) {
318     if (predecessorsToRemove.isEmpty()) {
319       return;
320     }
321     List<BasicBlock> copy = new ArrayList<>(predecessors);
322     predecessors.clear();
323     int current = 0;
324     for (int i : predecessorsToRemove) {
325       predecessors.addAll(copy.subList(current, i));
326       current = i + 1;
327     }
328     predecessors.addAll(copy.subList(current, copy.size()));
329   }
330 
removePhisByIndex(List<Integer> predecessorsToRemove)331   public void removePhisByIndex(List<Integer> predecessorsToRemove) {
332     for (Phi phi : phis) {
333       phi.removeOperandsByIndex(predecessorsToRemove);
334     }
335   }
336 
getPhis()337   public List<Phi> getPhis() {
338     return phis;
339   }
340 
setPhis(List<Phi> phis)341   public void setPhis(List<Phi> phis) {
342     this.phis = phis;
343   }
344 
isFilled()345   public boolean isFilled() {
346     return filled;
347   }
348 
setFilledForTesting()349   void setFilledForTesting() {
350     filled = true;
351   }
352 
hasCatchHandlers()353   public boolean hasCatchHandlers() {
354     assert catchHandlers != null;
355     return !catchHandlers.isEmpty();
356   }
357 
getNumber()358   public int getNumber() {
359     assert number >= 0;
360     return number;
361   }
362 
setNumber(int number)363   public void setNumber(int number) {
364     assert number >= 0;
365     this.number = number;
366   }
367 
getInstructions()368   public LinkedList<Instruction> getInstructions() {
369     return instructions;
370   }
371 
entry()372   public Instruction entry() {
373     return instructions.get(0);
374   }
375 
exit()376   public JumpInstruction exit() {
377     assert filled;
378     assert instructions.get(instructions.size() - 1).isJumpInstruction();
379     return instructions.get(instructions.size() - 1).asJumpInstruction();
380   }
381 
clearUserInfo()382   public void clearUserInfo() {
383     phis = null;
384     instructions.forEach(Instruction::clearUserInfo);
385   }
386 
buildDex(DexBuilder builder)387   public void buildDex(DexBuilder builder) {
388     for (Instruction instruction : instructions) {
389       instruction.buildDex(builder);
390     }
391   }
392 
mark()393   public void mark() {
394     assert color == 0;
395     color = 1;
396   }
397 
clearMark()398   public void clearMark() {
399     color = 0;
400   }
401 
isMarked()402   public boolean isMarked() {
403     return color == 1;
404   }
405 
setColor(int color)406   public void setColor(int color) {
407     this.color = color;
408   }
409 
getColor()410   public int getColor() {
411     return color;
412   }
413 
hasColor(int color)414   public boolean hasColor(int color) {
415     return this.color == color;
416   }
417 
incrementUnfilledPredecessorCount()418   public void incrementUnfilledPredecessorCount() {
419     ++unfilledPredecessorsCount;
420     ++estimatedPredecessorsCount;
421   }
422 
decrementUnfilledPredecessorCount(int n)423   public void decrementUnfilledPredecessorCount(int n) {
424     unfilledPredecessorsCount -= n;
425     estimatedPredecessorsCount -= n;
426   }
427 
decrementUnfilledPredecessorCount()428   public void decrementUnfilledPredecessorCount() {
429     --unfilledPredecessorsCount;
430     --estimatedPredecessorsCount;
431   }
432 
verifyFilledPredecessors()433   public boolean verifyFilledPredecessors() {
434     assert estimatedPredecessorsCount == predecessors.size();
435     assert unfilledPredecessorsCount == 0;
436     return true;
437   }
438 
addPhi(Phi phi)439   public void addPhi(Phi phi) {
440     phis.add(phi);
441   }
442 
removePhi(Phi phi)443   public void removePhi(Phi phi) {
444     phis.remove(phi);
445   }
446 
add(Instruction next)447   public void add(Instruction next) {
448     assert !isFilled();
449     instructions.add(next);
450     next.setBlock(this);
451   }
452 
close(IRBuilder builder)453   public void close(IRBuilder builder) {
454     assert !isFilled();
455     assert !instructions.isEmpty();
456     filled = true;
457     sealed = unfilledPredecessorsCount == 0;
458     assert exit().isJumpInstruction();
459     assert verifyNoValuesAfterThrowingInstruction();
460     for (BasicBlock successor : successors) {
461       successor.filledPredecessor(builder);
462     }
463   }
464 
link(BasicBlock successor)465   public void link(BasicBlock successor) {
466     assert !successors.contains(successor);
467     assert !successor.predecessors.contains(this);
468     successors.add(successor);
469     successor.predecessors.add(this);
470   }
471 
allPredecessorsDominated(BasicBlock block, DominatorTree dominator)472   private boolean allPredecessorsDominated(BasicBlock block, DominatorTree dominator) {
473     for (BasicBlock pred : block.predecessors) {
474       if (!dominator.dominatedBy(pred, block)) {
475         return false;
476       }
477     }
478     return true;
479   }
480 
blocksClean(List<BasicBlock> blocks)481   private boolean blocksClean(List<BasicBlock> blocks) {
482     blocks.forEach((b) -> {
483       assert b.predecessors.size() == 0;
484       assert b.successors.size() == 0;
485     });
486     return true;
487   }
488 
489   /**
490    * Unlinks this block from a single predecessor.
491    *
492    * @return returns the unlinked predecessor.
493    */
unlinkSinglePredecessor()494   public BasicBlock unlinkSinglePredecessor() {
495     assert predecessors.size() == 1;
496     assert predecessors.get(0).successors.size() == 1;
497     BasicBlock unlinkedBlock = predecessors.get(0);
498     predecessors.get(0).successors.clear();
499     predecessors.clear();
500     return unlinkedBlock;
501   }
502 
503   /**
504    * Unlinks this block from a single normal successor.
505    *
506    * @return Returns the unlinked successor.
507    */
unlinkSingleSuccessor()508   public BasicBlock unlinkSingleSuccessor() {
509     assert !hasCatchHandlers();
510     assert successors.size() == 1;
511     assert successors.get(0).predecessors.size() == 1;
512     BasicBlock unlinkedBlock = successors.get(0);
513     successors.get(0).predecessors.clear();
514     successors.clear();
515     return unlinkedBlock;
516   }
517 
518   /**
519    * Unlinks this block from a single predecessor and successor.
520    *
521    * @return Returns the unlinked successor
522    */
unlinkSingle()523   public BasicBlock unlinkSingle() {
524     unlinkSinglePredecessor();
525     return unlinkSingleSuccessor();
526   }
527 
unlink(BasicBlock successor, DominatorTree dominator)528   public List<BasicBlock> unlink(BasicBlock successor, DominatorTree dominator) {
529     assert successors.contains(successor);
530     assert successor.predecessors.contains(this);
531     List<BasicBlock> removedBlocks = new ArrayList<>();
532     TreeSet<Pair> worklist = new TreeSet<>();
533     worklist.add(new Pair(this, successor));
534     while (!worklist.isEmpty()) {
535       Pair pair = worklist.pollFirst();
536       BasicBlock pred = pair.first;
537       BasicBlock succ = pair.second;
538       assert pred.successors.contains(succ);
539       assert succ.predecessors.contains(pred);
540       int size = pred.successors.size();
541       pred.removeSuccessor(succ);
542       assert size == pred.successors.size() + 1;
543       size = succ.predecessors.size();
544       succ.removePredecessor(pred);
545       assert size == succ.predecessors.size() + 1;
546       // A predecessor has been removed. If all remaining predecessors are dominated by this block
547       // schedule it for removal, as it is no longer reachable.
548       if (allPredecessorsDominated(succ, dominator)) {
549         removedBlocks.add(succ);
550         for (BasicBlock block : succ.successors) {
551           worklist.add(new Pair(succ, block));
552         }
553         for (Instruction instruction : succ.getInstructions()) {
554           for (Value value : instruction.inValues) {
555             value.removeUser(instruction);
556           }
557           for (Value value : instruction.getDebugValues()) {
558             value.removeDebugUser(instruction);
559           }
560           Value previousLocalValue = instruction.getPreviousLocalValue();
561           if (previousLocalValue != null) {
562             previousLocalValue.removeDebugUser(instruction);
563           }
564         }
565       }
566     }
567     assert blocksClean(removedBlocks);
568     return removedBlocks;
569   }
570 
linkCatchSuccessors(List<DexType> guards, List<BasicBlock> targets)571   public void linkCatchSuccessors(List<DexType> guards, List<BasicBlock> targets) {
572     List<Integer> successorIndexes = new ArrayList<>(targets.size());
573     for (BasicBlock target : targets) {
574       int index = successors.indexOf(target);
575       if (index < 0) {
576         index = successors.size();
577         link(target);
578       }
579       successorIndexes.add(index);
580     }
581     catchHandlers = new CatchHandlers<>(guards, successorIndexes);
582   }
583 
clearCurrentDefinitions()584   public void clearCurrentDefinitions() {
585     currentDefinitions = null;
586     for (Phi phi : getPhis()) {
587       phi.clearDefinitionsUsers();
588     }
589   }
590 
591   // The proper incoming register for a catch successor (that is otherwise shadowed by the out-value
592   // of a throwing instruction) is stored at the negative register-index in the definitions map.
593   // (See readCurrentDefinition/writeCurrentDefinition/updateCurrentDefinition).
onThrowValueRegister(int register)594   private int onThrowValueRegister(int register) {
595     return -(register + 1);
596   }
597 
readOnThrowValue(int register, EdgeType readingEdge)598   private Value readOnThrowValue(int register, EdgeType readingEdge) {
599     if (readingEdge == EdgeType.EXCEPTIONAL) {
600       return currentDefinitions.get(onThrowValueRegister(register));
601     }
602     return null;
603   }
604 
isOnThrowValue(int register, EdgeType readingEdge)605   private boolean isOnThrowValue(int register, EdgeType readingEdge) {
606     return readOnThrowValue(register, readingEdge) != null;
607   }
608 
readCurrentDefinition(int register, EdgeType readingEdge)609   public Value readCurrentDefinition(int register, EdgeType readingEdge) {
610     // If the block reading the current definition is a catch successor, then we must return the
611     // previous value of the throwing-instructions outgoing register if any.
612     Value result = readOnThrowValue(register, readingEdge);
613     if (result != null) {
614       return result == Value.UNDEFINED ? null : result;
615     }
616     return currentDefinitions.get(register);
617   }
618 
updateCurrentDefinition(int register, Value value, EdgeType readingEdge)619   public void updateCurrentDefinition(int register, Value value, EdgeType readingEdge) {
620     // If the reading/writing block is a catch successor, possibly update the on-throw value.
621     if (isOnThrowValue(register, readingEdge)) {
622       register = onThrowValueRegister(register);
623     }
624     // We keep track of all users of phis so that we can update all users during
625     // trivial phi elimination. We only rewrite phi values during IR construction, so
626     // we only need to record definition users for phis.
627     Value previousValue = currentDefinitions.get(register);
628     if (value.isPhi()) {
629       value.asPhi().addDefinitionsUser(currentDefinitions);
630     }
631     assert verifyOnThrowWrite(register);
632     currentDefinitions.put(register, value);
633     // We have replaced one occurrence of value in currentDefinitions. There could be
634     // other occurrences. We only remove currentDefinitions from the set of users
635     // of the phi if we have removed all occurrences.
636     if (previousValue != null &&
637         previousValue.isPhi() &&
638         !currentDefinitions.values().contains(previousValue)) {
639       previousValue.asPhi().removeDefinitionsUser(currentDefinitions);
640     }
641   }
642 
writeCurrentDefinition(int register, Value value, ThrowingInfo throwing)643   public void writeCurrentDefinition(int register, Value value, ThrowingInfo throwing) {
644     // If this write is dependent on not throwing, we move the existing value to its negative index
645     // so that it can be read by catch successors.
646     if (throwing == ThrowingInfo.CAN_THROW) {
647       Value previous = currentDefinitions.get(register);
648       assert verifyOnThrowWrite(register);
649       currentDefinitions.put(onThrowValueRegister(register),
650           previous == null ? Value.UNDEFINED : previous);
651     }
652     updateCurrentDefinition(register, value, EdgeType.NON_EDGE);
653   }
654 
filledPredecessor(IRBuilder builder)655   public void filledPredecessor(IRBuilder builder) {
656     assert unfilledPredecessorsCount > 0;
657     if (--unfilledPredecessorsCount == 0) {
658       assert estimatedPredecessorsCount == predecessors.size();
659       for (Entry<Integer, Phi> entry : incompletePhis.entrySet()) {
660         int register = entry.getKey();
661         if (register < 0) {
662           register = onThrowValueRegister(register);
663         }
664         entry.getValue().addOperands(builder, register);
665       }
666       sealed = true;
667       incompletePhis.clear();
668     }
669   }
670 
getEdgeType(BasicBlock successor)671   public EdgeType getEdgeType(BasicBlock successor) {
672     assert successors.indexOf(successor) >= 0;
673     return hasCatchSuccessor(successor) ? EdgeType.EXCEPTIONAL : EdgeType.NORMAL;
674   }
675 
hasCatchSuccessor(BasicBlock block)676   public boolean hasCatchSuccessor(BasicBlock block) {
677     if (!hasCatchHandlers()) {
678       return false;
679     }
680     return catchHandlers.getAllTargets().contains(successors.indexOf(block));
681   }
682 
guardsForCatchSuccessor(BasicBlock block)683   public int guardsForCatchSuccessor(BasicBlock block) {
684     assert hasCatchSuccessor(block);
685     int index = successors.indexOf(block);
686     int count = 0;
687     for (int handler : catchHandlers.getAllTargets()) {
688       if (handler == index) {
689         count++;
690       }
691     }
692     assert count > 0;
693     return count;
694   }
695 
isSealed()696   public boolean isSealed() {
697     return sealed;
698   }
699 
addIncompletePhi(int register, Phi phi, EdgeType readingEdge)700   public void addIncompletePhi(int register, Phi phi, EdgeType readingEdge) {
701     if (isOnThrowValue(register, readingEdge)) {
702       register = onThrowValueRegister(register);
703     }
704     assert !incompletePhis.containsKey(register);
705     incompletePhis.put(register, phi);
706   }
707 
hasIncompletePhis()708   public boolean hasIncompletePhis() {
709     return !incompletePhis.isEmpty();
710   }
711 
getIncompletePhiRegisters()712   public Collection<Integer> getIncompletePhiRegisters() {
713     return incompletePhis.keySet();
714   }
715 
appendBasicBlockList( StringBuilder builder, List<BasicBlock> list, Function<BasicBlock, String> postfix)716   private void appendBasicBlockList(
717       StringBuilder builder, List<BasicBlock> list, Function<BasicBlock, String> postfix) {
718     if (list.size() > 0) {
719       for (BasicBlock block : list) {
720         builder.append(block.number >= 0 ? block.number : "<unknown>");
721         builder.append(postfix.apply(block));
722         builder.append(" ");
723       }
724     } else {
725       builder.append("-");
726     }
727   }
728 
729   @Override
toString()730   public String toString() {
731     return toDetailedString();
732   }
733 
toSimpleString()734   public String toSimpleString() {
735     return number < 0 ? super.toString() : ("block " + number);
736   }
737 
predecessorPostfix(BasicBlock block)738   private String predecessorPostfix(BasicBlock block) {
739     if (hasCatchSuccessor(block)) {
740       return new String(new char[guardsForCatchSuccessor(block)]).replace("\0", "*");
741     }
742     return "";
743   }
744 
toDetailedString()745   public String toDetailedString() {
746     StringBuilder builder = new StringBuilder();
747     builder.append("block ");
748     builder.append(number);
749     builder.append(" (");
750     builder.append(System.identityHashCode(this));
751     builder.append(")");
752     builder.append(", pred-counts: " + predecessors.size());
753     if (unfilledPredecessorsCount > 0) {
754       builder.append(" (" + unfilledPredecessorsCount + " unfilled)");
755     }
756     builder.append(", succ-count: " + successors.size());
757     builder.append(", filled: " + isFilled());
758     builder.append(", sealed: " + isSealed());
759     builder.append("\n");
760     builder.append("predecessors: ");
761     appendBasicBlockList(builder, predecessors, b -> "");
762     builder.append("\n");
763     builder.append("successors: ");
764     appendBasicBlockList(builder, successors, this::predecessorPostfix);
765     if (successors.size() > 0) {
766       builder.append(" (");
767       if (hasCatchHandlers()) {
768         builder.append(catchHandlers.size());
769       } else {
770         builder.append("no");
771       }
772       builder.append(" try/catch successors)");
773     }
774     builder.append("\n");
775     if (phis != null && phis.size() > 0) {
776       for (Phi phi : phis) {
777         builder.append(phi.printPhi());
778         if (incompletePhis.values().contains(phi)) {
779           builder.append(" (incomplete)");
780         }
781         builder.append("\n");
782       }
783     } else {
784       builder.append("no phis\n");
785     }
786     if (localsAtEntry != null) {
787       builder.append("locals: ");
788       StringUtils.append(builder, localsAtEntry.int2ReferenceEntrySet(), ", ", BraceType.NONE);
789       builder.append("\n");
790     }
791     for (Instruction instruction : instructions) {
792       StringUtils.appendLeftPadded(builder, Integer.toString(instruction.getNumber()), 6);
793       builder.append(": ");
794       StringUtils.appendRightPadded(builder, instruction.toString(), 20);
795       builder.append("\n");
796     }
797     return builder.toString();
798   }
799 
print(CfgPrinter printer)800   public void print(CfgPrinter printer) {
801     printer.begin("block");
802     printer.print("name \"B").append(number).append("\"\n");
803     printer.print("from_bci -1\n");
804     printer.print("to_bci -1\n");
805     printer.print("predecessors");
806     printBlockList(printer, predecessors);
807     printer.ln();
808     printer.print("successors");
809     printBlockList(printer, successors);
810     printer.ln();
811     printer.print("xhandlers\n");
812     printer.print("flags\n");
813     printer.print("first_lir_id ").print(instructions.get(0).getNumber()).ln();
814     printer.print("last_lir_id ").print(instructions.get(instructions.size() - 1).getNumber()).ln();
815     printer.begin("HIR");
816     if (phis != null) {
817       for (Phi phi : phis) {
818         phi.print(printer);
819         printer.append(" <|@\n");
820       }
821     }
822     for (Instruction instruction : instructions) {
823       instruction.print(printer);
824       printer.append(" <|@\n");
825     }
826     printer.end("HIR");
827     printer.begin("LIR");
828     for (Instruction instruction : instructions) {
829       instruction.printLIR(printer);
830       printer.append(" <|@\n");
831     }
832     printer.end("LIR");
833     printer.end("block");
834   }
835 
printBlockList(CfgPrinter printer, List<BasicBlock> blocks)836   private static void printBlockList(CfgPrinter printer, List<BasicBlock> blocks) {
837     for (BasicBlock block : blocks) {
838       printer.append(" \"B").append(block.number).append("\"");
839     }
840   }
841 
addPhiMove(Move move)842   public void addPhiMove(Move move) {
843     // TODO(ager): Consider this more, is it always the case that we should add it before the
844     // exit instruction?
845     Instruction branch = exit();
846     instructions.set(instructions.size() - 1, move);
847     instructions.add(branch);
848   }
849 
setInstructions(LinkedList<Instruction> instructions)850   public void setInstructions(LinkedList<Instruction> instructions) {
851     this.instructions = instructions;
852   }
853 
854   /**
855    * Remove a number of instructions. The instructions to remove are given as indexes in the
856    * instruction stream.
857    */
removeInstructions(List<Integer> toRemove)858   public void removeInstructions(List<Integer> toRemove) {
859     if (!toRemove.isEmpty()) {
860       LinkedList<Instruction> newInstructions = new LinkedList<>();
861       int nextIndex = 0;
862       for (Integer index : toRemove) {
863         assert index >= nextIndex;  // Indexes in toRemove must be sorted ascending.
864         newInstructions.addAll(instructions.subList(nextIndex, index));
865         instructions.get(index).clearBlock();
866         nextIndex = index + 1;
867       }
868       if (nextIndex < instructions.size()) {
869         newInstructions.addAll(instructions.subList(nextIndex, instructions.size()));
870       }
871       assert instructions.size() == newInstructions.size() + toRemove.size();
872       setInstructions(newInstructions);
873     }
874   }
875 
876   /**
877    * Remove an instruction.
878    */
removeInstruction(Instruction toRemove)879   public void removeInstruction(Instruction toRemove) {
880     int index = instructions.indexOf(toRemove);
881     assert index >= 0;
882     removeInstructions(Collections.singletonList(index));
883   }
884 
885   /**
886    * Create a new basic block with a single goto instruction.
887    *
888    * <p>The constructed basic block has no predecessors and has one
889    * successors which is the target block.
890    *
891    * @param target the target of the goto block
892    * @param blockNumber the block number of the goto block
893    */
createGotoBlock(BasicBlock target, int blockNumber)894   public static BasicBlock createGotoBlock(BasicBlock target, int blockNumber) {
895     BasicBlock block = createGotoBlock(blockNumber);
896     block.getSuccessors().add(target);
897     return block;
898   }
899 
900   /**
901    * Create a new basic block with a single goto instruction.
902    *
903    * <p>The constructed basic block has no predecessors and no successors.
904    *
905    * @param blockNumber the block number of the goto block
906    */
createGotoBlock(int blockNumber)907   public static BasicBlock createGotoBlock(int blockNumber) {
908     BasicBlock block = new BasicBlock();
909     block.add(new Goto());
910     block.close(null);
911     block.setNumber(blockNumber);
912     return block;
913   }
914 
915   /**
916    * Create a new basic block with a single if instruction.
917    *
918    * <p>The constructed basic block has no predecessors and no successors.
919    *
920    * @param blockNumber the block number of the goto block
921    */
createIfBlock(int blockNumber, If theIf)922   public static BasicBlock createIfBlock(int blockNumber, If theIf) {
923     BasicBlock block = new BasicBlock();
924     block.add(theIf);
925     block.close(null);
926     block.setNumber(blockNumber);
927     return block;
928   }
929 
isTrivialGoto()930   public boolean isTrivialGoto() {
931     return instructions.size() == 1 && exit().isGoto();
932   }
933 
hasOneNormalExit()934   public boolean hasOneNormalExit() {
935     return successors.size() == 1 && exit().isGoto();
936   }
937 
getCatchHandlers()938   public CatchHandlers<BasicBlock> getCatchHandlers() {
939     if (!hasCatchHandlers()) {
940       return CatchHandlers.EMPTY_BASIC_BLOCK;
941     }
942     List<BasicBlock> targets = ListUtils.map(catchHandlers.getAllTargets(), successors::get);
943     return new CatchHandlers<>(catchHandlers.getGuards(), targets);
944   }
945 
getCatchHandlersWithSuccessorIndexes()946   public CatchHandlers<Integer> getCatchHandlersWithSuccessorIndexes() {
947     return catchHandlers;
948   }
949 
clearCatchHandlers()950   public void clearCatchHandlers() {
951     catchHandlers = CatchHandlers.EMPTY_INDICES;
952   }
953 
transferCatchHandlers(BasicBlock other)954   public void transferCatchHandlers(BasicBlock other) {
955     catchHandlers = other.catchHandlers;
956     other.catchHandlers = CatchHandlers.EMPTY_INDICES;
957   }
958 
canThrow()959   public boolean canThrow() {
960     for (Instruction instruction : instructions) {
961       if (instruction.instructionTypeCanThrow()) {
962         return true;
963       }
964     }
965     return false;
966   }
967 
968   // A block can have at most one "on throw" value.
verifyOnThrowWrite(int register)969   private boolean verifyOnThrowWrite(int register) {
970     if (register >= 0) {
971       return true;
972     }
973     for (Integer other : currentDefinitions.keySet()) {
974       assert other >= 0 || other == register;
975     }
976     return true;
977   }
978 
979   // Verify that if this block has a throwing instruction none of the following instructions may
980   // introduce an SSA value. Such values can lead to invalid uses since the values are not actually
981   // visible to exceptional successors.
verifyNoValuesAfterThrowingInstruction()982   private boolean verifyNoValuesAfterThrowingInstruction() {
983     if (hasCatchHandlers()) {
984       ListIterator<Instruction> iterator = listIterator(instructions.size());
985       while (iterator.hasPrevious()) {
986         Instruction instruction = iterator.previous();
987         if (instruction.instructionTypeCanThrow()) {
988           return true;
989         }
990         assert instruction.outValue() == null;
991       }
992     }
993     return true;
994   }
995 
iterator()996   public InstructionIterator iterator() {
997     return new BasicBlockInstructionIterator(this);
998   }
999 
listIterator()1000   public InstructionListIterator listIterator() {
1001     return new BasicBlockInstructionIterator(this);
1002   }
1003 
listIterator(int index)1004   public InstructionListIterator listIterator(int index) {
1005     return new BasicBlockInstructionIterator(this, index);
1006   }
1007 
1008   /**
1009    * Creates an instruction list iterator starting at <code>instruction</code>.
1010    *
1011    * The cursor will be positioned after <code>instruction</code>. Calling <code>next</code> on
1012    * the returned iterator will return the instruction after <code>instruction</code>. Calling
1013    * <code>previous</code> will return <code>instruction</code>.
1014    */
listIterator(Instruction instruction)1015   public InstructionListIterator listIterator(Instruction instruction) {
1016     return new BasicBlockInstructionIterator(this, instruction);
1017   }
1018 
1019   /**
1020    * Creates a new empty block as a successor for this block.
1021    *
1022    * The new block will have all the normal successors of the original block.
1023    *
1024    * The catch successors are either on the original block or the new block depending on the
1025    * value of <code>keepCatchHandlers</code>.
1026    *
1027    * The current block still has all the instructions, and the new block is empty instruction-wise.
1028    *
1029    * @param blockNumber block number for new block
1030    * @param keepCatchHandlers keep catch successors on the original block
1031    * @return the new block
1032    */
createSplitBlock(int blockNumber, boolean keepCatchHandlers)1033   BasicBlock createSplitBlock(int blockNumber, boolean keepCatchHandlers) {
1034     boolean hadCatchHandlers = hasCatchHandlers();
1035     BasicBlock newBlock = new BasicBlock();
1036     newBlock.setNumber(blockNumber);
1037 
1038     // Copy all successors including catch handlers to the new block, and update predecessors.
1039     successors.forEach(newBlock.successors::add);
1040     for (BasicBlock successor : newBlock.getSuccessors()) {
1041       successor.replacePredecessor(this, newBlock);
1042     }
1043     successors.clear();
1044     newBlock.catchHandlers = catchHandlers;
1045     catchHandlers = CatchHandlers.EMPTY_INDICES;
1046 
1047     // If the catch handlers should be kept on the original block move them back.
1048     if (keepCatchHandlers && hadCatchHandlers) {
1049       moveCatchHandlers(newBlock);
1050     }
1051 
1052     // Link the two blocks
1053     link(newBlock);
1054 
1055     // Mark the new block filled and sealed.
1056     newBlock.filled = true;
1057     newBlock.sealed = true;
1058 
1059     return newBlock;
1060   }
1061 
1062   /**
1063    * Moves catch successors from `fromBlock` into this block.
1064    */
moveCatchHandlers(BasicBlock fromBlock)1065   public void moveCatchHandlers(BasicBlock fromBlock) {
1066     List<BasicBlock> catchSuccessors = appendCatchHandlers(fromBlock);
1067     for (BasicBlock successor : catchSuccessors) {
1068       fromBlock.successors.remove(successor);
1069       successor.removePredecessor(fromBlock);
1070     }
1071     fromBlock.catchHandlers = CatchHandlers.EMPTY_INDICES;
1072   }
1073 
1074   /**
1075    * Clone catch successors from `fromBlock` into this block.
1076    */
copyCatchHandlers( IRCode code, ListIterator<BasicBlock> blockIterator, BasicBlock fromBlock)1077   public void copyCatchHandlers(
1078       IRCode code, ListIterator<BasicBlock> blockIterator, BasicBlock fromBlock) {
1079     if (catchHandlers != null && catchHandlers.hasCatchAll()) {
1080       return;
1081     }
1082     List<BasicBlock> catchSuccessors = appendCatchHandlers(fromBlock);
1083 
1084     // After cloning is done all catch handler targets are referenced from both the
1085     // original and the newly created catch handlers. Thus, since we keep both of
1086     // them, we need to split appropriate edges to make sure every catch handler
1087     // target block has only one predecessor.
1088     //
1089     // Note that for each catch handler block target block we actually create two new blocks:
1090     // a copy of the original block and a new block to serve as a merging point for
1091     // the original and its copy. This actually simplifies things since we only need
1092     // one new phi to merge the two exception values, and all other phis don't need
1093     // to be changed.
1094     for (BasicBlock catchSuccessor : catchSuccessors) {
1095       catchSuccessor.splitCriticalExceptionEdges(
1096           code.valueNumberGenerator,
1097           newBlock -> {
1098             newBlock.setNumber(code.blocks.size());
1099             blockIterator.add(newBlock);
1100           });
1101     }
1102   }
1103 
1104   /**
1105    * Assumes that `this` block is a catch handler target (note that it does not have to
1106    * start with MoveException instruction, since the instruction can be removed by
1107    * optimizations like dead code remover.
1108    *
1109    * Introduces new blocks on all incoming edges and clones MoveException instruction to
1110    * these blocks if it exists. All exception values introduced in newly created blocks
1111    * are combined in a phi added to `this` block.
1112    *
1113    * Note that if there are any other phis defined on this block, they remain valid, since
1114    * this method does not affect incoming edges in any way, and just adds new blocks with
1115    * MoveException and Goto.
1116    *
1117    * NOTE: onNewBlock must assign block number to the newly created block.
1118    */
splitCriticalExceptionEdges( ValueNumberGenerator valueNumberGenerator, Consumer<BasicBlock> onNewBlock)1119   public void splitCriticalExceptionEdges(
1120       ValueNumberGenerator valueNumberGenerator, Consumer<BasicBlock> onNewBlock) {
1121     List<BasicBlock> predecessors = this.getPredecessors();
1122     boolean hasMoveException = entry().isMoveException();
1123     MoveException move = null;
1124     if (hasMoveException) {
1125       // Remove the move-exception instruction.
1126       move = entry().asMoveException();
1127       assert move.getPreviousLocalValue() == null;
1128       this.getInstructions().remove(0);
1129     }
1130     // Create new predecessor blocks.
1131     List<BasicBlock> newPredecessors = new ArrayList<>();
1132     List<Value> values = new ArrayList<>(predecessors.size());
1133     for (BasicBlock predecessor : predecessors) {
1134       if (!predecessor.hasCatchSuccessor(this)) {
1135         throw new CompilationError(
1136             "Invalid block structure: catch block reachable via non-exceptional flow.");
1137       }
1138       BasicBlock newBlock = new BasicBlock();
1139       newPredecessors.add(newBlock);
1140       if (hasMoveException) {
1141         Value value = new Value(
1142             valueNumberGenerator.next(), MoveType.OBJECT, move.getDebugInfo());
1143         values.add(value);
1144         newBlock.add(new MoveException(value));
1145       }
1146       newBlock.add(new Goto());
1147       newBlock.close(null);
1148       newBlock.getSuccessors().add(this);
1149       newBlock.getPredecessors().add(predecessor);
1150       predecessor.replaceSuccessor(this, newBlock);
1151       onNewBlock.accept(newBlock);
1152       assert newBlock.getNumber() >= 0 : "Number must be assigned by `onNewBlock`";
1153     }
1154     // Replace the blocks predecessors with the new ones.
1155     predecessors.clear();
1156     predecessors.addAll(newPredecessors);
1157     // Insert a phi for the move-exception value.
1158     if (hasMoveException) {
1159       Phi phi = new Phi(valueNumberGenerator.next(),
1160           this, MoveType.OBJECT, move.getLocalInfo());
1161       phi.addOperands(values);
1162       move.outValue().replaceUsers(phi);
1163     }
1164   }
1165 
1166   /**
1167    * Append catch handlers from another block <code>fromBlock</code> (which must have catch
1168    * handlers) to the catch handlers of this block.
1169    *
1170    * Note that after appending catch handlers their targets are referenced by both
1171    * <code>fromBlock</code> and <code>this</code> block, but no phis are inserted. For this reason
1172    * this method should only be called from either {@link #moveCatchHandlers} or
1173    * {@link #copyCatchHandlers} which know how to handle phis.
1174    *
1175    * @returns the catch successors that are reused in both blocks after appending.
1176    */
appendCatchHandlers(BasicBlock fromBlock)1177   private List<BasicBlock> appendCatchHandlers(BasicBlock fromBlock) {
1178     assert fromBlock.hasCatchHandlers();
1179 
1180     List<Integer> prevCatchTargets = fromBlock.catchHandlers.getAllTargets();
1181     List<DexType> prevCatchGuards = fromBlock.catchHandlers.getGuards();
1182     List<BasicBlock> catchSuccessors = new ArrayList<>();
1183     List<DexType> newCatchGuards = new ArrayList<>();
1184     List<Integer> newCatchTargets = new ArrayList<>();
1185 
1186     // First add existing catch handlers to the catch handler list.
1187     if (hasCatchHandlers()) {
1188       newCatchGuards.addAll(catchHandlers.getGuards());
1189       newCatchTargets.addAll(catchHandlers.getAllTargets());
1190       for (int newCatchTarget : newCatchTargets) {
1191         BasicBlock catchSuccessor = successors.get(newCatchTarget);
1192         if (!catchSuccessors.contains(catchSuccessor)) {
1193           catchSuccessors.add(catchSuccessor);
1194         }
1195         int index = catchSuccessors.indexOf(catchSuccessor);
1196         assert index == newCatchTarget;
1197       }
1198     }
1199 
1200     // This is the number of catch handlers which are already successors of this block.
1201     int formerCatchHandlersCount = catchSuccessors.size();
1202 
1203     // Then add catch handlers from the other block to the catch handler list.
1204     for (int i = 0; i < prevCatchTargets.size(); i++) {
1205       int prevCatchTarget = prevCatchTargets.get(i);
1206       DexType prevCatchGuard = prevCatchGuards.get(i);
1207       // TODO(sgjesse): Check sub-types of guards. Will require AppInfoWithSubtyping.
1208       BasicBlock catchSuccessor = fromBlock.successors.get(prevCatchTarget);
1209       // We assume that all the catch handlers targets has only one
1210       // predecessor and, thus, no phis.
1211       assert catchSuccessor.getPredecessors().size() == 1;
1212       assert catchSuccessor.getPhis().isEmpty();
1213 
1214       int index = catchSuccessors.indexOf(catchSuccessor);
1215       if (index == -1) {
1216         catchSuccessors.add(catchSuccessor);
1217         index = catchSuccessors.size() - 1;
1218       }
1219       newCatchGuards.add(prevCatchGuard);
1220       newCatchTargets.add(index);
1221     }
1222 
1223     // Create the new successors list and link things up.
1224     List<BasicBlock> formerSuccessors = new ArrayList<>(successors);
1225     successors.clear();
1226     List<BasicBlock> sharedCatchSuccessors = new ArrayList<>();
1227     for (int i = 0; i < catchSuccessors.size(); i++) {
1228       if (i < formerCatchHandlersCount) {
1229         // Former catch successors are just copied, as they are already linked.
1230         assert catchSuccessors.get(i).getPredecessors().contains(this);
1231         successors.add(catchSuccessors.get(i));
1232       } else {
1233         // New catch successors are linked properly.
1234         assert !catchSuccessors.get(i).getPredecessors().contains(this);
1235         link(catchSuccessors.get(i));
1236         sharedCatchSuccessors.add(catchSuccessors.get(i));
1237       }
1238     }
1239     catchHandlers = new CatchHandlers<>(newCatchGuards, newCatchTargets);
1240 
1241     // Finally add the normal successor if any.
1242     int catchSuccessorsCount = successors.size();
1243     for (BasicBlock formerSuccessor : formerSuccessors) {
1244       if (!successors.contains(formerSuccessor)) {
1245         assert !exit().isThrow();
1246         successors.add(formerSuccessor);
1247       }
1248     }
1249     assert successors.size() == catchSuccessorsCount || !exit().isThrow();
1250 
1251     return sharedCatchSuccessors;
1252   }
1253 }
1254