Search in sources :

Example 31 with IntList

use of com.android.dx.util.IntList in project buck by facebook.

the class BasicBlockList method preferredSuccessorOf.

/**
     * Gets the preferred successor for the given block. If the block
     * only has one successor, then that is the preferred successor.
     * Otherwise, if the block has a primay successor, then that is
     * the preferred successor. If the block has no successors, then
     * this returns {@code null}.
     *
     * @param block {@code non-null;} the block in question
     * @return {@code null-ok;} the preferred successor, if any
     */
public BasicBlock preferredSuccessorOf(BasicBlock block) {
    int primarySuccessor = block.getPrimarySuccessor();
    IntList successors = block.getSuccessors();
    int succSize = successors.size();
    switch(succSize) {
        case 0:
            {
                return null;
            }
        case 1:
            {
                return labelToBlock(successors.get(0));
            }
    }
    if (primarySuccessor != -1) {
        return labelToBlock(primarySuccessor);
    } else {
        return labelToBlock(successors.get(0));
    }
}
Also used : IntList(com.android.dx.util.IntList)

Example 32 with IntList

use of com.android.dx.util.IntList in project buck by facebook.

the class SsaBasicBlock method getRopLabelSuccessorList.

/**
     * @return successor list of rop labels
     */
public IntList getRopLabelSuccessorList() {
    IntList result = new IntList(successorList.size());
    int sz = successorList.size();
    for (int i = 0; i < sz; i++) {
        result.add(parent.blockIndexToRopLabel(successorList.get(i)));
    }
    return result;
}
Also used : IntList(com.android.dx.util.IntList)

Example 33 with IntList

use of com.android.dx.util.IntList in project buck by facebook.

the class BlockDumper method ropDump.

/**
     * Does a registerizing dump.
     *
     * @param meth {@code non-null;} method data to dump
     */
private void ropDump(ConcreteMethod meth) {
    TranslationAdvice advice = DexTranslationAdvice.THE_ONE;
    BytecodeArray code = meth.getCode();
    ByteArray bytes = code.getBytes();
    RopMethod rmeth = Ropper.convert(meth, advice, classFile.getMethods());
    StringBuffer sb = new StringBuffer(2000);
    if (optimize) {
        boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());
        int paramWidth = computeParamWidth(meth, isStatic);
        rmeth = Optimizer.optimize(rmeth, paramWidth, isStatic, true, advice);
    }
    BasicBlockList blocks = rmeth.getBlocks();
    int[] order = blocks.getLabelsInOrder();
    sb.append("first " + Hex.u2(rmeth.getFirstLabel()) + "\n");
    for (int label : order) {
        BasicBlock bb = blocks.get(blocks.indexOfLabel(label));
        sb.append("block ");
        sb.append(Hex.u2(label));
        sb.append("\n");
        IntList preds = rmeth.labelToPredecessors(label);
        int psz = preds.size();
        for (int i = 0; i < psz; i++) {
            sb.append("  pred ");
            sb.append(Hex.u2(preds.get(i)));
            sb.append("\n");
        }
        InsnList il = bb.getInsns();
        int ilsz = il.size();
        for (int i = 0; i < ilsz; i++) {
            Insn one = il.get(i);
            sb.append("  ");
            sb.append(il.get(i).toHuman());
            sb.append("\n");
        }
        IntList successors = bb.getSuccessors();
        int ssz = successors.size();
        if (ssz == 0) {
            sb.append("  returns\n");
        } else {
            int primary = bb.getPrimarySuccessor();
            for (int i = 0; i < ssz; i++) {
                int succ = successors.get(i);
                sb.append("  next ");
                sb.append(Hex.u2(succ));
                if ((ssz != 1) && (succ == primary)) {
                    sb.append(" *");
                }
                sb.append("\n");
            }
        }
    }
    suppressDump = false;
    setAt(bytes, 0);
    parsed(bytes, 0, bytes.size(), sb.toString());
    suppressDump = true;
}
Also used : BytecodeArray(com.android.dx.cf.code.BytecodeArray) Insn(com.android.dx.rop.code.Insn) RopMethod(com.android.dx.rop.code.RopMethod) BasicBlock(com.android.dx.rop.code.BasicBlock) DexTranslationAdvice(com.android.dx.rop.code.DexTranslationAdvice) TranslationAdvice(com.android.dx.rop.code.TranslationAdvice) InsnList(com.android.dx.rop.code.InsnList) IntList(com.android.dx.util.IntList) ByteArray(com.android.dx.util.ByteArray) BasicBlockList(com.android.dx.rop.code.BasicBlockList)

