Search in sources :

Example 6 with SourcePosition

use of com.taobao.android.dx.rop.code.SourcePosition 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 7 with SourcePosition

use of com.taobao.android.dx.rop.code.SourcePosition 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)

Example 8 with SourcePosition

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

the class PositionList method make.

/**
     * Extracts and returns the source position information out of an
     * instruction list.
     *
     * @param insns {@code non-null;} instructions to convert
     * @param howMuch how much information should be included; one of the
     * static constants defined by this class
     * @return {@code non-null;} the positions list
     */
public static PositionList make(DalvInsnList insns, int howMuch) {
    switch(howMuch) {
        case NONE:
            {
                return EMPTY;
            }
        case LINES:
        case IMPORTANT:
            {
                // Valid.
                break;
            }
        default:
            {
                throw new IllegalArgumentException("bogus howMuch");
            }
    }
    SourcePosition noInfo = SourcePosition.NO_INFO;
    SourcePosition cur = noInfo;
    int sz = insns.size();
    Entry[] arr = new Entry[sz];
    boolean lastWasTarget = false;
    int at = 0;
    for (int i = 0; i < sz; i++) {
        DalvInsn insn = insns.get(i);
        if (insn instanceof CodeAddress) {
            lastWasTarget = true;
            ;
            continue;
        }
        SourcePosition pos = insn.getPosition();
        if (pos.equals(noInfo) || pos.sameLine(cur)) {
            continue;
        }
        if ((howMuch == IMPORTANT) && !lastWasTarget) {
            continue;
        }
        cur = pos;
        arr[at] = new Entry(insn.getAddress(), pos);
        at++;
        lastWasTarget = false;
    }
    PositionList result = new PositionList(at);
    for (int i = 0; i < at; i++) {
        result.set(i, arr[i]);
    }
    result.setImmutable();
    return result;
}
Also used : SourcePosition(com.taobao.android.dx.rop.code.SourcePosition)

Example 9 with SourcePosition

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

the class DebugInfoEncoder method emitPosition.

/**
     * Emits the necessary byte sequences to emit the given position table
     * entry. This will typically be a single special opcode, although
     * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
     *
     * @param entry position entry to emit.
     * @throws IOException
     */
private void emitPosition(PositionList.Entry entry) throws IOException {
    SourcePosition pos = entry.getPosition();
    int newLine = pos.getLine();
    int newAddress = entry.getAddress();
    int opcode;
    int deltaLines = newLine - line;
    int deltaAddress = newAddress - address;
    if (deltaAddress < 0) {
        throw new RuntimeException("Position entries must be in ascending address order");
    }
    if ((deltaLines < DBG_LINE_BASE) || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE - 1))) {
        emitAdvanceLine(deltaLines);
        deltaLines = 0;
    }
    opcode = computeOpcode(deltaLines, deltaAddress);
    if ((opcode & ~0xff) > 0) {
        emitAdvancePc(deltaAddress);
        deltaAddress = 0;
        opcode = computeOpcode(deltaLines, deltaAddress);
        if ((opcode & ~0xff) > 0) {
            emitAdvanceLine(deltaLines);
            deltaLines = 0;
            opcode = computeOpcode(deltaLines, deltaAddress);
        }
    }
    output.writeByte(opcode);
    line += deltaLines;
    address += deltaAddress;
    if (annotateTo != null || debugPrint != null) {
        annotate(1, String.format("%04x: line %d", address, line));
    }
}
Also used : SourcePosition(com.taobao.android.dx.rop.code.SourcePosition)

Aggregations

SourcePosition (com.taobao.android.dx.rop.code.SourcePosition)9 Insn (com.taobao.android.dx.rop.code.Insn)7 BasicBlock (com.taobao.android.dx.rop.code.BasicBlock)6 PlainCstInsn (com.taobao.android.dx.rop.code.PlainCstInsn)6 PlainInsn (com.taobao.android.dx.rop.code.PlainInsn)6 ThrowingCstInsn (com.taobao.android.dx.rop.code.ThrowingCstInsn)6 ThrowingInsn (com.taobao.android.dx.rop.code.ThrowingInsn)6 InsnList (com.taobao.android.dx.rop.code.InsnList)5 RegisterSpec (com.taobao.android.dx.rop.code.RegisterSpec)4 CstType (com.taobao.android.dx.rop.cst.CstType)3 RegisterSpecList (com.taobao.android.dx.rop.code.RegisterSpecList)2 Rop (com.taobao.android.dx.rop.code.Rop)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 BasicBlockList (com.taobao.android.dx.rop.code.BasicBlockList)1 FillArrayDataInsn (com.taobao.android.dx.rop.code.FillArrayDataInsn)1 SwitchInsn (com.taobao.android.dx.rop.code.SwitchInsn)1 Constant (com.taobao.android.dx.rop.cst.Constant)1 CstFieldRef (com.taobao.android.dx.rop.cst.CstFieldRef)1