FileDocCategorySizeDatePackage
SsaToRop.javaAPI DocAndroid 5.1 API12568Thu Mar 12 22:18:30 GMT 2015com.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
local debug flag
private final com.android.dx.ssa.SsaMethod
ssaMeth
{@code non-null;} method to process
private final boolean
minimizeRegisters
{@code true} if the converter should attempt to minimize the rop-form register count
private final InterferenceGraph
interference
{@code non-null;} interference graph
Constructors Summary
private SsaToRop(com.android.dx.ssa.SsaMethod ssaMethod, boolean minimizeRegisters)
Constructs an instance.

param
ssaMeth {@code non-null;} method to process
param
minimizeRegisters {@code true} if the converter should attempt to minimize the rop-form register count

        this.minimizeRegisters = minimizeRegisters;
        this.ssaMeth = ssaMethod;
        this.interference =
            LivenessAnalyzer.constructInterferenceGraph(ssaMethod);
    
Methods Summary
private com.android.dx.rop.code.RopMethodconvert()
Performs the conversion.

return
{@code non-null;} rop-form output

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

        // These are other allocators for debugging or historical comparison:
        // allocator = new NullRegisterAllocator(ssaMeth, interference);
        // allocator = new FirstFitAllocator(ssaMeth, interference);

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

        RegisterMapper 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 = new RopMethod(convertBasicBlocks(),
                ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
        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
{@code non-null;} ROP block

        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();

        BasicBlock 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();

        ssaMeth.computeReachability();
        int ropBlockCount = ssaMeth.getCountReachableBlocks();

        // Don't count the exit block, if it exists and is reachable.
        ropBlockCount -= (exitBlock != null && exitBlock.isReachable()) ? 1 : 0;

        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 {@code non-null;} old instructions
return
{@code non-null;} immutable instruction list

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

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

        result.setImmutable();

        return result;
    
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 {@code non-null;} method to process
param
minimizeRegisters {@code true} if the converter should attempt to minimize the rop-form register count
return
{@code non-null;} rop-form output


                                             
        
              
        return new SsaToRop(ssaMeth, minimizeRegisters).convert();
    
public int[]getRegistersByFrequency()
Note: 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[regCount];

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

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

        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.

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

        for (SsaBasicBlock block : blocks) {
            // Add moves in all the pred blocks for each phi insn.
            block.forEachPhiInsn(new PhiVisitor(blocks));

            // Delete the phi insns.
            block.removeAllPhiInsns();
        }

        /*
         * After all move insns have been added, sort them so they don't
         * destructively interfere.
         */
        for (SsaBasicBlock block : blocks) {
            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 {@code 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.");
        }