Search in sources :

Example 1 with Rop

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

the class RopperMachine method run.

/** {@inheritDoc} */
@Override
public void run(Frame frame, int offset, int opcode) {
    /*
         * This is the stack pointer after the opcode's arguments have been
         * popped.
         */
    int stackPointer = maxLocals + frame.getStack().size();
    // The sources have to be retrieved before super.run() gets called.
    RegisterSpecList sources = getSources(opcode, stackPointer);
    int sourceCount = sources.size();
    super.run(frame, offset, opcode);
    SourcePosition pos = method.makeSourcePosistion(offset);
    RegisterSpec localTarget = getLocalTarget(opcode == ByteOps.ISTORE);
    int destCount = resultCount();
    RegisterSpec dest;
    if (destCount == 0) {
        dest = null;
        switch(opcode) {
            case ByteOps.POP:
            case ByteOps.POP2:
                {
                    // These simply don't appear in the rop form.
                    return;
                }
        }
    } else if (localTarget != null) {
        dest = localTarget;
    } else if (destCount == 1) {
        dest = RegisterSpec.make(stackPointer, result(0));
    } else {
        /*
             * This clause only ever applies to the stack manipulation
             * ops that have results (that is, dup* and swap but not
             * pop*).
             *
             * What we do is first move all the source registers into
             * the "temporary stack" area defined for the method, and
             * then move stuff back down onto the main "stack" in the
             * arrangement specified by the stack op pattern.
             *
             * Note: This code ends up emitting a lot of what will
             * turn out to be superfluous moves (e.g., moving back and
             * forth to the same local when doing a dup); however,
             * that makes this code a bit easier (and goodness knows
             * it doesn't need any extra complexity), and all the SSA
             * stuff is going to want to deal with this sort of
             * superfluous assignment anyway, so it should be a wash
             * in the end.
             */
        int scratchAt = ropper.getFirstTempStackReg();
        RegisterSpec[] scratchRegs = new RegisterSpec[sourceCount];
        for (int i = 0; i < sourceCount; i++) {
            RegisterSpec src = sources.get(i);
            TypeBearer type = src.getTypeBearer();
            RegisterSpec scratch = src.withReg(scratchAt);
            insns.add(new PlainInsn(Rops.opMove(type), pos, scratch, src));
            scratchRegs[i] = scratch;
            scratchAt += src.getCategory();
        }
        for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) {
            int which = (pattern & 0x0f) - 1;
            RegisterSpec scratch = scratchRegs[which];
            TypeBearer type = scratch.getTypeBearer();
            insns.add(new PlainInsn(Rops.opMove(type), pos, scratch.withReg(stackPointer), scratch));
            stackPointer += type.getType().getCategory();
        }
        return;
    }
    TypeBearer destType = (dest != null) ? dest : Type.VOID;
    Constant cst = getAuxCst();
    int ropOpcode;
    Rop rop;
    Insn insn;
    if (opcode == ByteOps.MULTIANEWARRAY) {
        blockCanThrow = true;
        // Add the extra instructions for handling multianewarray.
        extraBlockCount = 6;
        /*
             * Add an array constructor for the int[] containing all the
             * dimensions.
             */
        RegisterSpec dimsReg = RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY);
        rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount);
        insn = new ThrowingCstInsn(rop, pos, sources, catches, CstType.INT_ARRAY);
        insns.add(insn);
        // Add a move-result for the new-filled-array
        rop = Rops.opMoveResult(Type.INT_ARRAY);
        insn = new PlainInsn(rop, pos, dimsReg, RegisterSpecList.EMPTY);
        insns.add(insn);
        /*
             * Add a const-class instruction for the specified array
             * class.
             */
        /*
             * Remove as many dimensions from the originally specified
             * class as are given in the explicit list of dimensions,
             * so as to pass the right component class to the standard
             * Java library array constructor.
             */
        Type componentType = ((CstType) cst).getClassType();
        for (int i = 0; i < sourceCount; i++) {
            componentType = componentType.getComponentType();
        }
        RegisterSpec classReg = RegisterSpec.make(dest.getReg(), Type.CLASS);
        if (componentType.isPrimitive()) {
            /*
                 * The component type is primitive (e.g., int as opposed
                 * to Integer), so we have to fetch the corresponding
                 * TYPE class.
                 */
            CstFieldRef typeField = CstFieldRef.forPrimitiveType(componentType);
            insn = new ThrowingCstInsn(Rops.GET_STATIC_OBJECT, pos, RegisterSpecList.EMPTY, catches, typeField);
        } else {
            /*
                 * The component type is an object type, so just make a
                 * normal class reference.
                 */
            insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, RegisterSpecList.EMPTY, catches, new CstType(componentType));
        }
        insns.add(insn);
        // Add a move-result-pseudo for the get-static or const
        rop = Rops.opMoveResultPseudo(classReg.getType());
        insn = new PlainInsn(rop, pos, classReg, RegisterSpecList.EMPTY);
        insns.add(insn);
        /*
             * Add a call to the "multianewarray method," that is,
             * Array.newInstance(class, dims). Note: The result type
             * of newInstance() is Object, which is why the last
             * instruction in this sequence is a cast to the right
             * type for the original instruction.
             */
        RegisterSpec objectReg = RegisterSpec.make(dest.getReg(), Type.OBJECT);
        insn = new ThrowingCstInsn(Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()), pos, RegisterSpecList.make(classReg, dimsReg), catches, MULTIANEWARRAY_METHOD);
        insns.add(insn);
        // Add a move-result.
        rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype().getReturnType());
        insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY);
        insns.add(insn);
        /*
             * And finally, set up for the remainder of this method to
             * add an appropriate cast.
             */
        opcode = ByteOps.CHECKCAST;
        sources = RegisterSpecList.make(objectReg);
    } else if (opcode == ByteOps.JSR) {
        // JSR has no Rop instruction
        hasJsr = true;
        return;
    } else if (opcode == ByteOps.RET) {
        try {
            returnAddress = (ReturnAddress) arg(0);
        } catch (ClassCastException ex) {
            throw new RuntimeException("Argument to RET was not a ReturnAddress", ex);
        }
        // RET has no Rop instruction.
        return;
    }
    ropOpcode = jopToRopOpcode(opcode, cst);
    rop = Rops.ropFor(ropOpcode, destType, sources, cst);
    Insn moveResult = null;
    if (dest != null && rop.isCallLike()) {
        /*
             * We're going to want to have a move-result in the next
             * basic block.
             */
        extraBlockCount++;
        moveResult = new PlainInsn(Rops.opMoveResult(((CstMethodRef) cst).getPrototype().getReturnType()), pos, dest, RegisterSpecList.EMPTY);
        dest = null;
    } else if (dest != null && rop.canThrow()) {
        /*
             * We're going to want to have a move-result-pseudo in the
             * next basic block.
             */
        extraBlockCount++;
        moveResult = new PlainInsn(Rops.opMoveResultPseudo(dest.getTypeBearer()), pos, dest, RegisterSpecList.EMPTY);
        dest = null;
    }
    if (ropOpcode == RegOps.NEW_ARRAY) {
        /*
             * In the original bytecode, this was either a primitive
             * array constructor "newarray" or an object array
             * constructor "anewarray". In the former case, there is
             * no explicit constant, and in the latter, the constant
             * is for the element type and not the array type. The rop
             * instruction form for both of these is supposed to be
             * the resulting array type, so we initialize / alter
             * "cst" here, accordingly. Conveniently enough, the rop
             * opcode already gets constructed with the proper array
             * type.
             */
        cst = CstType.intern(rop.getResult());
    } else if ((cst == null) && (sourceCount == 2)) {
        TypeBearer firstType = sources.get(0).getTypeBearer();
        TypeBearer lastType = sources.get(1).getTypeBearer();
        if ((lastType.isConstant() || firstType.isConstant()) && advice.hasConstantOperation(rop, sources.get(0), sources.get(1))) {
            if (lastType.isConstant()) {
                /*
                     * The target architecture has an instruction that can
                     * build in the constant found in the second argument,
                     * so pull it out of the sources and just use it as a
                     * constant here.
                     */
                cst = (Constant) lastType;
                sources = sources.withoutLast();
                // For subtraction, change to addition and invert constant
                if (rop.getOpcode() == RegOps.SUB) {
                    ropOpcode = RegOps.ADD;
                    CstInteger cstInt = (CstInteger) lastType;
                    cst = CstInteger.make(-cstInt.getValue());
                }
            } else {
                /*
                     * The target architecture has an instruction that can
                     * build in the constant found in the first argument,
                     * so pull it out of the sources and just use it as a
                     * constant here.
                     */
                cst = (Constant) firstType;
                sources = sources.withoutFirst();
            }
            rop = Rops.ropFor(ropOpcode, destType, sources, cst);
        }
    }
    SwitchList cases = getAuxCases();
    ArrayList<Constant> initValues = getInitValues();
    boolean canThrow = rop.canThrow();
    blockCanThrow |= canThrow;
    if (cases != null) {
        if (cases.size() == 0) {
            // It's a default-only switch statement. It can happen!
            insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
            primarySuccessorIndex = 0;
        } else {
            IntList values = cases.getValues();
            insn = new SwitchInsn(rop, pos, dest, sources, values);
            primarySuccessorIndex = values.size();
        }
    } else if (ropOpcode == RegOps.RETURN) {
        /*
             * Returns get turned into the combination of a move (if
             * non-void and if the return doesn't already mention
             * register 0) and a goto (to the return block).
             */
        if (sources.size() != 0) {
            RegisterSpec source = sources.get(0);
            TypeBearer type = source.getTypeBearer();
            if (source.getReg() != 0) {
                insns.add(new PlainInsn(Rops.opMove(type), pos, RegisterSpec.make(0, type), source));
            }
        }
        insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
        primarySuccessorIndex = 0;
        updateReturnOp(rop, pos);
        returns = true;
    } else if (cst != null) {
        if (canThrow) {
            insn = new ThrowingCstInsn(rop, pos, sources, catches, cst);
            catchesUsed = true;
            primarySuccessorIndex = catches.size();
        } else {
            insn = new PlainCstInsn(rop, pos, dest, sources, cst);
        }
    } else if (canThrow) {
        insn = new ThrowingInsn(rop, pos, sources, catches);
        catchesUsed = true;
        if (opcode == ByteOps.ATHROW) {
            /*
                 * The op athrow is the only one where it's possible
                 * to have non-empty successors and yet not have a
                 * primary successor.
                 */
            primarySuccessorIndex = -1;
        } else {
            primarySuccessorIndex = catches.size();
        }
    } else {
        insn = new PlainInsn(rop, pos, dest, sources);
    }
    insns.add(insn);
    if (moveResult != null) {
        insns.add(moveResult);
    }
    /*
         * If initValues is non-null, it means that the parser has
         * seen a group of compatible constant initialization
         * bytecodes that are applied to the current newarray. The
         * action we take here is to convert these initialization
         * bytecodes into a single fill-array-data ROP which lays out
         * all the constant values in a table.
         */
    if (initValues != null) {
        extraBlockCount++;
        insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos, RegisterSpecList.make(moveResult.getResult()), initValues, cst);
        insns.add(insn);
    }
}
Also used : Insn(com.taobao.android.dx.rop.code.Insn) PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) SwitchInsn(com.taobao.android.dx.rop.code.SwitchInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) ThrowingCstInsn(com.taobao.android.dx.rop.code.ThrowingCstInsn) FillArrayDataInsn(com.taobao.android.dx.rop.code.FillArrayDataInsn) ThrowingCstInsn(com.taobao.android.dx.rop.code.ThrowingCstInsn) Constant(com.taobao.android.dx.rop.cst.Constant) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) RegisterSpecList(com.taobao.android.dx.rop.code.RegisterSpecList) CstInteger(com.taobao.android.dx.rop.cst.CstInteger) SourcePosition(com.taobao.android.dx.rop.code.SourcePosition) RegisterSpec(com.taobao.android.dx.rop.code.RegisterSpec) FillArrayDataInsn(com.taobao.android.dx.rop.code.FillArrayDataInsn) CstFieldRef(com.taobao.android.dx.rop.cst.CstFieldRef) CstMethodRef(com.taobao.android.dx.rop.cst.CstMethodRef) SwitchInsn(com.taobao.android.dx.rop.code.SwitchInsn) IntList(com.taobao.android.dx.util.IntList) PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) Rop(com.taobao.android.dx.rop.code.Rop) CstType(com.taobao.android.dx.rop.cst.CstType) Type(com.taobao.android.dx.rop.type.Type) CstType(com.taobao.android.dx.rop.cst.CstType) TypeBearer(com.taobao.android.dx.rop.type.TypeBearer)