Example 34 with IntList

use of com.android.dx.util.IntList in project buck by facebook.

the class Ropper method deleteUnreachableBlocks.

/**
     * Deletes all blocks that cannot be reached. This is run to delete
     * original subroutine blocks after subroutine inlining.
     */
private void deleteUnreachableBlocks() {
    final IntList reachableLabels = new IntList(result.size());
    // subroutine inlining is done now and we won't update this list here
    resultSubroutines.clear();
    forEachNonSubBlockDepthFirst(getSpecialLabel(PARAM_ASSIGNMENT), new BasicBlock.Visitor() {

        public void visitBlock(BasicBlock b) {
            reachableLabels.add(b.getLabel());
        }
    });
    reachableLabels.sort();
    for (int i = result.size() - 1; i >= 0; i--) {
        if (reachableLabels.indexOf(result.get(i).getLabel()) < 0) {
            result.remove(i);
        // unnecessary here really, since subroutine inlining is done
        //resultSubroutines.remove(i);
        }
    }
}
Also used : BasicBlock(com.android.dx.rop.code.BasicBlock) IntList(com.android.dx.util.IntList)

Example 35 with IntList

use of com.android.dx.util.IntList in project buck by facebook.

the class Ropper method processBlock.

/**
     * Processes the given block.
     *
     * @param block {@code non-null;} block to process
     * @param frame {@code non-null;} start frame for the block
     * @param workSet {@code non-null;} bits representing work to do,
     * which this method may add to
     */
