FileDocCategorySizeDatePackage
SsaToRop.javaAPI DocAndroid 1.5 API12305Wed May 06 22:41:02 BST 2009com.android.dx.ssa.back

SsaToRop

public class SsaToRop extends Object
Converts a method in SSA form to ROP form.

Fields Summary
private static final boolean
DEBUG
private final com.android.dx.ssa.SsaMethod
ssaMeth
non-null; method to process
private final boolean
minimizeRegisters
true if the converter should attempt to minimize the rop-form register count
private InterferenceGraph
interference
interference graph
Constructors Summary
private SsaToRop(com.android.dx.ssa.SsaMethod ssaMethod, boolean minimizeRegisters)

        this.minimizeRegisters = minimizeRegisters;
        this.ssaMeth = ssaMethod;
    
Methods Summary
private com.android.dx.rop.code.RopMethodconvert()

        interference = LivenessAnalyzer.constructInterferenceGraph(ssaMeth);

        if (DEBUG) {
            interference.dumpToStdout();
        }

        RegisterAllocator allocator;
        RegisterMapper mapper;

        // These are other allocators for debugging or historical comparison

        //allocator = new NullRegisterAllocator(ssaMeth, interference);
        //allocator = new FirstFitAllocator(ssaMeth, interference);

        allocator = new FirstFitLocalCombiningAllocator(ssaMeth, interference,
                minimizeRegisters);

        mapper = allocator.allocateRegisters();

        if (DEBUG) {
            System.out.println("Printing reg map");
            System.out.println(((BasicRegisterMapper)mapper).toHuman());
        }        

        ssaMeth.setBackMode();

        ssaMeth.mapRegisters(mapper);

        removePhiFunctions();

        if (allocator.wantsParamsMovedHigh()) {
            moveParametersToHighRegisters();
        }

        removeEmptyGotos();

        RopMethod ropMethod;

        ropMethod = convertToRop();

        ropMethod = new IdenticalBlockCombiner(ropMethod).process();

        return ropMethod;
    
private com.android.dx.rop.code.BasicBlockconvertBasicBlock(com.android.dx.ssa.SsaBasicBlock block)
Converts a single basic block to rop form.

param
block SSA block to process
return
ROP block

        BasicBlock result;
        IntList successorList = block.getRopLabelSuccessorList();
        int primarySuccessorLabel = block.getPrimarySuccessorRopLabel();
        // Filter out any reference to the SSA form's exit block

        // exit block may be null
        SsaBasicBlock exitBlock = ssaMeth.getExitBlock();

        int exitRopLabel = (exitBlock == null) ? -1 : exitBlock.getRopLabel();

        if (successorList.contains(exitRopLabel)) {
            if (successorList.size() > 1) {
                throw new RuntimeException (
                        "Exit predecessor must have no other successors"
                                + Hex.u2(block.getRopLabel()));
            } else {
                successorList = IntList.EMPTY;
                primarySuccessorLabel = -1;

                verifyValidExitPredecessor(block);
            }
        }

        successorList.setImmutable();

        result = new BasicBlock(
                block.getRopLabel(), convertInsns(block.getInsns()),
                successorList,
                primarySuccessorLabel);

        return result;
    
private com.android.dx.rop.code.BasicBlockListconvertBasicBlocks()

return
rop-form basic block list

        ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
        // Exit block may be null
        SsaBasicBlock exitBlock = ssaMeth.getExitBlock();

        int ropBlockCount = ssaMeth.getCountReachableBlocks();

        // Don't count the exit block, if it exists
        ropBlockCount -= (exitBlock == null) ? 0 : 1;

        BasicBlockList result = new BasicBlockList(ropBlockCount);

        // Convert all the reachable blocks except the exit block
        int ropBlockIndex = 0;
        for(SsaBasicBlock b : blocks) {
            if (b.isReachable() && b != exitBlock) {
                result.set(ropBlockIndex++, convertBasicBlock(b));
            }
        }

        // The exit block, which is discarded, must do nothing.
        if (exitBlock != null && exitBlock.getInsns().size() != 0) {
            throw new RuntimeException
                    ("Exit block must have no insns when leaving SSA form");
        }

        return result;
    
private com.android.dx.rop.code.InsnListconvertInsns(java.util.ArrayList ssaInsns)
Converts an insn list to rop form

param
ssaInsns non-null;old instructions
return
non-null; immutable instruction list

        InsnList result;
        int insnCount;

        insnCount = ssaInsns.size();
        result = new InsnList (insnCount);

        for (int i = 0; i < insnCount; i++) {
            result.set(i, ssaInsns.get(i).toRopInsn());
        }

        result.setImmutable();

        return result;
    