Example 2 with Rop

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

the class RopTranslator method outputBlock.

/**
     * Helper for {@link #outputInstructions}, which does the processing
     * and output of one block.
     *
     * @param block {@code non-null;} the block to process and output
     * @param nextLabel {@code >= -1;} the next block that will be processed, or
     * {@code -1} if there is no next block
     */
private void outputBlock(BasicBlock block, int nextLabel) {
    // Append the code address for this block.
    CodeAddress startAddress = addresses.getStart(block);
    output.add(startAddress);
    // Append the local variable state for the block.
    if (locals != null) {
        RegisterSpecSet starts = locals.getStarts(block);
        output.add(new LocalSnapshot(startAddress.getPosition(), starts));
    }
    /*
         * Choose and append an output instruction for each original
         * instruction.
         */
    translationVisitor.setBlock(block, addresses.getLast(block));
    block.getInsns().forEach(translationVisitor);
    // Insert the block end code address.
    output.add(addresses.getEnd(block));
    // Set up for end-of-block activities.
    int succ = block.getPrimarySuccessor();
    Insn lastInsn = block.getLastInsn();
    if ((succ >= 0) && (succ != nextLabel)) {
        /*
             * The block has a "primary successor" and that primary
             * successor isn't the next block to be output.
             */
        Rop lastRop = lastInsn.getOpcode();
        if ((lastRop.getBranchingness() == Rop.BRANCH_IF) && (block.getSecondarySuccessor() == nextLabel)) {
            /*
                 * The block ends with an "if" of some sort, and its
                 * secondary successor (the "then") is in fact the
                 * next block to output. So, reverse the sense of
                 * the test, so that we can just emit the next block
                 * without an interstitial goto.
                 */
            output.reverseBranch(1, addresses.getStart(succ));
        } else {
            /*
                 * Our only recourse is to add a goto here to get the
                 * flow to be correct.
                 */
            TargetInsn insn = new TargetInsn(Dops.GOTO, lastInsn.getPosition(), RegisterSpecList.EMPTY, addresses.getStart(succ));
            output.add(insn);
        }
    }
}
Also used : Insn(com.taobao.android.dx.rop.code.Insn) ThrowingInsn(com.taobao.android.dx.rop.code.ThrowingInsn) PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) ThrowingCstInsn(com.taobao.android.dx.rop.code.ThrowingCstInsn) SwitchInsn(com.taobao.android.dx.rop.code.SwitchInsn) FillArrayDataInsn(com.taobao.android.dx.rop.code.FillArrayDataInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) Rop(com.taobao.android.dx.rop.code.Rop) RegisterSpecSet(com.taobao.android.dx.rop.code.RegisterSpecSet)

