Search in sources :

Example 16 with PlainInsn

use of com.taobao.android.dx.rop.code.PlainInsn in project atlas by alibaba.

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 : Insn(com.taobao.android.dx.rop.code.Insn) PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) ThrowingCstInsn(com.taobao.android.dx.rop.code.ThrowingCstInsn) BasicBlock(com.taobao.android.dx.rop.code.BasicBlock) InsnList(com.taobao.android.dx.rop.code.InsnList) IntList(com.taobao.android.dx.util.IntList) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) CstType(com.taobao.android.dx.rop.cst.CstType) SourcePosition(com.taobao.android.dx.rop.code.SourcePosition)

Example 17 with PlainInsn

use of com.taobao.android.dx.rop.code.PlainInsn in project atlas by alibaba.

the class Ropper method addReturnBlock.

/**
     * Constructs and adds the return block, if necessary. The return
     * block merely contains an appropriate {@code return}
     * instruction.
     */
private void addReturnBlock() {
    Rop returnOp = machine.getReturnOp();
    if (returnOp == null) {
        /*
             * The method being converted never returns normally, so there's
             * no need for a return block.
             */
        return;
    }
    SourcePosition returnPos = machine.getReturnPosition();
    int label = getSpecialLabel(RETURN);
    if (isSynchronized()) {
        InsnList insns = new InsnList(1);
        Insn insn = new ThrowingInsn(Rops.MONITOR_EXIT, returnPos, RegisterSpecList.make(getSynchReg()), StdTypeList.EMPTY);
        insns.set(0, insn);
        insns.setImmutable();
        int nextLabel = getSpecialLabel(SYNCH_RETURN);
        BasicBlock bb = new BasicBlock(label, insns, IntList.makeImmutable(nextLabel), nextLabel);
        addBlock(bb, IntList.EMPTY);
        label = nextLabel;
    }
    InsnList insns = new InsnList(1);
    TypeList sourceTypes = returnOp.getSources();
    RegisterSpecList sources;
    if (sourceTypes.size() == 0) {
        sources = RegisterSpecList.EMPTY;
    } else {
        RegisterSpec source = RegisterSpec.make(0, sourceTypes.getType(0));
        sources = RegisterSpecList.make(source);
    }
    Insn insn = new PlainInsn(returnOp, returnPos, null, sources);
    insns.set(0, insn);
    insns.setImmutable();
    BasicBlock bb = new BasicBlock(label, insns, IntList.EMPTY, -1);
    addBlock(bb, IntList.EMPTY);
}
Also used : PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) Rop(com.taobao.android.dx.rop.code.Rop) Insn(com.taobao.android.dx.rop.code.Insn) PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) ThrowingCstInsn(com.taobao.android.dx.rop.code.ThrowingCstInsn) SourcePosition(com.taobao.android.dx.rop.code.SourcePosition) BasicBlock(com.taobao.android.dx.rop.code.BasicBlock) InsnList(com.taobao.android.dx.rop.code.InsnList) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) RegisterSpecList(com.taobao.android.dx.rop.code.RegisterSpecList) StdTypeList(com.taobao.android.dx.rop.type.StdTypeList) TypeList(com.taobao.android.dx.rop.type.TypeList) RegisterSpec(com.taobao.android.dx.rop.code.RegisterSpec)

Aggregations

PlainInsn (com.taobao.android.dx.rop.code.PlainInsn)17 Insn (com.taobao.android.dx.rop.code.Insn)10 PlainCstInsn (com.taobao.android.dx.rop.code.PlainCstInsn)9 RegisterSpec (com.taobao.android.dx.rop.code.RegisterSpec)9 ThrowingCstInsn (com.taobao.android.dx.rop.code.ThrowingCstInsn)8 ThrowingInsn (com.taobao.android.dx.rop.code.ThrowingInsn)7 RegisterSpecList (com.taobao.android.dx.rop.code.RegisterSpecList)6 SourcePosition (com.taobao.android.dx.rop.code.SourcePosition)6 BasicBlock (com.taobao.android.dx.rop.code.BasicBlock)5 InsnList (com.taobao.android.dx.rop.code.InsnList)5 Rop (com.taobao.android.dx.rop.code.Rop)5 CstType (com.taobao.android.dx.rop.cst.CstType)3 FillArrayDataInsn (com.taobao.android.dx.rop.code.FillArrayDataInsn)2 StdTypeList (com.taobao.android.dx.rop.type.StdTypeList)2 Type (com.taobao.android.dx.rop.type.Type)2 IntList (com.taobao.android.dx.util.IntList)2 BitSet (java.util.BitSet)2 CstInsn (com.taobao.android.dx.rop.code.CstInsn)1 LocalItem (com.taobao.android.dx.rop.code.LocalItem)1 SwitchInsn (com.taobao.android.dx.rop.code.SwitchInsn)1