private com.android.dx.rop.code.RopMethodconvertToRop()

        return new RopMethod(convertBasicBlocks(),
                ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
    
public static com.android.dx.rop.code.RopMethodconvertToRopMethod(com.android.dx.ssa.SsaMethod ssaMeth, boolean minimizeRegisters)
Converts a method in SSA form to ROP form.

param
ssaMeth input
return
non-null; rop-form output


                         
        
              
        return new SsaToRop(ssaMeth, minimizeRegisters).convert();
    
public int[]getRegistersByFrequency()
This method is not presently used.

return
a list of registers ordered by most-frequently-used to least-frequently-used. Each register is listed once and only once.

        int regCount = ssaMeth.getRegCount();
        Integer[] ret = new Integer[ssaMeth.getRegCount()];

        for (int i = 0; i < regCount; i++) {
            ret[i] = i;
        }

        java.util.Arrays.sort(ret, new java.util.Comparator<Integer>() {
            public int compare (Integer o1, Integer o2) {
                return ssaMeth.getUseListForRegister(o2).size()
                        - ssaMeth.getUseListForRegister(o1).size();
            }

            public boolean equals(Object o) {
                return o == this;
            }
        });

        int result[] = new int[regCount];

        for (int i = 0; i < regCount; i++) {
            result[i] = ret[i];
        }

        return result;
    
private voidmoveParametersToHighRegisters()
Moves the parameter registers, which allocateRegisters() places at the bottom of the frame, up to the top of the frame to match Dalvik calling convention.


        int paramWidth = ssaMeth.getParamWidth();

        BasicRegisterMapper mapper
                = new BasicRegisterMapper(ssaMeth.getRegCount());
        int regCount = ssaMeth.getRegCount();

        for (int i = 0; i < regCount; i++) {
            if (i < paramWidth) {
                mapper.addMapping(i, regCount - paramWidth + i, 1);
            } else {
                mapper.addMapping(i, i - paramWidth, 1);
            }
        }

        if (DEBUG) {
            System.out.printf("Moving %d registers from 0 to %d\n",
                    paramWidth, regCount - paramWidth);
        }

        ssaMeth.mapRegisters(mapper);
    
private voidremoveEmptyGotos()
Removes all blocks containing only GOTOs from the control flow. Although much of this work will be done later when converting from rop to dex, not all simplification cases can be handled there. Furthermore, any no-op block between the exit block and blocks containing the real return or throw statements must be removed.

        final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();

        ssaMeth.forEachBlockDepthFirst(false, new SsaBasicBlock.Visitor() {
            public void visitBlock(SsaBasicBlock b, SsaBasicBlock parent) {
                ArrayList<SsaInsn> insns = b.getInsns();

                if ((insns.size() == 1)
                        && (insns.get(0).getOpcode() == Rops.GOTO)) {

                    BitSet preds = (BitSet)b.getPredecessors().clone();

                    for (int i = preds.nextSetBit(0); i >= 0;
                            i = preds.nextSetBit(i + 1)) {
                        SsaBasicBlock pb = blocks.get(i);
                        pb.replaceSuccessor(b.getIndex(),
                                b.getPrimarySuccessorIndex());
                    }
                }
            }
        });
    
private voidremovePhiFunctions()
See Appel 19.6 To remove the phi instructions in an edge-split SSA representation we know we can always insert a move in a predecessor block

        for (SsaBasicBlock block: ssaMeth.getBlocks()) {
            // Add moves in all the pred blocks for each phi insn`
            block.forEachPhiInsn(new PhiVisitor(block));
            // Delete the phi insns
            block.removeAllPhiInsns();
        }

        /*
         * After all move insns have been added: sort them so they don't
         * destructively interfere
         */
        for (SsaBasicBlock block: ssaMeth.getBlocks()) {
            block.scheduleMovesFromPhis();
        }
    
private voidverifyValidExitPredecessor(com.android.dx.ssa.SsaBasicBlock b)
Validates that a basic block is a valid end predecessor. It must end in a RETURN or a THROW. Throws a runtime exception on error.

param
b non-null; block to validate
throws
RuntimeException on error


        ArrayList<SsaInsn> insns = b.getInsns();
        SsaInsn lastInsn = insns.get(insns.size() - 1);
        Rop opcode = lastInsn.getOpcode();

        if (opcode.getBranchingness() != Rop.BRANCH_RETURN
                && opcode != Rops.THROW) {
            throw new RuntimeException("Exit predecessor must end"
                    + " in valid exit statement.");
        }