Example 3 with Rop

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

the class EscapeAnalysis method insertPlainInsnBefore.

/**
     * Inserts a new PlainInsn before the given instruction.
     * TODO: move this somewhere more appropriate
     *
     * @param insn {@code non-null;} instruction to insert before
     * @param newSources {@code non-null;} sources of new instruction
     * @param newResult {@code non-null;} result of new instruction
     * @param newOpcode opcode of new instruction
     * @param cst {@code null-ok;} constant for new instruction, if any
     */
private void insertPlainInsnBefore(SsaInsn insn, RegisterSpecList newSources, RegisterSpec newResult, int newOpcode, Constant cst) {
    Insn originalRopInsn = insn.getOriginalRopInsn();
    Rop newRop;
    if (newOpcode == RegOps.MOVE_RESULT_PSEUDO) {
        newRop = Rops.opMoveResultPseudo(newResult.getType());
    } else {
        newRop = Rops.ropFor(newOpcode, newResult, newSources, cst);
    }
    Insn newRopInsn;
    if (cst == null) {
        newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(), newResult, newSources);
    } else {
        newRopInsn = new PlainCstInsn(newRop, originalRopInsn.getPosition(), newResult, newSources, cst);
    }
    NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock());
    List<SsaInsn> insns = insn.getBlock().getInsns();
    insns.add(insns.lastIndexOf(insn), newInsn);
    ssaMeth.onInsnAdded(newInsn);
}
Also used : PlainCstInsn(com.taobao.android.dx.rop.code.PlainCstInsn) PlainInsn(com.taobao.android.dx.rop.code.PlainInsn) 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) FillArrayDataInsn(com.taobao.android.dx.rop.code.FillArrayDataInsn) Rop(com.taobao.android.dx.rop.code.Rop)

