Home | History | Annotate | Download | only in code
      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 
     39   public void setLocalsAtEntry(Int2ReferenceMap<DebugLocalInfo> localsAtEntry) {
     40     this.localsAtEntry = localsAtEntry;
     41   }
     42 
     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 
     62     public Pair(BasicBlock first, BasicBlock second) {
     63       this.first = first;
     64       this.second = second;
     65     }
     66 
     67     @Override
     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 
    111   public List<BasicBlock> getSuccessors() {
    112     return successors;
    113   }
    114 
    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 
    129   public List<BasicBlock> getPredecessors() {
    130     return predecessors;
    131   }
    132 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    331   public void removePhisByIndex(List<Integer> predecessorsToRemove) {
    332     for (Phi phi : phis) {
    333       phi.removeOperandsByIndex(predecessorsToRemove);
    334     }
    335   }
    336 
    337   public List<Phi> getPhis() {
    338     return phis;
    339   }
    340 
    341   public void setPhis(List<Phi> phis) {
    342     this.phis = phis;
    343   }
    344 
    345   public boolean isFilled() {
    346     return filled;
    347   }
    348 
    349   void setFilledForTesting() {
    350     filled = true;
    351   }
    352 
    353   public boolean hasCatchHandlers() {
    354     assert catchHandlers != null;
    355     return !catchHandlers.isEmpty();
    356   }
    357 
    358   public int getNumber() {
    359     assert number >= 0;
    360     return number;
    361   }
    362 
    363   public void setNumber(int number) {
    364     assert number >= 0;
    365     this.number = number;
    366   }
    367 
    368   public LinkedList<Instruction> getInstructions() {
    369     return instructions;
    370   }
    371 
    372   public Instruction entry() {
    373     return instructions.get(0);
    374   }
    375 
    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 
    382   public void clearUserInfo() {
    383     phis = null;
    384     instructions.forEach(Instruction::clearUserInfo);
    385   }
    386 
    387   public void buildDex(DexBuilder builder) {
    388     for (Instruction instruction : instructions) {
    389       instruction.buildDex(builder);
    390     }
    391   }
    392 
    393   public void mark() {
    394     assert color == 0;
    395     color = 1;
    396   }
    397 
    398   public void clearMark() {
    399     color = 0;
    400   }
    401 
    402   public boolean isMarked() {
    403     return color == 1;
    404   }
    405 
    406   public void setColor(int color) {
    407     this.color = color;
    408   }
    409 
    410   public int getColor() {
    411     return color;
    412   }
    413 
    414   public boolean hasColor(int color) {
    415     return this.color == color;
    416   }
    417 
    418   public void incrementUnfilledPredecessorCount() {
    419     ++unfilledPredecessorsCount;
    420     ++estimatedPredecessorsCount;
    421   }
    422 
    423   public void decrementUnfilledPredecessorCount(int n) {
    424     unfilledPredecessorsCount -= n;
    425     estimatedPredecessorsCount -= n;
    426   }
    427 
    428   public void decrementUnfilledPredecessorCount() {
    429     --unfilledPredecessorsCount;
    430     --estimatedPredecessorsCount;
    431   }
    432 
    433   public boolean verifyFilledPredecessors() {
    434     assert estimatedPredecessorsCount == predecessors.size();
    435     assert unfilledPredecessorsCount == 0;
    436     return true;
    437   }
    438 
    439   public void addPhi(Phi phi) {
    440     phis.add(phi);
    441   }
    442 
    443   public void removePhi(Phi phi) {
    444     phis.remove(phi);
    445   }
    446 
    447   public void add(Instruction next) {
    448     assert !isFilled();
    449     instructions.add(next);
    450     next.setBlock(this);
    451   }
    452 
    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 
    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 
    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 
    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    */
    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    */
    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    */
    523   public BasicBlock unlinkSingle() {
    524     unlinkSinglePredecessor();
    525     return unlinkSingleSuccessor();
    526   }
    527 
    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 
    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 
    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).
    594   private int onThrowValueRegister(int register) {
    595     return -(register + 1);
    596   }
    597 
    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 
    605   private boolean isOnThrowValue(int register, EdgeType readingEdge) {
    606     return readOnThrowValue(register, readingEdge) != null;
    607   }
    608 
    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 
    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 
    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 
    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 
    671   public EdgeType getEdgeType(BasicBlock successor) {
    672     assert successors.indexOf(successor) >= 0;
    673     return hasCatchSuccessor(successor) ? EdgeType.EXCEPTIONAL : EdgeType.NORMAL;
    674   }
    675 
    676   public boolean hasCatchSuccessor(BasicBlock block) {
    677     if (!hasCatchHandlers()) {
    678       return false;
    679     }
    680     return catchHandlers.getAllTargets().contains(successors.indexOf(block));
    681   }
    682 
    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 
    696   public boolean isSealed() {
    697     return sealed;
    698   }
    699 
    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 
    708   public boolean hasIncompletePhis() {
    709     return !incompletePhis.isEmpty();
    710   }
    711 
    712   public Collection<Integer> getIncompletePhiRegisters() {
    713     return incompletePhis.keySet();
    714   }
    715 
    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
    730   public String toString() {
    731     return toDetailedString();
    732   }
    733 
    734   public String toSimpleString() {
    735     return number < 0 ? super.toString() : ("block " + number);
    736   }
    737 
    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 
    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 
    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 
    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 
    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 
    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    */
    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    */
    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    */
    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    */
    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    */
    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 
    930   public boolean isTrivialGoto() {
    931     return instructions.size() == 1 && exit().isGoto();
    932   }
    933 
    934   public boolean hasOneNormalExit() {
    935     return successors.size() == 1 && exit().isGoto();
    936   }
    937 
    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 
    946   public CatchHandlers<Integer> getCatchHandlersWithSuccessorIndexes() {
    947     return catchHandlers;
    948   }
    949 
    950   public void clearCatchHandlers() {
    951     catchHandlers = CatchHandlers.EMPTY_INDICES;
    952   }
    953 
    954   public void transferCatchHandlers(BasicBlock other) {
    955     catchHandlers = other.catchHandlers;
    956     other.catchHandlers = CatchHandlers.EMPTY_INDICES;
    957   }
    958 
    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.
    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.
    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 
    996   public InstructionIterator iterator() {
    997     return new BasicBlockInstructionIterator(this);
    998   }
    999 
   1000   public InstructionListIterator listIterator() {
   1001     return new BasicBlockInstructionIterator(this);
   1002   }
   1003 
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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