private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
    // Prepare the list of caught exceptions for this block.
    ByteCatchList catches = block.getCatches();
    machine.startBlock(catches.toRopCatchList());
    /*
         * Using a copy of the given frame, simulate each instruction,
         * calling into machine for each.
         */
    frame = frame.copy();
    sim.simulate(block, frame);
    frame.setImmutable();
    int extraBlockCount = machine.getExtraBlockCount();
    ArrayList<Insn> insns = machine.getInsns();
    int insnSz = insns.size();
    /*
         * Merge the frame into each possible non-exceptional
         * successor.
         */
    int catchSz = catches.size();
    IntList successors = block.getSuccessors();
    int startSuccessorIndex;
    Subroutine calledSubroutine = null;
    if (machine.hasJsr()) {
        /*
             * If this frame ends in a JSR, only merge our frame with
             * the subroutine start, not the subroutine's return target.
             */
        startSuccessorIndex = 1;
        int subroutineLabel = successors.get(1);
        if (subroutines[subroutineLabel] == null) {
            subroutines[subroutineLabel] = new Subroutine(subroutineLabel);
        }
        subroutines[subroutineLabel].addCallerBlock(block.getLabel());
        calledSubroutine = subroutines[subroutineLabel];
    } else if (machine.hasRet()) {
        /*
             * This block ends in a ret, which means it's the final block
             * in some subroutine. Ultimately, this block will be copied
             * and inlined for each call and then disposed of.
             */
        ReturnAddress ra = machine.getReturnAddress();
        int subroutineLabel = ra.getSubroutineAddress();
        if (subroutines[subroutineLabel] == null) {
            subroutines[subroutineLabel] = new Subroutine(subroutineLabel, block.getLabel());
        } else {
            subroutines[subroutineLabel].addRetBlock(block.getLabel());
        }
        successors = subroutines[subroutineLabel].getSuccessors();
        subroutines[subroutineLabel].mergeToSuccessors(frame, workSet);
        // Skip processing below since we just did it.
        startSuccessorIndex = successors.size();
    } else if (machine.wereCatchesUsed()) {
        /*
             * If there are catches, then the first successors
             * (which will either be all of them or all but the last one)
             * are catch targets.
             */
        startSuccessorIndex = catchSz;
    } else {
        startSuccessorIndex = 0;
    }
    int succSz = successors.size();
    for (int i = startSuccessorIndex; i < succSz; i++) {
        int succ = successors.get(i);
        try {
            mergeAndWorkAsNecessary(succ, block.getLabel(), calledSubroutine, frame, workSet);
        } catch (SimException ex) {
            ex.addContext("...while merging to block " + Hex.u2(succ));
            throw ex;
        }
    }
    if ((succSz == 0) && machine.returns()) {
        /*
             * The block originally contained a return, but it has
             * been made to instead end with a goto, and we need to
             * tell it at this point that its sole successor is the
             * return block. This has to happen after the merge loop
             * above, since, at this point, the return block doesn't
             * actually exist; it gets synthesized at the end of
             * processing the original blocks.
             */
        successors = IntList.makeImmutable(getSpecialLabel(RETURN));
        succSz = 1;
    }
    int primarySucc;
    if (succSz == 0) {
        primarySucc = -1;
    } else {
        primarySucc = machine.getPrimarySuccessorIndex();
        if (primarySucc >= 0) {
            primarySucc = successors.get(primarySucc);
        }
    }
    /*
         * This variable is true only when the method is synchronized and
         * the block being processed can possibly throw an exception.
         */
    boolean synch = isSynchronized() && machine.canThrow();
    if (synch || (catchSz != 0)) {
        /*
             * Deal with exception handlers: Merge an exception-catch
             * frame into each possible exception handler, and
             * construct a new set of successors to point at the
             * exception handler setup blocks (which get synthesized
             * at the very end of processing).
             */
        boolean catchesAny = false;
        IntList newSucc = new IntList(succSz);
        for (int i = 0; i < catchSz; i++) {
            ByteCatchList.Item one = catches.get(i);
            CstType exceptionClass = one.getExceptionClass();
            int targ = one.getHandlerPc();
            catchesAny |= (exceptionClass == CstType.OBJECT);
            Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
            try {
                mergeAndWorkAsNecessary(targ, block.getLabel(), null, f, workSet);
            } catch (SimException ex) {
                ex.addContext("...while merging exception to block " + Hex.u2(targ));
                throw ex;
            }
            /*
                 * Set up the exception handler type.
                 */
            CatchInfo handlers = catchInfos[targ];
            if (handlers == null) {
                handlers = new CatchInfo();
                catchInfos[targ] = handlers;
            }
            ExceptionHandlerSetup handler = handlers.getSetup(exceptionClass.getClassType());
            /*
                 * The synthesized exception setup block will have the label given by handler.
                 */
            newSucc.add(handler.getLabel());
        }
        if (synch && !catchesAny) {
            /*
                 * The method is synchronized and this block doesn't
                 * already have a catch-all handler, so add one to the
                 * end, both in the successors and in the throwing
                 * instruction(s) at the end of the block (which is where
                 * the caught classes live).
                 */
            newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
            synchNeedsExceptionHandler = true;
            for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
                Insn insn = insns.get(i);
                if (insn.canThrow()) {
                    insn = insn.withAddedCatch(Type.OBJECT);
                    insns.set(i, insn);
                }
            }
        }
        if (primarySucc >= 0) {
            newSucc.add(primarySucc);
        }
        newSucc.setImmutable();
        successors = newSucc;
    }
    // Construct the final resulting block(s), and store it (them).
    int primarySuccListIndex = successors.indexOf(primarySucc);
    /*
         * If there are any extra blocks, work backwards through the
         * list of instructions, adding single-instruction blocks, and
         * resetting the successors variables as appropriate.
         */
    for (; /*extraBlockCount*/
    extraBlockCount > 0; extraBlockCount--) {
        /*
             * Some of the blocks that the RopperMachine wants added
             * are for move-result insns, and these need goto insns as well.
             */
        Insn extraInsn = insns.get(--insnSz);
        boolean needsGoto = extraInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE;
        InsnList il = new InsnList(needsGoto ? 2 : 1);
        IntList extraBlockSuccessors = successors;
        il.set(0, extraInsn);
        if (needsGoto) {
            il.set(1, new PlainInsn(Rops.GOTO, extraInsn.getPosition(), null, RegisterSpecList.EMPTY));
            /*
                 * Obviously, this block won't be throwing an exception
                 * so it should only have one successor.
                 */
            extraBlockSuccessors = IntList.makeImmutable(primarySucc);
        }
        il.setImmutable();
        int label = getAvailableLabel();
        BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors, primarySucc);
        // All of these extra blocks will be in the same subroutine
        addBlock(bb, frame.getSubroutines());
        successors = successors.mutableCopy();
        successors.set(primarySuccListIndex, label);
        successors.setImmutable();
        primarySucc = label;
    }
    Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
    /*
         * Add a goto to the end of the block if it doesn't already
         * end with a branch, to maintain the invariant that all
         * blocks end with a branch of some sort or other. Note that
         * it is possible for there to be blocks for which no
         * instructions were ever output (e.g., only consist of pop*
         * in the original Java bytecode).
         */
    if ((lastInsn == null) || (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
        SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO : lastInsn.getPosition();
        insns.add(new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY));
        insnSz++;
    }
    /*
         * Construct a block for the remaining instructions (which in
         * the usual case is all of them).
         */
    InsnList il = new InsnList(insnSz);
    for (int i = 0; i < insnSz; i++) {
        il.set(i, insns.get(i));
    }
    il.setImmutable();
    BasicBlock bb = new BasicBlock(block.getLabel(), il, successors, primarySucc);
    addOrReplaceBlock(bb, frame.getSubroutines());
}
Also used : ThrowingCstInsn(com.android.dx.rop.code.ThrowingCstInsn) ThrowingInsn(com.android.dx.rop.code.ThrowingInsn) PlainInsn(com.android.dx.rop.code.PlainInsn) Insn(com.android.dx.rop.code.Insn) PlainCstInsn(com.android.dx.rop.code.PlainCstInsn) BasicBlock(com.android.dx.rop.code.BasicBlock) InsnList(com.android.dx.rop.code.InsnList) IntList(com.android.dx.util.IntList) PlainInsn(com.android.dx.rop.code.PlainInsn) CstType(com.android.dx.rop.cst.CstType) SourcePosition(com.android.dx.rop.code.SourcePosition)