Example 4 with Rop

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

the class FirstFitLocalCombiningAllocator method getParameterIndexForReg.

/**
     * Gets the parameter index for SSA registers that are method parameters.
     * {@code -1} is returned for non-parameter registers.
     *
     * @param ssaReg {@code >=0;} SSA register to look up
     * @return parameter index or {@code -1} if not a parameter
     */
private int getParameterIndexForReg(int ssaReg) {
    SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
    if (defInsn == null) {
        return -1;
    }
    Rop opcode = defInsn.getOpcode();
    // opcode == null for phi insns.
    if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
        CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
        return ((CstInteger) origInsn.getConstant()).getValue();
    }
    return -1;
}
Also used : CstInsn(com.taobao.android.dx.rop.code.CstInsn) Rop(com.taobao.android.dx.rop.code.Rop) CstInteger(com.taobao.android.dx.rop.cst.CstInteger) SsaInsn(com.taobao.android.dx.ssa.SsaInsn) NormalSsaInsn(com.taobao.android.dx.ssa.NormalSsaInsn)

Example 5 with Rop

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

the class LiteralOpUpgrader method run.

/**
     * Run the literal op upgrader
     */
private void run() {
    final TranslationAdvice advice = optimizer.getAdvice();
    ssaMeth.forEachInsn(new SsaInsn.Visitor() {

        public void visitMoveInsn(NormalSsaInsn insn) {
        // do nothing
        }

        public void visitPhiInsn(PhiInsn insn) {
        // do nothing
        }

        public void visitNonMoveInsn(NormalSsaInsn insn) {
            Insn originalRopInsn = insn.getOriginalRopInsn();
            Rop opcode = originalRopInsn.getOpcode();
            RegisterSpecList sources = insn.getSources();
            // Replace insns with constant results with const insns
            if (tryReplacingWithConstant(insn))
                return;
            if (sources.size() != 2) {
                // We're only dealing with two-source insns here.
                return;
            }
            if (opcode.getBranchingness() == Rop.BRANCH_IF) {
                /*
                     * An if instruction can become an if-*z instruction.
                     */
                if (isConstIntZeroOrKnownNull(sources.get(0))) {
                    replacePlainInsn(insn, sources.withoutFirst(), RegOps.flippedIfOpcode(opcode.getOpcode()), null);
                } else if (isConstIntZeroOrKnownNull(sources.get(1))) {
                    replacePlainInsn(insn, sources.withoutLast(), opcode.getOpcode(), null);
                }
            } else if (advice.hasConstantOperation(opcode, sources.get(0), sources.get(1))) {
                insn.upgradeToLiteral();
            } else if (opcode.isCommutative() && advice.hasConstantOperation(opcode, sources.get(1), sources.get(0))) {
                /*
                     * An instruction can be commuted to a literal operation
                     */
                insn.setNewSources(RegisterSpecList.make(sources.get(1), sources.get(0)));
                insn.upgradeToLiteral();
            }
        }
    });
}
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) Rop(com.taobao.android.dx.rop.code.Rop) TranslationAdvice(com.taobao.android.dx.rop.code.TranslationAdvice) RegisterSpecList(com.taobao.android.dx.rop.code.RegisterSpecList)

