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
17package com.android.dx.ssa;
18
19import com.android.dx.rop.code.BasicBlockList;
20import com.android.dx.rop.code.Insn;
21import com.android.dx.rop.code.PlainInsn;
22import com.android.dx.rop.code.RegOps;
23import com.android.dx.rop.code.RegisterSpec;
24import com.android.dx.rop.code.RegisterSpecList;
25import com.android.dx.rop.code.Rop;
26import com.android.dx.rop.code.RopMethod;
27import com.android.dx.rop.code.Rops;
28import com.android.dx.rop.code.SourcePosition;
29import com.android.dx.util.IntList;
30import java.util.ArrayList;
31import java.util.BitSet;
32import java.util.Collections;
33import java.util.List;
34import java.util.Set;
35import java.util.Stack;
36
37/**
38 * A method in SSA form.
39 */
40public 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     * 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
867    public void setBackMode() {
868        backMode = true;
869        useList = null;
870        definitionList = null;
871    }
872}
873