Home | History | Annotate | Download | only in ssa
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.ssa;
     18 
     19 import com.android.dx.rop.code.BasicBlockList;
     20 import com.android.dx.rop.code.Insn;
     21 import com.android.dx.rop.code.PlainInsn;
     22 import com.android.dx.rop.code.RegOps;
     23 import com.android.dx.rop.code.RegisterSpec;
     24 import com.android.dx.rop.code.RegisterSpecList;
     25 import com.android.dx.rop.code.Rop;
     26 import com.android.dx.rop.code.RopMethod;
     27 import com.android.dx.rop.code.Rops;
     28 import com.android.dx.rop.code.SourcePosition;
     29 import com.android.dx.util.IntList;
     30 import java.util.ArrayList;
     31 import java.util.BitSet;
     32 import java.util.Collections;
     33 import java.util.List;
     34 import java.util.Set;
     35 import java.util.Stack;
     36 
     37 /**
     38  * A method in SSA form.
     39  */
     40 public final class SsaMethod {
     41     /** basic blocks, indexed by block index */
     42     private ArrayList<SsaBasicBlock> blocks;
     43 
     44     /** Index of first executed block in method */
     45     private int entryBlockIndex;
     46 
     47     /**
     48      * Index of exit block, which exists only in SSA form,
     49      * or or {@code -1} if there is none
     50      */
     51     private int exitBlockIndex;
     52 
     53     /** total number of registers required */
     54     private int registerCount;
     55 
     56     /** first register number to use for any temporary "spares" */
     57     private int spareRegisterBase;
     58 
     59     /** current count of spare registers used */
     60     private int borrowedSpareRegisters;
     61 
     62     /** really one greater than the max label */
     63     private int maxLabel;
     64 
     65     /** the total width, in register-units, of the method's parameters */
     66     private final int paramWidth;
     67 
     68     /** true if this method has no {@code this} pointer argument */
     69     private final boolean isStatic;
     70 
     71     /**
     72      * indexed by register: the insn where said register is defined or null
     73      * if undefined. null until (lazily) created.
     74      */
     75     private SsaInsn[] definitionList;
     76 
     77     /** indexed by register: the list of all insns that use a register */
     78     private ArrayList<SsaInsn>[] useList;
     79 
     80     /** A version of useList with each List unmodifiable */
     81     private List<SsaInsn>[] unmodifiableUseList;
     82 
     83     /**
     84      * "back-convert mode". Set during back-conversion when registers
     85      * are about to be mapped into a non-SSA namespace. When true,
     86      * use and def lists are unavailable.
     87      *
     88      * TODO: Remove this mode, and place the functionality elsewhere
     89      */
     90     private boolean backMode;
     91 
     92     /**
     93      * @param ropMethod rop-form method to convert from
     94      * @param paramWidth the total width, in register-units, of the
     95      * method's parameters
     96      * @param isStatic {@code true} if this method has no {@code this}
     97      * pointer argument
     98      */
     99     public static SsaMethod newFromRopMethod(RopMethod ropMethod,
    100             int paramWidth, boolean isStatic) {
    101         SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic);
    102 
    103         result.convertRopToSsaBlocks(ropMethod);
    104 
    105         return result;
    106     }
    107 
    108     /**
    109      * Constructs an instance.
    110      *
    111      * @param ropMethod {@code non-null;} the original rop-form method that
    112      * this instance is based on
    113      * @param paramWidth the total width, in register-units, of the
    114      * method's parameters
    115      * @param isStatic {@code true} if this method has no {@code this}
    116      * pointer argument
    117      */
    118     private SsaMethod(RopMethod ropMethod, int paramWidth, boolean isStatic) {
    119         this.paramWidth = paramWidth;
    120         this.isStatic = isStatic;
    121         this.backMode = false;
    122         this.maxLabel = ropMethod.getBlocks().getMaxLabel();
    123         this.registerCount = ropMethod.getBlocks().getRegCount();
    124         this.spareRegisterBase = registerCount;
    125     }
    126 
    127     /**
    128      * Builds a BitSet of block indices from a basic block list and a list
    129      * of labels taken from Rop form.
    130      *
    131      * @param blocks Rop blocks
    132      * @param labelList list of rop block labels
    133      * @return BitSet of block indices
    134      */
    135     static BitSet bitSetFromLabelList(BasicBlockList blocks,
    136             IntList labelList) {
    137         BitSet result = new BitSet(blocks.size());
    138 
    139         for (int i = 0, sz = labelList.size(); i < sz; i++) {
    140             result.set(blocks.indexOfLabel(labelList.get(i)));
    141         }
    142 
    143         return result;
    144     }
    145 
    146     /**
    147      * Builds an IntList of block indices from a basic block list and a list
    148      * of labels taken from Rop form.
    149      *
    150      * @param ropBlocks Rop blocks
    151      * @param labelList list of rop block labels
    152      * @return IntList of block indices
    153      */
    154     public static IntList indexListFromLabelList(BasicBlockList ropBlocks,
    155             IntList labelList) {
    156 
    157         IntList result = new IntList(labelList.size());
    158 
    159         for (int i = 0, sz = labelList.size(); i < sz; i++) {
    160             result.add(ropBlocks.indexOfLabel(labelList.get(i)));
    161         }
    162 
    163         return result;
    164     }
    165 
    166     private void convertRopToSsaBlocks(RopMethod rmeth) {
    167         BasicBlockList ropBlocks = rmeth.getBlocks();
    168         int sz = ropBlocks.size();
    169 
    170         blocks = new ArrayList<SsaBasicBlock>(sz + 2);
    171 
    172         for (int i = 0; i < sz; i++) {
    173             SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
    174             blocks.add(sbb);
    175         }
    176 
    177         // Add an no-op entry block.
    178         int origEntryBlockIndex = rmeth.getBlocks()
    179                 .indexOfLabel(rmeth.getFirstLabel());
    180 
    181         SsaBasicBlock entryBlock
    182                 = blocks.get(origEntryBlockIndex).insertNewPredecessor();
    183 
    184         entryBlockIndex = entryBlock.getIndex();
    185         exitBlockIndex = -1; // This gets made later.
    186     }
    187 
    188     /**
    189      * Creates an exit block and attaches it to the CFG if this method
    190      * exits. Methods that never exit will not have an exit block. This
    191      * is called after edge-splitting and phi insertion, since the edges
    192      * going into the exit block should not be considered in those steps.
    193      */
    194     /*package*/ void makeExitBlock() {
    195         if (exitBlockIndex >= 0) {
    196             throw new RuntimeException("must be called at most once");
    197         }
    198 
    199         exitBlockIndex = blocks.size();
    200         SsaBasicBlock exitBlock
    201                 = new SsaBasicBlock(exitBlockIndex, maxLabel++, this);
    202 
    203         blocks.add(exitBlock);
    204 
    205         for (SsaBasicBlock block : blocks) {
    206             block.exitBlockFixup(exitBlock);
    207         }
    208 
    209         if (exitBlock.getPredecessors().cardinality() == 0) {
    210             // In cases where there is no exit...
    211             blocks.remove(exitBlockIndex);
    212             exitBlockIndex = -1;
    213             maxLabel--;
    214         }
    215     }
    216 
    217     /**
    218      * Gets a new {@code GOTO} insn.
    219      *
    220      * @param block block to which this GOTO will be added
    221      * (not it's destination!)
    222      * @return an appropriately-constructed instance.
    223      */
    224     private static SsaInsn getGoto(SsaBasicBlock block) {
    225         return new NormalSsaInsn (
    226                 new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO,
    227                     null, RegisterSpecList.EMPTY), block);
    228     }
    229 
    230     /**
    231      * Makes a new basic block for this method, which is empty besides
    232      * a single {@code GOTO}. Successors and predecessors are not yet
    233      * set.
    234      *
    235      * @return new block
    236      */
    237     public SsaBasicBlock makeNewGotoBlock() {
    238         int newIndex = blocks.size();
    239         SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this);
    240 
    241         newBlock.getInsns().add(getGoto(newBlock));
    242         blocks.add(newBlock);
    243 
    244         return newBlock;
    245     }
    246 
    247     /**
    248      * @return block index of first execution block
    249      */
    250     public int getEntryBlockIndex() {
    251         return entryBlockIndex;
    252     }
    253 
    254     /**
    255      * @return first execution block
    256      */
    257     public SsaBasicBlock getEntryBlock() {
    258         return blocks.get(entryBlockIndex);
    259     }
    260 
    261     /**
    262      * @return block index of exit block or {@code -1} if there is none
    263      */
    264     public int getExitBlockIndex() {
    265         return exitBlockIndex;
    266     }
    267 
    268     /**
    269      * @return {@code null-ok;} block of exit block or {@code null} if
    270      * there is none
    271      */
    272     public SsaBasicBlock getExitBlock() {
    273         return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex);
    274     }
    275 
    276     /**
    277      * @param bi block index or {@code -1} for none
    278      * @return rop label or {code -1} if {@code bi} was {@code -1}
    279      */
    280     public int blockIndexToRopLabel(int bi) {
    281         if (bi < 0) {
    282             return -1;
    283         }
    284         return blocks.get(bi).getRopLabel();
    285     }
    286 
    287     /**
    288      * @return count of registers used in this method
    289      */
    290     public int getRegCount() {
    291         return registerCount;
    292     }
    293 
    294     /**
    295      * @return the total width, in register units, of the method's
    296      * parameters
    297      */
    298     public int getParamWidth() {
    299         return paramWidth;
    300     }
    301 
    302     /**
    303      * Returns {@code true} if this is a static method.
    304      *
    305      * @return {@code true} if this is a static method
    306      */
    307     public boolean isStatic() {
    308         return isStatic;
    309     }
    310 
    311     /**
    312      * Borrows a register to use as a temp. Used in the phi removal process.
    313      * Call returnSpareRegisters() when done.
    314      *
    315      * @param category width (1 or 2) of the register
    316      * @return register number to use
    317      */
    318     public int borrowSpareRegister(int category) {
    319         int result = spareRegisterBase + borrowedSpareRegisters;
    320 
    321         borrowedSpareRegisters += category;
    322         registerCount = Math.max(registerCount, result + category);
    323 
    324         return result;
    325     }
    326 
    327     /**
    328      * Returns all borrowed registers.
    329      */
    330     public void returnSpareRegisters() {
    331         borrowedSpareRegisters = 0;
    332     }
    333 
    334     /**
    335      * @return {@code non-null;} basic block list. Do not modify.
    336      */
    337     public ArrayList<SsaBasicBlock> getBlocks() {
    338         return blocks;
    339     }
    340 
    341     /**
    342      * Computes reachability for all blocks in the method.
    343      *
    344      * @return a BitSet of reachable blocks.
    345      */
    346     public BitSet computeReachability() {
    347         final int size = blocks.size();
    348         BitSet reachableUnvisited = new BitSet(size);
    349         BitSet reachableVisited = new BitSet(size);
    350 
    351         reachableUnvisited.set(getEntryBlock().getIndex());
    352 
    353         int index;
    354         while ((index = reachableUnvisited.nextSetBit(0)) != -1) {
    355             reachableVisited.set(index);
    356             reachableUnvisited.or(blocks.get(index).getSuccessors());
    357             reachableUnvisited.andNot(reachableVisited);
    358         }
    359 
    360         return reachableVisited;
    361     }
    362 
    363     /**
    364      * Remaps unversioned registers.
    365      *
    366      * @param mapper maps old registers to new.
    367      */
    368     public void mapRegisters(RegisterMapper mapper) {
    369         for (SsaBasicBlock block : getBlocks()) {
    370             for (SsaInsn insn : block.getInsns()) {
    371                 insn.mapRegisters(mapper);
    372             }
    373         }
    374 
    375         registerCount = mapper.getNewRegisterCount();
    376         spareRegisterBase = registerCount;
    377     }
    378 
    379     /**
    380      * Returns the insn that defines the given register
    381      * @param reg register in question
    382      * @return insn (actual instance from code) that defined this reg or null
    383      * if reg is not defined.
    384      */
    385     public SsaInsn getDefinitionForRegister(int reg) {
    386         if (backMode) {
    387             throw new RuntimeException("No def list in back mode");
    388         }
    389 
    390         if (definitionList != null) {
    391             return definitionList[reg];
    392         }
    393 
    394         definitionList = new SsaInsn[getRegCount()];
    395 
    396         forEachInsn(new SsaInsn.Visitor() {
    397             @Override
    398             public void visitMoveInsn (NormalSsaInsn insn) {
    399                 definitionList[insn.getResult().getReg()] = insn;
    400             }
    401             @Override
    402             public void visitPhiInsn (PhiInsn phi) {
    403                 definitionList[phi.getResult().getReg()] = phi;
    404             }
    405             @Override
    406             public void visitNonMoveInsn (NormalSsaInsn insn) {
    407                 RegisterSpec result = insn.getResult();
    408                 if (result != null) {
    409                     definitionList[insn.getResult().getReg()] = insn;
    410                 }
    411             }
    412         });
    413 
    414         return definitionList[reg];
    415     }
    416 
    417     /**
    418      * Builds useList and unmodifiableUseList.
    419      */
    420     private void buildUseList() {
    421         if (backMode) {
    422             throw new RuntimeException("No use list in back mode");
    423         }
    424 
    425         useList = new ArrayList[registerCount];
    426 
    427         for (int i = 0; i < registerCount; i++) {
    428             useList[i] = new ArrayList();
    429         }
    430 
    431         forEachInsn(new SsaInsn.Visitor() {
    432             /** {@inheritDoc} */
    433             @Override
    434             public void visitMoveInsn (NormalSsaInsn insn) {
    435                 addToUses(insn);
    436             }
    437             /** {@inheritDoc} */
    438             @Override
    439             public void visitPhiInsn (PhiInsn phi) {
    440                 addToUses(phi);
    441             }
    442             /** {@inheritDoc} */
    443             @Override
    444             public void visitNonMoveInsn (NormalSsaInsn insn) {
    445                 addToUses(insn);
    446             }
    447             /**
    448              * Adds specified insn to the uses list for all of its sources.
    449              * @param insn {@code non-null;} insn to process
    450              */
    451             private void addToUses(SsaInsn insn) {
    452                 RegisterSpecList rl = insn.getSources();
    453                 int sz = rl.size();
    454 
    455                 for (int i = 0; i < sz; i++) {
    456                     useList[rl.get(i).getReg()].add(insn);
    457                 }
    458             }
    459         });
    460 
    461         unmodifiableUseList = new List[registerCount];
    462 
    463         for (int i = 0; i < registerCount; i++) {
    464             unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
    465         }
    466     }
    467 
    468     /**
    469      * Updates the use list for a single change in source register.
    470      *
    471      * @param insn {@code non-null;} insn being changed
    472      * @param oldSource {@code null-ok;} The source that was used, if
    473      * applicable
    474      * @param newSource {@code non-null;} the new source being used
    475      */
    476     /*package*/ void onSourceChanged(SsaInsn insn,
    477             RegisterSpec oldSource, RegisterSpec newSource) {
    478         if (useList == null) return;
    479 
    480         if (oldSource != null) {
    481             int reg = oldSource.getReg();
    482             useList[reg].remove(insn);
    483         }
    484 
    485         int reg = newSource.getReg();
    486         if (useList.length <= reg) {
    487             useList = null;
    488             return;
    489         }
    490         useList[reg].add(insn);
    491     }
    492 
    493     /**
    494      * Updates the use list for a source list change.
    495      *
    496      * @param insn {@code insn non-null;} insn being changed.
    497      * {@code insn.getSources()} must return the new source list.
    498      * @param oldSources {@code null-ok;} list of sources that were
    499      * previously used
    500      */
    501     /*package*/ void onSourcesChanged(SsaInsn insn,
    502             RegisterSpecList oldSources) {
    503         if (useList == null) return;
    504 
    505         if (oldSources != null) {
    506             removeFromUseList(insn, oldSources);
    507         }
    508 
    509         RegisterSpecList sources = insn.getSources();
    510         int szNew = sources.size();
    511 
    512         for (int i = 0; i < szNew; i++) {
    513             int reg = sources.get(i).getReg();
    514             useList[reg].add(insn);
    515         }
    516     }
    517 
    518     /**
    519      * Removes a given {@code insn} from the use lists for the given
    520      * {@code oldSources} (rather than the sources currently
    521      * returned by insn.getSources()).
    522      *
    523      * @param insn {@code non-null;} insn in question
    524      * @param oldSources {@code null-ok;} registers whose use lists
    525      * {@code insn} should be removed form
    526      */
    527     private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) {
    528         if (oldSources == null) {
    529             return;
    530         }
    531 
    532         int szNew = oldSources.size();
    533         for (int i = 0; i < szNew; i++) {
    534             if (!useList[oldSources.get(i).getReg()].remove(insn)) {
    535                 throw new RuntimeException("use not found");
    536             }
    537         }
    538     }
    539 
    540     /**
    541      * Adds an insn to both the use and def lists. For use when adding
    542      * a new insn to the method.
    543      *
    544      * @param insn {@code non-null;} insn to add
    545      */
    546     /*package*/ void onInsnAdded(SsaInsn insn) {
    547         onSourcesChanged(insn, null);
    548         updateOneDefinition(insn, null);
    549     }
    550 
    551     /**
    552      * Removes an instruction from use and def lists. For use during
    553      * instruction removal.
    554      *
    555      * @param insn {@code non-null;} insn to remove
    556      */
    557     /*package*/ void onInsnRemoved(SsaInsn insn) {
    558         if (useList != null) {
    559             removeFromUseList(insn, insn.getSources());
    560         }
    561 
    562         RegisterSpec resultReg = insn.getResult();
    563         if (definitionList != null && resultReg != null) {
    564             definitionList[resultReg.getReg()] = null;
    565         }
    566     }
    567 
    568     /**
    569      * Indicates that the instruction list has changed or the SSA register
    570      * count has increased, so that internal datastructures that rely on
    571      * it should be rebuild. In general, the various other on* methods
    572      * should be called in preference when changes occur if they are
    573      * applicable.
    574      */
    575     public void onInsnsChanged() {
    576         // Definition list will need to be recomputed
    577         definitionList = null;
    578 
    579         // Use list will need to be recomputed
    580         useList = null;
    581         unmodifiableUseList = null;
    582     }
    583 
    584     /**
    585      * Updates a single definition.
    586      *
    587      * @param insn {@code non-null;} insn who's result should be recorded as
    588      * a definition
    589      * @param oldResult {@code null-ok;} a previous result that should
    590      * be no longer considered a definition by this insn
    591      */
    592     /*package*/ void updateOneDefinition(SsaInsn insn,
    593             RegisterSpec oldResult) {
    594         if (definitionList == null) return;
    595 
    596         if (oldResult != null) {
    597             int reg = oldResult.getReg();
    598             definitionList[reg] = null;
    599         }
    600 
    601         RegisterSpec resultReg = insn.getResult();
    602 
    603         if (resultReg != null) {
    604             int reg = resultReg.getReg();
    605 
    606             if (definitionList[reg] != null) {
    607                 throw new RuntimeException("Duplicate add of insn");
    608             } else {
    609                 definitionList[resultReg.getReg()] = insn;
    610             }
    611         }
    612     }
    613 
    614     /**
    615      * Returns the list of all source uses (not results) for a register.
    616      *
    617      * @param reg register in question
    618      * @return unmodifiable instruction list
    619      */
    620     public List<SsaInsn> getUseListForRegister(int reg) {
    621 
    622         if (unmodifiableUseList == null) {
    623             buildUseList();
    624         }
    625 
    626         return unmodifiableUseList[reg];
    627     }
    628 
    629     /**
    630      * Returns a modifiable copy of the register use list.
    631      *
    632      * @return modifiable copy of the use-list, indexed by register
    633      */
    634     public ArrayList<SsaInsn>[] getUseListCopy() {
    635         if (useList == null) {
    636             buildUseList();
    637         }
    638 
    639         ArrayList<SsaInsn>[] useListCopy
    640                 = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]);
    641 
    642         for (int i = 0; i < registerCount; i++) {
    643             useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i]));
    644         }
    645 
    646         return useListCopy;
    647     }
    648 
    649     /**
    650      * Checks to see if the given SSA reg is ever associated with a local
    651      * local variable. Each SSA reg may be associated with at most one
    652      * local var.
    653      *
    654      * @param spec {@code non-null;} ssa reg
    655      * @return true if reg is ever associated with a local
    656      */
    657     public boolean isRegALocal(RegisterSpec spec) {
    658         SsaInsn defn = getDefinitionForRegister(spec.getReg());
    659 
    660         if (defn == null) {
    661             // version 0 registers are never used as locals
    662             return false;
    663         }
    664 
    665         // Does the definition have a local associated with it?
    666         if (defn.getLocalAssignment() != null) return true;
    667 
    668         // If not, is there a mark-local insn?
    669         for (SsaInsn use : getUseListForRegister(spec.getReg())) {
    670             Insn insn = use.getOriginalRopInsn();
    671 
    672             if (insn != null
    673                     && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
    674                 return true;
    675             }
    676         }
    677 
    678         return false;
    679     }
    680 
    681     /**
    682      * Sets the new register count after renaming.
    683      *
    684      * @param newRegCount new register count
    685      */
    686     /*package*/ void setNewRegCount(int newRegCount) {
    687         registerCount = newRegCount;
    688         spareRegisterBase = registerCount;
    689         onInsnsChanged();
    690     }
    691 
    692     /**
    693      * Makes a new SSA register. For use after renaming has completed.
    694      *
    695      * @return {@code >=0;} new SSA register.
    696      */
    697     public int makeNewSsaReg() {
    698         int reg = registerCount++;
    699         spareRegisterBase = registerCount;
    700         onInsnsChanged();
    701         return reg;
    702     }
    703 
    704     /**
    705      * Visits all insns in this method.
    706      *
    707      * @param visitor {@code non-null;} callback interface
    708      */
    709     public void forEachInsn(SsaInsn.Visitor visitor) {
    710         for (SsaBasicBlock block : blocks) {
    711             block.forEachInsn(visitor);
    712         }
    713     }
    714 
    715     /**
    716      * Visits each phi insn in this method
    717      * @param v {@code non-null;} callback.
    718      *
    719      */
    720     public void forEachPhiInsn(PhiInsn.Visitor v) {
    721         for (SsaBasicBlock block : blocks) {
    722             block.forEachPhiInsn(v);
    723         }
    724     }
    725 
    726 
    727     /**
    728      * Walks the basic block tree in depth-first order, calling the visitor
    729      * method once for every block. This depth-first walk may be run forward
    730      * from the method entry point or backwards from the method exit points.
    731      *
    732      * @param reverse true if this should walk backwards from the exit points
    733      * @param v {@code non-null;} callback interface. {@code parent} is set
    734      * unless this is the root node
    735      */
    736     public void forEachBlockDepthFirst(boolean reverse,
    737             SsaBasicBlock.Visitor v) {
    738         BitSet visited = new BitSet(blocks.size());
    739 
    740         // We push the parent first, then the child on the stack.
    741         Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
    742 
    743         SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
    744 
    745         if (rootBlock == null) {
    746             // in the case there's no exit block
    747             return;
    748         }
    749 
    750         stack.add(null);    // Start with null parent.
    751         stack.add(rootBlock);
    752 
    753         while (stack.size() > 0) {
    754             SsaBasicBlock cur = stack.pop();
    755             SsaBasicBlock parent = stack.pop();
    756 
    757             if (!visited.get(cur.getIndex())) {
    758                 BitSet children
    759                     = reverse ? cur.getPredecessors() : cur.getSuccessors();
    760                 for (int i = children.nextSetBit(0); i >= 0
    761                         ; i = children.nextSetBit(i + 1)) {
    762                     stack.add(cur);
    763                     stack.add(blocks.get(i));
    764                 }
    765                 visited.set(cur.getIndex());
    766                 v.visitBlock(cur, parent);
    767             }
    768         }
    769     }
    770 
    771     /**
    772      * Visits blocks in dom-tree order, starting at the current node.
    773      * The {@code parent} parameter of the Visitor.visitBlock callback
    774      * is currently always set to null.
    775      *
    776      * @param v {@code non-null;} callback interface
    777      */
    778     public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) {
    779         BitSet visited = new BitSet(getBlocks().size());
    780         Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
    781 
    782         stack.add(getEntryBlock());
    783 
    784         while (stack.size() > 0) {
    785             SsaBasicBlock cur = stack.pop();
    786             ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren();
    787 
    788             if (!visited.get(cur.getIndex())) {
    789                 // We walk the tree this way for historical reasons...
    790                 for (int i = curDomChildren.size() - 1; i >= 0; i--) {
    791                     SsaBasicBlock child = curDomChildren.get(i);
    792                     stack.add(child);
    793                 }
    794                 visited.set(cur.getIndex());
    795                 v.visitBlock(cur, null);
    796             }
    797         }
    798     }
    799 
    800     /**
    801      * Deletes all insns in the set from this method.
    802      *
    803      * @param deletedInsns {@code non-null;} insns to delete
    804      */
    805     public void deleteInsns(Set<SsaInsn> deletedInsns) {
    806         for (SsaInsn deletedInsn : deletedInsns) {
    807             SsaBasicBlock block = deletedInsn.getBlock();
    808             ArrayList<SsaInsn> insns = block.getInsns();
    809 
    810             for (int i = insns.size() - 1; i >= 0; i--) {
    811                 SsaInsn insn = insns.get(i);
    812 
    813                 if (deletedInsn == insn) {
    814                     onInsnRemoved(insn);
    815                     insns.remove(i);
    816                     break;
    817                 }
    818             }
    819 
    820             // Check to see if we need to add a GOTO
    821 
    822             int insnsSz = insns.size();
    823             SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1);
    824 
    825             if (block != getExitBlock() && (insnsSz == 0
    826                     || lastInsn.getOriginalRopInsn() == null
    827                     || lastInsn.getOriginalRopInsn().getOpcode()
    828                         .getBranchingness() == Rop.BRANCH_NONE)) {
    829                 // We managed to eat a throwable insn
    830 
    831                 Insn gotoInsn = new PlainInsn(Rops.GOTO,
    832                         SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
    833                 insns.add(SsaInsn.makeFromRop(gotoInsn, block));
    834 
    835                 // Remove secondary successors from this block
    836                 BitSet succs = block.getSuccessors();
    837                 for (int i = succs.nextSetBit(0); i >= 0;
    838                          i = succs.nextSetBit(i + 1)) {
    839                     if (i != block.getPrimarySuccessorIndex()) {
    840                         block.removeSuccessor(i);
    841                     }
    842                 }
    843             }
    844         }
    845     }
    846 
    847     /**
    848      * Sets "back-convert mode". Set during back-conversion when registers
    849      * are about to be mapped into a non-SSA namespace. When true,
    850      * use and def lists are unavailable.
    851      */
    852     public void setBackMode() {
    853         backMode = true;
    854         useList = null;
    855         definitionList = null;
    856     }
    857 }
    858