Aggregations

Rop (com.taobao.android.dx.rop.code.Rop)15 PlainCstInsn (com.taobao.android.dx.rop.code.PlainCstInsn)9 PlainInsn (com.taobao.android.dx.rop.code.PlainInsn)9 Insn (com.taobao.android.dx.rop.code.Insn)8 RegisterSpec (com.taobao.android.dx.rop.code.RegisterSpec)7 ThrowingCstInsn (com.taobao.android.dx.rop.code.ThrowingCstInsn)7 ThrowingInsn (com.taobao.android.dx.rop.code.ThrowingInsn)5 FillArrayDataInsn (com.taobao.android.dx.rop.code.FillArrayDataInsn)4 RegisterSpecList (com.taobao.android.dx.rop.code.RegisterSpecList)4 Constant (com.taobao.android.dx.rop.cst.Constant)3 CstInteger (com.taobao.android.dx.rop.cst.CstInteger)3 SourcePosition (com.taobao.android.dx.rop.code.SourcePosition)2 SwitchInsn (com.taobao.android.dx.rop.code.SwitchInsn)2 CstFieldRef (com.taobao.android.dx.rop.cst.CstFieldRef)2 CstType (com.taobao.android.dx.rop.cst.CstType)2 TypedConstant (com.taobao.android.dx.rop.cst.TypedConstant)2 TypeBearer (com.taobao.android.dx.rop.type.TypeBearer)2 SsaInsn (com.taobao.android.dx.ssa.SsaInsn)2 BasicBlock (com.taobao.android.dx.rop.code.BasicBlock)1 CstInsn (com.taobao.android.dx.rop.code.CstInsn)1