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      */
newFromRopMethod(RopMethod ropMethod, int paramWidth, boolean isStatic)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      */
SsaMethod(RopMethod ropMethod, int paramWidth, boolean isStatic)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      */
bitSetFromLabelList(BasicBlockList blocks, IntList labelList)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      */
indexListFromLabelList(BasicBlockList ropBlocks, IntList labelList)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 
convertRopToSsaBlocks(RopMethod rmeth)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      */
makeExitBlock()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      */
getGoto(SsaBasicBlock block)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      */
makeNewGotoBlock()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      */
getEntryBlockIndex()250     public int getEntryBlockIndex() {
251         return entryBlockIndex;
252     }
253 
254     /**
255      * @return first execution block
256      */
getEntryBlock()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      */
getExitBlockIndex()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      */
getExitBlock()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      */
blockIndexToRopLabel(int bi)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      */
getRegCount()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      */
getParamWidth()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      */
isStatic()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      */
borrowSpareRegister(int category)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      */
returnSpareRegisters()330     public void returnSpareRegisters() {
331         borrowedSpareRegisters = 0;
332     }
333 
334     /**
335      * @return {@code non-null;} basic block list. Do not modify.
336      */
getBlocks()337     public ArrayList<SsaBasicBlock> getBlocks() {
338         return blocks;
339     }
340 
341     /**
342      * Returns the count of reachable blocks in this method: blocks that have
343      * predecessors (or are the start block)
344      *
345      * @return {@code >= 0;} number of reachable basic blocks
346      */
getCountReachableBlocks()347     public int getCountReachableBlocks() {
348         int ret = 0;
349 
350         for (SsaBasicBlock b : blocks) {
351             // Blocks that have been disconnected don't count.
352             if (b.isReachable()) {
353                 ret++;
354             }
355         }
356 
357         return ret;
358     }
359 
360     /**
361      * Computes reachability for all blocks in the method. First clears old
362      * values from all blocks, then starts with the entry block and walks down
363      * the control flow graph, marking all blocks it finds as reachable.
364      */
computeReachability()365     public void computeReachability() {
366         for (SsaBasicBlock block : blocks) {
367             block.setReachable(0);
368         }
369 
370         ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>();
371         blockList.add(this.getEntryBlock());
372 
373         while (!blockList.isEmpty()) {
374             SsaBasicBlock block = blockList.remove(0);
375             if (block.isReachable()) continue;
376 
377             block.setReachable(1);
378             BitSet succs = block.getSuccessors();
379             for (int i = succs.nextSetBit(0); i >= 0;
380                      i = succs.nextSetBit(i + 1)) {
381                 blockList.add(blocks.get(i));
382             }
383         }
384     }
385 
386     /**
387      * Remaps unversioned registers.
388      *
389      * @param mapper maps old registers to new.
390      */
mapRegisters(RegisterMapper mapper)391     public void mapRegisters(RegisterMapper mapper) {
392         for (SsaBasicBlock block : getBlocks()) {
393             for (SsaInsn insn : block.getInsns()) {
394                 insn.mapRegisters(mapper);
395             }
396         }
397 
398         registerCount = mapper.getNewRegisterCount();
399         spareRegisterBase = registerCount;
400     }
401 
402     /**
403      * Returns the insn that defines the given register
404      * @param reg register in question
405      * @return insn (actual instance from code) that defined this reg or null
406      * if reg is not defined.
407      */
getDefinitionForRegister(int reg)408     public SsaInsn getDefinitionForRegister(int reg) {
409         if (backMode) {
410             throw new RuntimeException("No def list in back mode");
411         }
412 
413         if (definitionList != null) {
414             return definitionList[reg];
415         }
416 
417         definitionList = new SsaInsn[getRegCount()];
418 
419         forEachInsn(new SsaInsn.Visitor() {
420             public void visitMoveInsn (NormalSsaInsn insn) {
421                 definitionList[insn.getResult().getReg()] = insn;
422             }
423             public void visitPhiInsn (PhiInsn phi) {
424                 definitionList[phi.getResult().getReg()] = phi;
425             }
426             public void visitNonMoveInsn (NormalSsaInsn insn) {
427                 RegisterSpec result = insn.getResult();
428                 if (result != null) {
429                     definitionList[insn.getResult().getReg()] = insn;
430                 }
431             }
432         });
433 
434         return definitionList[reg];
435     }
436 
437     /**
438      * Builds useList and unmodifiableUseList.
439      */
buildUseList()440     private void buildUseList() {
441         if (backMode) {
442             throw new RuntimeException("No use list in back mode");
443         }
444 
445         useList = new ArrayList[registerCount];
446 
447         for (int i = 0; i < registerCount; i++) {
448             useList[i] = new ArrayList();
449         }
450 
451         forEachInsn(new SsaInsn.Visitor() {
452             /** {@inheritDoc} */
453             public void visitMoveInsn (NormalSsaInsn insn) {
454                 addToUses(insn);
455             }
456             /** {@inheritDoc} */
457             public void visitPhiInsn (PhiInsn phi) {
458                 addToUses(phi);
459             }
460             /** {@inheritDoc} */
461             public void visitNonMoveInsn (NormalSsaInsn insn) {
462                 addToUses(insn);
463             }
464             /**
465              * Adds specified insn to the uses list for all of its sources.
466              * @param insn {@code non-null;} insn to process
467              */
468             private void addToUses(SsaInsn insn) {
469                 RegisterSpecList rl = insn.getSources();
470                 int sz = rl.size();
471 
472                 for (int i = 0; i < sz; i++) {
473                     useList[rl.get(i).getReg()].add(insn);
474                 }
475             }
476         });
477 
478         unmodifiableUseList = new List[registerCount];
479 
480         for (int i = 0; i < registerCount; i++) {
481             unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
482         }
483     }
484 
485     /**
486      * Updates the use list for a single change in source register.
487      *
488      * @param insn {@code non-null;} insn being changed
489      * @param oldSource {@code null-ok;} The source that was used, if
490      * applicable
491      * @param newSource {@code non-null;} the new source being used
492      */
onSourceChanged(SsaInsn insn, RegisterSpec oldSource, RegisterSpec newSource)493     /*package*/ void onSourceChanged(SsaInsn insn,
494             RegisterSpec oldSource, RegisterSpec newSource) {
495         if (useList == null) return;
496 
497         if (oldSource != null) {
498             int reg = oldSource.getReg();
499             useList[reg].remove(insn);
500         }
501 
502         int reg = newSource.getReg();
503         if (useList.length <= reg) {
504             useList = null;
505             return;
506         }
507         useList[reg].add(insn);
508     }
509 
510     /**
511      * Updates the use list for a source list change.
512      *
513      * @param insn {@code insn non-null;} insn being changed.
514      * {@code insn.getSources()} must return the new source list.
515      * @param oldSources {@code null-ok;} list of sources that were
516      * previously used
517      */
onSourcesChanged(SsaInsn insn, RegisterSpecList oldSources)518     /*package*/ void onSourcesChanged(SsaInsn insn,
519             RegisterSpecList oldSources) {
520         if (useList == null) return;
521 
522         if (oldSources != null) {
523             removeFromUseList(insn, oldSources);
524         }
525 
526         RegisterSpecList sources = insn.getSources();
527         int szNew = sources.size();
528 
529         for (int i = 0; i < szNew; i++) {
530             int reg = sources.get(i).getReg();
531             useList[reg].add(insn);
532         }
533     }
534 
535     /**
536      * Removes a given {@code insn} from the use lists for the given
537      * {@code oldSources} (rather than the sources currently
538      * returned by insn.getSources()).
539      *
540      * @param insn {@code non-null;} insn in question
541      * @param oldSources {@code null-ok;} registers whose use lists
542      * {@code insn} should be removed form
543      */
removeFromUseList(SsaInsn insn, RegisterSpecList oldSources)544     private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) {
545         if (oldSources == null) {
546             return;
547         }
548 
549         int szNew = oldSources.size();
550         for (int i = 0; i < szNew; i++) {
551             if (!useList[oldSources.get(i).getReg()].remove(insn)) {
552                 throw new RuntimeException("use not found");
553             }
554         }
555     }
556 
557     /**
558      * Adds an insn to both the use and def lists. For use when adding
559      * a new insn to the method.
560      *
561      * @param insn {@code non-null;} insn to add
562      */
onInsnAdded(SsaInsn insn)563     /*package*/ void onInsnAdded(SsaInsn insn) {
564         onSourcesChanged(insn, null);
565         updateOneDefinition(insn, null);
566     }
567 
568     /**
569      * Removes an instruction from use and def lists. For use during
570      * instruction removal.
571      *
572      * @param insn {@code non-null;} insn to remove
573      */
onInsnRemoved(SsaInsn insn)574     /*package*/ void onInsnRemoved(SsaInsn insn) {
575         if (useList != null) {
576             removeFromUseList(insn, insn.getSources());
577         }
578 
579         RegisterSpec resultReg = insn.getResult();
580         if (definitionList != null && resultReg != null) {
581             definitionList[resultReg.getReg()] = null;
582         }
583     }
584 
585     /**
586      * Indicates that the instruction list has changed or the SSA register
587      * count has increased, so that internal datastructures that rely on
588      * it should be rebuild. In general, the various other on* methods
589      * should be called in preference when changes occur if they are
590      * applicable.
591      */
onInsnsChanged()592     public void onInsnsChanged() {
593         // Definition list will need to be recomputed
594         definitionList = null;
595 
596         // Use list will need to be recomputed
597         useList = null;
598         unmodifiableUseList = null;
599     }
600 
601     /**
602      * Updates a single definition.
603      *
604      * @param insn {@code non-null;} insn who's result should be recorded as
605      * a definition
606      * @param oldResult {@code null-ok;} a previous result that should
607      * be no longer considered a definition by this insn
608      */
updateOneDefinition(SsaInsn insn, RegisterSpec oldResult)609     /*package*/ void updateOneDefinition(SsaInsn insn,
610             RegisterSpec oldResult) {
611         if (definitionList == null) return;
612 
613         if (oldResult != null) {
614             int reg = oldResult.getReg();
615             definitionList[reg] = null;
616         }
617 
618         RegisterSpec resultReg = insn.getResult();
619 
620         if (resultReg != null) {
621             int reg = resultReg.getReg();
622 
623             if (definitionList[reg] != null) {
624                 throw new RuntimeException("Duplicate add of insn");
625             } else {
626                 definitionList[resultReg.getReg()] = insn;
627             }
628         }
629     }
630 
631     /**
632      * Returns the list of all source uses (not results) for a register.
633      *
634      * @param reg register in question
635      * @return unmodifiable instruction list
636      */
getUseListForRegister(int reg)637     public List<SsaInsn> getUseListForRegister(int reg) {
638 
639         if (unmodifiableUseList == null) {
640             buildUseList();
641         }
642 
643         return unmodifiableUseList[reg];
644     }
645 
646     /**
647      * Returns a modifiable copy of the register use list.
648      *
649      * @return modifiable copy of the use-list, indexed by register
650      */
getUseListCopy()651     public ArrayList<SsaInsn>[] getUseListCopy() {
652         if (useList == null) {
653             buildUseList();
654         }
655 
656         ArrayList<SsaInsn>[] useListCopy
657                 = (ArrayList<SsaInsn>[])(new ArrayList[registerCount]);
658 
659         for (int i = 0; i < registerCount; i++) {
660             useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i]));
661         }
662 
663         return useListCopy;
664     }
665 
666     /**
667      * Checks to see if the given SSA reg is ever associated with a local
668      * local variable. Each SSA reg may be associated with at most one
669      * local var.
670      *
671      * @param spec {@code non-null;} ssa reg
672      * @return true if reg is ever associated with a local
673      */
isRegALocal(RegisterSpec spec)674     public boolean isRegALocal(RegisterSpec spec) {
675         SsaInsn defn = getDefinitionForRegister(spec.getReg());
676 
677         if (defn == null) {
678             // version 0 registers are never used as locals
679             return false;
680         }
681 
682         // Does the definition have a local associated with it?
683         if (defn.getLocalAssignment() != null) return true;
684 
685         // If not, is there a mark-local insn?
686         for (SsaInsn use : getUseListForRegister(spec.getReg())) {
687             Insn insn = use.getOriginalRopInsn();
688 
689             if (insn != null
690                     && insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
691                 return true;
692             }
693         }
694 
695         return false;
696     }
697 
698     /**
699      * Sets the new register count after renaming.
700      *
701      * @param newRegCount new register count
702      */
setNewRegCount(int newRegCount)703     /*package*/ void setNewRegCount(int newRegCount) {
704         registerCount = newRegCount;
705         spareRegisterBase = registerCount;
706         onInsnsChanged();
707     }
708 
709     /**
710      * Makes a new SSA register. For use after renaming has completed.
711      *
712      * @return {@code >=0;} new SSA register.
713      */
makeNewSsaReg()714     public int makeNewSsaReg() {
715         int reg = registerCount++;
716         spareRegisterBase = registerCount;
717         onInsnsChanged();
718         return reg;
719     }
720 
721     /**
722      * Visits all insns in this method.
723      *
724      * @param visitor {@code non-null;} callback interface
725      */
forEachInsn(SsaInsn.Visitor visitor)726     public void forEachInsn(SsaInsn.Visitor visitor) {
727         for (SsaBasicBlock block : blocks) {
728             block.forEachInsn(visitor);
729         }
730     }
731 
732     /**
733      * Visits each phi insn in this method
734      * @param v {@code non-null;} callback.
735      *
736      */
forEachPhiInsn(PhiInsn.Visitor v)737     public void forEachPhiInsn(PhiInsn.Visitor v) {
738         for (SsaBasicBlock block : blocks) {
739             block.forEachPhiInsn(v);
740         }
741     }
742 
743 
744     /**
745      * Walks the basic block tree in depth-first order, calling the visitor
746      * method once for every block. This depth-first walk may be run forward
747      * from the method entry point or backwards from the method exit points.
748      *
749      * @param reverse true if this should walk backwards from the exit points
750      * @param v {@code non-null;} callback interface. {@code parent} is set
751      * unless this is the root node
752      */
forEachBlockDepthFirst(boolean reverse, SsaBasicBlock.Visitor v)753     public void forEachBlockDepthFirst(boolean reverse,
754             SsaBasicBlock.Visitor v) {
755         BitSet visited = new BitSet(blocks.size());
756 
757         // We push the parent first, then the child on the stack.
758         Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
759 
760         SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
761 
762         if (rootBlock == null) {
763             // in the case there's no exit block
764             return;
765         }
766 
767         stack.add(null);    // Start with null parent.
768         stack.add(rootBlock);
769 
770         while (stack.size() > 0) {
771             SsaBasicBlock cur = stack.pop();
772             SsaBasicBlock parent = stack.pop();
773 
774             if (!visited.get(cur.getIndex())) {
775                 BitSet children
776                     = reverse ? cur.getPredecessors() : cur.getSuccessors();
777                 for (int i = children.nextSetBit(0); i >= 0
778                         ; i = children.nextSetBit(i + 1)) {
779                     stack.add(cur);
780                     stack.add(blocks.get(i));
781                 }
782                 visited.set(cur.getIndex());
783                 v.visitBlock(cur, parent);
784             }
785         }
786     }
787 
788     /**
789      * Visits blocks in dom-tree order, starting at the current node.
790      * The {@code parent} parameter of the Visitor.visitBlock callback
791      * is currently always set to null.
792      *
793      * @param v {@code non-null;} callback interface
794      */
forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v)795     public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) {
796         BitSet visited = new BitSet(getBlocks().size());
797         Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
798 
799         stack.add(getEntryBlock());
800 
801         while (stack.size() > 0) {
802             SsaBasicBlock cur = stack.pop();
803             ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren();
804 
805             if (!visited.get(cur.getIndex())) {
806                 // We walk the tree this way for historical reasons...
807                 for (int i = curDomChildren.size() - 1; i >= 0; i--) {
808                     SsaBasicBlock child = curDomChildren.get(i);
809                     stack.add(child);
810                 }
811                 visited.set(cur.getIndex());
812                 v.visitBlock(cur, null);
813             }
814         }
815     }
816 
817     /**
818      * Deletes all insns in the set from this method.
819      *
820      * @param deletedInsns {@code non-null;} insns to delete
821      */
deleteInsns(Set<SsaInsn> deletedInsns)822     public void deleteInsns(Set<SsaInsn> deletedInsns) {
823         for (SsaBasicBlock block : getBlocks()) {
824             ArrayList<SsaInsn> insns = block.getInsns();
825 
826             for (int i = insns.size() - 1; i >= 0; i--) {
827                 SsaInsn insn = insns.get(i);
828 
829                 if (deletedInsns.contains(insn)) {
830                     onInsnRemoved(insn);
831                     insns.remove(i);
832                 }
833             }
834 
835             // Check to see if we need to add a GOTO
836 
837             int insnsSz = insns.size();
838             SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1);
839 
840             if (block != getExitBlock() && (insnsSz == 0
841                     || lastInsn.getOriginalRopInsn() == null
842                     || lastInsn.getOriginalRopInsn().getOpcode()
843                         .getBranchingness() == Rop.BRANCH_NONE)) {
844                 // We managed to eat a throwable insn
845 
846                 Insn gotoInsn = new PlainInsn(Rops.GOTO,
847                         SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
848                 insns.add(SsaInsn.makeFromRop(gotoInsn, block));
849 
850                 // Remove secondary successors from this block
851                 BitSet succs = block.getSuccessors();
852                 for (int i = succs.nextSetBit(0); i >= 0;
853                          i = succs.nextSetBit(i + 1)) {
854                     if (i != block.getPrimarySuccessorIndex()) {
855                         block.removeSuccessor(i);
856                     }
857                 }
858             }
859         }
860     }
861 
862     /**
863      * Sets "back-convert mode". Set during back-conversion when registers
864      * are about to be mapped into a non-SSA namespace. When true,
865      * use and def lists are unavailable.
866      */
setBackMode()867     public void setBackMode() {
868         backMode = true;
869         useList = null;
870         definitionList = null;
871     }
872 }
873