Aggregations

IntList (com.android.dx.util.IntList)56 BasicBlock (com.android.dx.rop.code.BasicBlock)20 CstType (com.android.dx.rop.cst.CstType)7 Insn (com.android.dx.rop.code.Insn)5 RopMethod (com.android.dx.rop.code.RopMethod)5 BasicBlockList (com.android.dx.rop.code.BasicBlockList)4 PlainCstInsn (com.android.dx.rop.code.PlainCstInsn)4 PlainInsn (com.android.dx.rop.code.PlainInsn)4 RegisterSpec (com.android.dx.rop.code.RegisterSpec)4 SourcePosition (com.android.dx.rop.code.SourcePosition)4 ThrowingCstInsn (com.android.dx.rop.code.ThrowingCstInsn)4 ThrowingInsn (com.android.dx.rop.code.ThrowingInsn)4 Type (com.android.dx.rop.type.Type)4 TypeList (com.android.dx.rop.type.TypeList)4 DexTranslationAdvice (com.android.dx.rop.code.DexTranslationAdvice)3 InsnList (com.android.dx.rop.code.InsnList)3 TranslationAdvice (com.android.dx.rop.code.TranslationAdvice)3 SsaBasicBlock (com.android.dx.ssa.SsaBasicBlock)3 ArrayList (java.util.ArrayList)3 BitSet (java.util.BitSet)3