Search in sources :

Example 6 with CstInteger

use of com.android.dx.rop.cst.CstInteger in project buck by facebook.

the class SCCP method simulateBranch.

/**
     * Simulates branch insns, if possible. Adds reachable successor blocks
     * to the CFG worklists.
     * @param insn branch to simulate
     */
private void simulateBranch(SsaInsn insn) {
    Rop opcode = insn.getOpcode();
    RegisterSpecList sources = insn.getSources();
    boolean constantBranch = false;
    boolean constantSuccessor = false;
    // Check if the insn is a branch with a constant condition
    if (opcode.getBranchingness() == Rop.BRANCH_IF) {
        Constant cA = null;
        Constant cB = null;
        RegisterSpec specA = sources.get(0);
        int regA = specA.getReg();
        if (!ssaMeth.isRegALocal(specA) && latticeValues[regA] == CONSTANT) {
            cA = latticeConstants[regA];
        }
        if (sources.size() == 2) {
            RegisterSpec specB = sources.get(1);
            int regB = specB.getReg();
            if (!ssaMeth.isRegALocal(specB) && latticeValues[regB] == CONSTANT) {
                cB = latticeConstants[regB];
            }
        }
        // Calculate the result of the condition
        if (cA != null && sources.size() == 1) {
            switch(((TypedConstant) cA).getBasicType()) {
                case Type.BT_INT:
                    constantBranch = true;
                    int vA = ((CstInteger) cA).getValue();
                    switch(opcode.getOpcode()) {
                        case RegOps.IF_EQ:
                            constantSuccessor = (vA == 0);
                            break;
                        case RegOps.IF_NE:
                            constantSuccessor = (vA != 0);
                            break;
                        case RegOps.IF_LT:
                            constantSuccessor = (vA < 0);
                            break;
                        case RegOps.IF_GE:
                            constantSuccessor = (vA >= 0);
                            break;
                        case RegOps.IF_LE:
                            constantSuccessor = (vA <= 0);
                            break;
                        case RegOps.IF_GT:
                            constantSuccessor = (vA > 0);
                            break;
                        default:
                            throw new RuntimeException("Unexpected op");
                    }
                    break;
                default:
            }
        } else if (cA != null && cB != null) {
            switch(((TypedConstant) cA).getBasicType()) {
                case Type.BT_INT:
                    constantBranch = true;
                    int vA = ((CstInteger) cA).getValue();
                    int vB = ((CstInteger) cB).getValue();
                    switch(opcode.getOpcode()) {
                        case RegOps.IF_EQ:
                            constantSuccessor = (vA == vB);
                            break;
                        case RegOps.IF_NE:
                            constantSuccessor = (vA != vB);
                            break;
                        case RegOps.IF_LT:
                            constantSuccessor = (vA < vB);
                            break;
                        case RegOps.IF_GE:
                            constantSuccessor = (vA >= vB);
                            break;
                        case RegOps.IF_LE:
                            constantSuccessor = (vA <= vB);
                            break;
                        case RegOps.IF_GT:
                            constantSuccessor = (vA > vB);
                            break;
                        default:
                            throw new RuntimeException("Unexpected op");
                    }
                    break;
                default:
            }
        }
    }
    /*
         * If condition is constant, add only the target block to the
         * worklist. Otherwise, add all successors to the worklist.
         */
    SsaBasicBlock block = insn.getBlock();
    if (constantBranch) {
        int successorBlock;
        if (constantSuccessor) {
            successorBlock = block.getSuccessorList().get(1);
        } else {
            successorBlock = block.getSuccessorList().get(0);
        }
        addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
        branchWorklist.add(insn);
    } else {
        for (int i = 0; i < block.getSuccessorList().size(); i++) {
            int successorBlock = block.getSuccessorList().get(i);
            addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
        }
    }
}
Also used : Rop(com.android.dx.rop.code.Rop) TypedConstant(com.android.dx.rop.cst.TypedConstant) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstInteger(com.android.dx.rop.cst.CstInteger) RegisterSpecList(com.android.dx.rop.code.RegisterSpecList) RegisterSpec(com.android.dx.rop.code.RegisterSpec)

Example 7 with CstInteger

use of com.android.dx.rop.cst.CstInteger in project buck by facebook.

the class MoveParamCombiner method getParamIndex.

/**
     * Returns the parameter index associated with a move-param insn. Does
     * not verify that the insn is a move-param insn.
     *
     * @param insn {@code non-null;} a move-param insn
     * @return {@code >=0;} parameter index
     */
private int getParamIndex(NormalSsaInsn insn) {
    CstInsn cstInsn = (CstInsn) (insn.getOriginalRopInsn());
    int param = ((CstInteger) cstInsn.getConstant()).getValue();
    return param;
}
Also used : CstInsn(com.android.dx.rop.code.CstInsn) CstInteger(com.android.dx.rop.cst.CstInteger)

Example 8 with CstInteger

use of com.android.dx.rop.cst.CstInteger in project J2ME-Loader by nikita36078.

the class BytecodeArray method parseNewarray.

/**
 * Helper to deal with {@code newarray}.
 *
 * @param offset the offset to the {@code newarray} opcode itself
 * @param visitor {@code non-null;} visitor to use
 * @return instruction length, in bytes
 */
private int parseNewarray(int offset, Visitor visitor) {
    int value = bytes.getUnsignedByte(offset + 1);
    CstType type;
    switch(value) {
        case ByteOps.NEWARRAY_BOOLEAN:
            {
                type = CstType.BOOLEAN_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_CHAR:
            {
                type = CstType.CHAR_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_DOUBLE:
            {
                type = CstType.DOUBLE_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_FLOAT:
            {
                type = CstType.FLOAT_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_BYTE:
            {
                type = CstType.BYTE_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_SHORT:
            {
                type = CstType.SHORT_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_INT:
            {
                type = CstType.INT_ARRAY;
                break;
            }
        case ByteOps.NEWARRAY_LONG:
            {
                type = CstType.LONG_ARRAY;
                break;
            }
        default:
            {
                throw new SimException("bad newarray code " + Hex.u1(value));
            }
    }
    // Revisit the previous bytecode to find out the length of the array
    int previousOffset = visitor.getPreviousOffset();
    ConstantParserVisitor constantVisitor = new ConstantParserVisitor();
    int arrayLength = 0;
    /*
         * For visitors that don't record the previous offset, -1 will be
         * seen here
         */
    if (previousOffset >= 0) {
        parseInstruction(previousOffset, constantVisitor);
        if (constantVisitor.cst instanceof CstInteger && constantVisitor.length + previousOffset == offset) {
            arrayLength = constantVisitor.value;
        }
    }
    /*
         * Try to match the array initialization idiom. For example, if the
         * subsequent code is initializing an int array, we are expecting the
         * following pattern repeatedly:
         *  dup
         *  push index
         *  push value
         *  *astore
         *
         * where the index value will be incrimented sequentially from 0 up.
         */
    int nInit = 0;
    int curOffset = offset + 2;
    int lastOffset = curOffset;
    ArrayList<Constant> initVals = new ArrayList<Constant>();
    if (arrayLength != 0) {
        while (true) {
            boolean punt = false;
            // First, check if the next bytecode is dup.
            int nextByte = bytes.getUnsignedByte(curOffset++);
            if (nextByte != ByteOps.DUP)
                break;
            /*
                 * Next, check if the expected array index is pushed to
                 * the stack.
                 */
            parseInstruction(curOffset, constantVisitor);
            if (constantVisitor.length == 0 || !(constantVisitor.cst instanceof CstInteger) || constantVisitor.value != nInit)
                break;
            // Next, fetch the init value and record it.
            curOffset += constantVisitor.length;
            /*
                 * Next, find out what kind of constant is pushed onto
                 * the stack.
                 */
            parseInstruction(curOffset, constantVisitor);
            if (constantVisitor.length == 0 || !(constantVisitor.cst instanceof CstLiteralBits))
                break;
            curOffset += constantVisitor.length;
            initVals.add(constantVisitor.cst);
            nextByte = bytes.getUnsignedByte(curOffset++);
            // Now, check if the value is stored to the array properly.
            switch(value) {
                case ByteOps.NEWARRAY_BYTE:
                case ByteOps.NEWARRAY_BOOLEAN:
                    {
                        if (nextByte != ByteOps.BASTORE) {
                            punt = true;
                        }
                        break;
                    }
                case ByteOps.NEWARRAY_CHAR:
                    {
                        if (nextByte != ByteOps.CASTORE) {
                            punt = true;
                        }
                        break;
                    }
                case ByteOps.NEWARRAY_DOUBLE:
                    {
                        if (nextByte != ByteOps.DASTORE) {
                            punt = true;
                        }
                        break;
                    }
                case ByteOps.NEWARRAY_FLOAT:
                    {
                        if (nextByte != ByteOps.FASTORE) {
                            punt = true;
                        }
                        break;
                    }
                case ByteOps.NEWARRAY_SHORT:
                    {
                        if (nextByte != ByteOps.SASTORE) {
                            punt = true;
                        }
                        break;
                    }
                case ByteOps.NEWARRAY_INT:
                    {
                        if (nextByte != ByteOps.IASTORE) {
                            punt = true;
                        }
                        break;
                    }
                case ByteOps.NEWARRAY_LONG:
                    {
                        if (nextByte != ByteOps.LASTORE) {
                            punt = true;
                        }
                        break;
                    }
                default:
                    punt = true;
                    break;
            }
            if (punt) {
                break;
            }
            lastOffset = curOffset;
            nInit++;
        }
    }
    /*
         * For singleton arrays it is still more economical to
         * generate the aput.
         */
    if (nInit < 2 || nInit != arrayLength) {
        visitor.visitNewarray(offset, 2, type, null);
        return 2;
    } else {
        visitor.visitNewarray(offset, lastOffset - offset, type, initVals);
        return lastOffset - offset;
    }
}
Also used : CstLiteralBits(com.android.dx.rop.cst.CstLiteralBits) CstInteger(com.android.dx.rop.cst.CstInteger) Constant(com.android.dx.rop.cst.Constant) CstType(com.android.dx.rop.cst.CstType) ArrayList(java.util.ArrayList)

Example 9 with CstInteger

use of com.android.dx.rop.cst.CstInteger in project J2ME-Loader by nikita36078.

the class BytecodeArray method parseInstruction.

/**
 * Parses the instruction at the indicated offset. Indicate the
 * result by calling the visitor if supplied and by returning the
 * number of bytes consumed by the instruction.
 *
 * <p>In order to simplify further processing, the opcodes passed
 * to the visitor are canonicalized, altering the opcode to a more
 * universal one and making formerly implicit arguments
 * explicit. In particular:</p>
 *
 * <ul>
 * <li>The opcodes to push literal constants of primitive types all become
 *   {@code ldc}.
 *   E.g., {@code fconst_0}, {@code sipush}, and
 *   {@code lconst_0} qualify for this treatment.</li>
 * <li>{@code aconst_null} becomes {@code ldc} of a
 *   "known null."</li>
 * <li>Shorthand local variable accessors become the corresponding
 *   longhand. E.g. {@code aload_2} becomes {@code aload}.</li>
 * <li>{@code goto_w} and {@code jsr_w} become {@code goto}
 *   and {@code jsr} (respectively).</li>
 * <li>{@code ldc_w} becomes {@code ldc}.</li>
 * <li>{@code tableswitch} becomes {@code lookupswitch}.
 * <li>Arithmetic, array, and value-returning ops are collapsed
 *   to the {@code int} variant opcode, with the {@code type}
 *   argument set to indicate the actual type. E.g.,
 *   {@code fadd} becomes {@code iadd}, but
 *   {@code type} is passed as {@code Type.FLOAT} in that
 *   case. Similarly, {@code areturn} becomes
 *   {@code ireturn}. (However, {@code return} remains
 *   unchanged.</li>
 * <li>Local variable access ops are collapsed to the {@code int}
 *   variant opcode, with the {@code type} argument set to indicate
 *   the actual type. E.g., {@code aload} becomes {@code iload},
 *   but {@code type} is passed as {@code Type.OBJECT} in
 *   that case.</li>
 * <li>Numeric conversion ops ({@code i2l}, etc.) are left alone
 *   to avoid too much confustion, but their {@code type} is
 *   the pushed type. E.g., {@code i2b} gets type
 *   {@code Type.INT}, and {@code f2d} gets type
 *   {@code Type.DOUBLE}. Other unaltered opcodes also get
 *   their pushed type. E.g., {@code arraylength} gets type
 *   {@code Type.INT}.</li>
 * </ul>
 *
 * @param offset {@code >= 0, < bytes.size();} offset to the start of the
 * instruction
 * @param visitor {@code null-ok;} visitor to call back to
 * @return the length of the instruction, in bytes
 */
public int parseInstruction(int offset, Visitor visitor) {
    if (visitor == null) {
        visitor = EMPTY_VISITOR;
    }
    try {
        int opcode = bytes.getUnsignedByte(offset);
        int info = ByteOps.opInfo(opcode);
        int fmt = info & ByteOps.FMT_MASK;
        switch(opcode) {
            case ByteOps.NOP:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
                    return 1;
                }
            case ByteOps.ACONST_NULL:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstKnownNull.THE_ONE, 0);
                    return 1;
                }
            case ByteOps.ICONST_M1:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_M1, -1);
                    return 1;
                }
            case ByteOps.ICONST_0:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_0, 0);
                    return 1;
                }
            case ByteOps.ICONST_1:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_1, 1);
                    return 1;
                }
            case ByteOps.ICONST_2:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_2, 2);
                    return 1;
                }
            case ByteOps.ICONST_3:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_3, 3);
                    return 1;
                }
            case ByteOps.ICONST_4:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_4, 4);
                    return 1;
                }
            case ByteOps.ICONST_5:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_5, 5);
                    return 1;
                }
            case ByteOps.LCONST_0:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstLong.VALUE_0, 0);
                    return 1;
                }
            case ByteOps.LCONST_1:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstLong.VALUE_1, 0);
                    return 1;
                }
            case ByteOps.FCONST_0:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstFloat.VALUE_0, 0);
                    return 1;
                }
            case ByteOps.FCONST_1:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstFloat.VALUE_1, 0);
                    return 1;
                }
            case ByteOps.FCONST_2:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstFloat.VALUE_2, 0);
                    return 1;
                }
            case ByteOps.DCONST_0:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstDouble.VALUE_0, 0);
                    return 1;
                }
            case ByteOps.DCONST_1:
                {
                    visitor.visitConstant(ByteOps.LDC, offset, 1, CstDouble.VALUE_1, 0);
                    return 1;
                }
            case ByteOps.BIPUSH:
                {
                    int value = bytes.getByte(offset + 1);
                    visitor.visitConstant(ByteOps.LDC, offset, 2, CstInteger.make(value), value);
                    return 2;
                }
            case ByteOps.SIPUSH:
                {
                    int value = bytes.getShort(offset + 1);
                    visitor.visitConstant(ByteOps.LDC, offset, 3, CstInteger.make(value), value);
                    return 3;
                }
            case ByteOps.LDC:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    Constant cst = pool.get(idx);
                    int value = (cst instanceof CstInteger) ? ((CstInteger) cst).getValue() : 0;
                    visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value);
                    return 2;
                }
            case ByteOps.LDC_W:
                {
                    int idx = bytes.getUnsignedShort(offset + 1);
                    Constant cst = pool.get(idx);
                    int value = (cst instanceof CstInteger) ? ((CstInteger) cst).getValue() : 0;
                    visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value);
                    return 3;
                }
            case ByteOps.LDC2_W:
                {
                    int idx = bytes.getUnsignedShort(offset + 1);
                    Constant cst = pool.get(idx);
                    visitor.visitConstant(ByteOps.LDC2_W, offset, 3, cst, 0);
                    return 3;
                }
            case ByteOps.ILOAD:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.INT, 0);
                    return 2;
                }
            case ByteOps.LLOAD:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.LONG, 0);
                    return 2;
                }
            case ByteOps.FLOAD:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.FLOAT, 0);
                    return 2;
                }
            case ByteOps.DLOAD:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.DOUBLE, 0);
                    return 2;
                }
            case ByteOps.ALOAD:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.OBJECT, 0);
                    return 2;
                }
            case ByteOps.ILOAD_0:
            case ByteOps.ILOAD_1:
            case ByteOps.ILOAD_2:
            case ByteOps.ILOAD_3:
                {
                    int idx = opcode - ByteOps.ILOAD_0;
                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.INT, 0);
                    return 1;
                }
            case ByteOps.LLOAD_0:
            case ByteOps.LLOAD_1:
            case ByteOps.LLOAD_2:
            case ByteOps.LLOAD_3:
                {
                    int idx = opcode - ByteOps.LLOAD_0;
                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.LONG, 0);
                    return 1;
                }
            case ByteOps.FLOAD_0:
            case ByteOps.FLOAD_1:
            case ByteOps.FLOAD_2:
            case ByteOps.FLOAD_3:
                {
                    int idx = opcode - ByteOps.FLOAD_0;
                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.FLOAT, 0);
                    return 1;
                }
            case ByteOps.DLOAD_0:
            case ByteOps.DLOAD_1:
            case ByteOps.DLOAD_2:
            case ByteOps.DLOAD_3:
                {
                    int idx = opcode - ByteOps.DLOAD_0;
                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.DOUBLE, 0);
                    return 1;
                }
            case ByteOps.ALOAD_0:
            case ByteOps.ALOAD_1:
            case ByteOps.ALOAD_2:
            case ByteOps.ALOAD_3:
                {
                    int idx = opcode - ByteOps.ALOAD_0;
                    visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.OBJECT, 0);
                    return 1;
                }
            case ByteOps.IALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.INT);
                    return 1;
                }
            case ByteOps.LALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.LONG);
                    return 1;
                }
            case ByteOps.FALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.FLOAT);
                    return 1;
                }
            case ByteOps.DALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.DOUBLE);
                    return 1;
                }
            case ByteOps.AALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.OBJECT);
                    return 1;
                }
            case ByteOps.BALOAD:
                {
                    /*
                     * Note: This is a load from either a byte[] or a
                     * boolean[].
                     */
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.BYTE);
                    return 1;
                }
            case ByteOps.CALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.CHAR);
                    return 1;
                }
            case ByteOps.SALOAD:
                {
                    visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.SHORT);
                    return 1;
                }
            case ByteOps.ISTORE:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.INT, 0);
                    return 2;
                }
            case ByteOps.LSTORE:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.LONG, 0);
                    return 2;
                }
            case ByteOps.FSTORE:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.FLOAT, 0);
                    return 2;
                }
            case ByteOps.DSTORE:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.DOUBLE, 0);
                    return 2;
                }
            case ByteOps.ASTORE:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.OBJECT, 0);
                    return 2;
                }
            case ByteOps.ISTORE_0:
            case ByteOps.ISTORE_1:
            case ByteOps.ISTORE_2:
            case ByteOps.ISTORE_3:
                {
                    int idx = opcode - ByteOps.ISTORE_0;
                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.INT, 0);
                    return 1;
                }
            case ByteOps.LSTORE_0:
            case ByteOps.LSTORE_1:
            case ByteOps.LSTORE_2:
            case ByteOps.LSTORE_3:
                {
                    int idx = opcode - ByteOps.LSTORE_0;
                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.LONG, 0);
                    return 1;
                }
            case ByteOps.FSTORE_0:
            case ByteOps.FSTORE_1:
            case ByteOps.FSTORE_2:
            case ByteOps.FSTORE_3:
                {
                    int idx = opcode - ByteOps.FSTORE_0;
                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.FLOAT, 0);
                    return 1;
                }
            case ByteOps.DSTORE_0:
            case ByteOps.DSTORE_1:
            case ByteOps.DSTORE_2:
            case ByteOps.DSTORE_3:
                {
                    int idx = opcode - ByteOps.DSTORE_0;
                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.DOUBLE, 0);
                    return 1;
                }
            case ByteOps.ASTORE_0:
            case ByteOps.ASTORE_1:
            case ByteOps.ASTORE_2:
            case ByteOps.ASTORE_3:
                {
                    int idx = opcode - ByteOps.ASTORE_0;
                    visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.OBJECT, 0);
                    return 1;
                }
            case ByteOps.IASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.INT);
                    return 1;
                }
            case ByteOps.LASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.LONG);
                    return 1;
                }
            case ByteOps.FASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.FLOAT);
                    return 1;
                }
            case ByteOps.DASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.DOUBLE);
                    return 1;
                }
            case ByteOps.AASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.OBJECT);
                    return 1;
                }
            case ByteOps.BASTORE:
                {
                    /*
                     * Note: This is a load from either a byte[] or a
                     * boolean[].
                     */
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.BYTE);
                    return 1;
                }
            case ByteOps.CASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.CHAR);
                    return 1;
                }
            case ByteOps.SASTORE:
                {
                    visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.SHORT);
                    return 1;
                }
            case ByteOps.POP:
            case ByteOps.POP2:
            case ByteOps.DUP:
            case ByteOps.DUP_X1:
            case ByteOps.DUP_X2:
            case ByteOps.DUP2:
            case ByteOps.DUP2_X1:
            case ByteOps.DUP2_X2:
            case ByteOps.SWAP:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
                    return 1;
                }
            case ByteOps.IADD:
            case ByteOps.ISUB:
            case ByteOps.IMUL:
            case ByteOps.IDIV:
            case ByteOps.IREM:
            case ByteOps.INEG:
            case ByteOps.ISHL:
            case ByteOps.ISHR:
            case ByteOps.IUSHR:
            case ByteOps.IAND:
            case ByteOps.IOR:
            case ByteOps.IXOR:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.INT);
                    return 1;
                }
            case ByteOps.LADD:
            case ByteOps.LSUB:
            case ByteOps.LMUL:
            case ByteOps.LDIV:
            case ByteOps.LREM:
            case ByteOps.LNEG:
            case ByteOps.LSHL:
            case ByteOps.LSHR:
            case ByteOps.LUSHR:
            case ByteOps.LAND:
            case ByteOps.LOR:
            case ByteOps.LXOR:
                {
                    /*
                     * It's "opcode - 1" because, conveniently enough, all
                     * these long ops are one past the int variants.
                     */
                    visitor.visitNoArgs(opcode - 1, offset, 1, Type.LONG);
                    return 1;
                }
            case ByteOps.FADD:
            case ByteOps.FSUB:
            case ByteOps.FMUL:
            case ByteOps.FDIV:
            case ByteOps.FREM:
            case ByteOps.FNEG:
                {
                    /*
                     * It's "opcode - 2" because, conveniently enough, all
                     * these float ops are two past the int variants.
                     */
                    visitor.visitNoArgs(opcode - 2, offset, 1, Type.FLOAT);
                    return 1;
                }
            case ByteOps.DADD:
            case ByteOps.DSUB:
            case ByteOps.DMUL:
            case ByteOps.DDIV:
            case ByteOps.DREM:
            case ByteOps.DNEG:
                {
                    /*
                     * It's "opcode - 3" because, conveniently enough, all
                     * these double ops are three past the int variants.
                     */
                    visitor.visitNoArgs(opcode - 3, offset, 1, Type.DOUBLE);
                    return 1;
                }
            case ByteOps.IINC:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    int value = bytes.getByte(offset + 2);
                    visitor.visitLocal(opcode, offset, 3, idx, Type.INT, value);
                    return 3;
                }
            case ByteOps.I2L:
            case ByteOps.F2L:
            case ByteOps.D2L:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.LONG);
                    return 1;
                }
            case ByteOps.I2F:
            case ByteOps.L2F:
            case ByteOps.D2F:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.FLOAT);
                    return 1;
                }
            case ByteOps.I2D:
            case ByteOps.L2D:
            case ByteOps.F2D:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.DOUBLE);
                    return 1;
                }
            case ByteOps.L2I:
            case ByteOps.F2I:
            case ByteOps.D2I:
            case ByteOps.I2B:
            case ByteOps.I2C:
            case ByteOps.I2S:
            case ByteOps.LCMP:
            case ByteOps.FCMPL:
            case ByteOps.FCMPG:
            case ByteOps.DCMPL:
            case ByteOps.DCMPG:
            case ByteOps.ARRAYLENGTH:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.INT);
                    return 1;
                }
            case ByteOps.IFEQ:
            case ByteOps.IFNE:
            case ByteOps.IFLT:
            case ByteOps.IFGE:
            case ByteOps.IFGT:
            case ByteOps.IFLE:
            case ByteOps.IF_ICMPEQ:
            case ByteOps.IF_ICMPNE:
            case ByteOps.IF_ICMPLT:
            case ByteOps.IF_ICMPGE:
            case ByteOps.IF_ICMPGT:
            case ByteOps.IF_ICMPLE:
            case ByteOps.IF_ACMPEQ:
            case ByteOps.IF_ACMPNE:
            case ByteOps.GOTO:
            case ByteOps.JSR:
            case ByteOps.IFNULL:
            case ByteOps.IFNONNULL:
                {
                    int target = offset + bytes.getShort(offset + 1);
                    visitor.visitBranch(opcode, offset, 3, target);
                    return 3;
                }
            case ByteOps.RET:
                {
                    int idx = bytes.getUnsignedByte(offset + 1);
                    visitor.visitLocal(opcode, offset, 2, idx, Type.RETURN_ADDRESS, 0);
                    return 2;
                }
            case ByteOps.TABLESWITCH:
                {
                    return parseTableswitch(offset, visitor);
                }
            case ByteOps.LOOKUPSWITCH:
                {
                    return parseLookupswitch(offset, visitor);
                }
            case ByteOps.IRETURN:
                {
                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.INT);
                    return 1;
                }
            case ByteOps.LRETURN:
                {
                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.LONG);
                    return 1;
                }
            case ByteOps.FRETURN:
                {
                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.FLOAT);
                    return 1;
                }
            case ByteOps.DRETURN:
                {
                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.DOUBLE);
                    return 1;
                }
            case ByteOps.ARETURN:
                {
                    visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.OBJECT);
                    return 1;
                }
            case ByteOps.RETURN:
            case ByteOps.ATHROW:
            case ByteOps.MONITORENTER:
            case ByteOps.MONITOREXIT:
                {
                    visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
                    return 1;
                }
            case ByteOps.GETSTATIC:
            case ByteOps.PUTSTATIC:
            case ByteOps.GETFIELD:
            case ByteOps.PUTFIELD:
            case ByteOps.INVOKEVIRTUAL:
            case ByteOps.INVOKESPECIAL:
            case ByteOps.INVOKESTATIC:
            case ByteOps.NEW:
            case ByteOps.ANEWARRAY:
            case ByteOps.CHECKCAST:
            case ByteOps.INSTANCEOF:
                {
                    int idx = bytes.getUnsignedShort(offset + 1);
                    Constant cst = pool.get(idx);
                    visitor.visitConstant(opcode, offset, 3, cst, 0);
                    return 3;
                }
            case ByteOps.INVOKEINTERFACE:
                {
                    int idx = bytes.getUnsignedShort(offset + 1);
                    int count = bytes.getUnsignedByte(offset + 3);
                    int expectZero = bytes.getUnsignedByte(offset + 4);
                    Constant cst = pool.get(idx);
                    visitor.visitConstant(opcode, offset, 5, cst, count | (expectZero << 8));
                    return 5;
                }
            case ByteOps.INVOKEDYNAMIC:
                {
                    throw new ParseException("invokedynamic not supported");
                }
            case ByteOps.NEWARRAY:
                {
                    return parseNewarray(offset, visitor);
                }
            case ByteOps.WIDE:
                {
                    return parseWide(offset, visitor);
                }
            case ByteOps.MULTIANEWARRAY:
                {
                    int idx = bytes.getUnsignedShort(offset + 1);
                    int dimensions = bytes.getUnsignedByte(offset + 3);
                    Constant cst = pool.get(idx);
                    visitor.visitConstant(opcode, offset, 4, cst, dimensions);
                    return 4;
                }
            case ByteOps.GOTO_W:
            case ByteOps.JSR_W:
                {
                    int target = offset + bytes.getInt(offset + 1);
                    int newop = (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO : ByteOps.JSR;
                    visitor.visitBranch(newop, offset, 5, target);
                    return 5;
                }
            default:
                {
                    visitor.visitInvalid(opcode, offset, 1);
                    return 1;
                }
        }
    } catch (SimException ex) {
        ex.addContext("...at bytecode offset " + Hex.u4(offset));
        throw ex;
    } catch (RuntimeException ex) {
        SimException se = new SimException(ex);
        se.addContext("...at bytecode offset " + Hex.u4(offset));
        throw se;
    }
}
Also used : Constant(com.android.dx.rop.cst.Constant) CstInteger(com.android.dx.rop.cst.CstInteger) ParseException(com.android.dx.cf.iface.ParseException)

Example 10 with CstInteger

use of com.android.dx.rop.cst.CstInteger in project J2ME-Loader by nikita36078.

the class SCCP method simulateMath.

/**
 * Simulates math insns, if possible.
 *
 * @param insn non-null insn to simulate
 * @param resultType basic type of the result
 * @return constant result or null if not simulatable.
 */
private Constant simulateMath(SsaInsn insn, int resultType) {
    Insn ropInsn = insn.getOriginalRopInsn();
    int opcode = insn.getOpcode().getOpcode();
    RegisterSpecList sources = insn.getSources();
    int regA = sources.get(0).getReg();
    Constant cA;
    Constant cB;
    if (latticeValues[regA] != CONSTANT) {
        cA = null;
    } else {
        cA = latticeConstants[regA];
    }
    if (sources.size() == 1) {
        CstInsn cstInsn = (CstInsn) ropInsn;
        cB = cstInsn.getConstant();
    } else {
        /* sources.size() == 2 */
        int regB = sources.get(1).getReg();
        if (latticeValues[regB] != CONSTANT) {
            cB = null;
        } else {
            cB = latticeConstants[regB];
        }
    }
    if (cA == null || cB == null) {
        // TODO handle a constant of 0 with MUL or AND
        return null;
    }
    switch(resultType) {
        case Type.BT_INT:
            int vR;
            boolean skip = false;
            int vA = ((CstInteger) cA).getValue();
            int vB = ((CstInteger) cB).getValue();
            switch(opcode) {
                case RegOps.ADD:
                    vR = vA + vB;
                    break;
                case RegOps.SUB:
                    // 1 source for reverse sub, 2 sources for regular sub
                    if (sources.size() == 1) {
                        vR = vB - vA;
                    } else {
                        vR = vA - vB;
                    }
                    break;
                case RegOps.MUL:
                    vR = vA * vB;
                    break;
                case RegOps.DIV:
                    if (vB == 0) {
                        skip = true;
                        // just to hide a warning
                        vR = 0;
                    } else {
                        vR = vA / vB;
                    }
                    break;
                case RegOps.AND:
                    vR = vA & vB;
                    break;
                case RegOps.OR:
                    vR = vA | vB;
                    break;
                case RegOps.XOR:
                    vR = vA ^ vB;
                    break;
                case RegOps.SHL:
                    vR = vA << vB;
                    break;
                case RegOps.SHR:
                    vR = vA >> vB;
                    break;
                case RegOps.USHR:
                    vR = vA >>> vB;
                    break;
                case RegOps.REM:
                    if (vB == 0) {
                        skip = true;
                        // just to hide a warning
                        vR = 0;
                    } else {
                        vR = vA % vB;
                    }
                    break;
                default:
                    throw new RuntimeException("Unexpected op");
            }
            return skip ? null : CstInteger.make(vR);
        default:
            // not yet supported
            return null;
    }
}
Also used : CstInsn(com.android.dx.rop.code.CstInsn) Insn(com.android.dx.rop.code.Insn) PlainInsn(com.android.dx.rop.code.PlainInsn) CstInsn(com.android.dx.rop.code.CstInsn) Constant(com.android.dx.rop.cst.Constant) TypedConstant(com.android.dx.rop.cst.TypedConstant) CstInteger(com.android.dx.rop.cst.CstInteger) RegisterSpecList(com.android.dx.rop.code.RegisterSpecList)

Aggregations

CstInteger (com.android.dx.rop.cst.CstInteger)19 Constant (com.android.dx.rop.cst.Constant)12 CstInsn (com.android.dx.rop.code.CstInsn)6 RegisterSpecList (com.android.dx.rop.code.RegisterSpecList)6 Rop (com.android.dx.rop.code.Rop)6 CstType (com.android.dx.rop.cst.CstType)6 Insn (com.android.dx.rop.code.Insn)5 PlainInsn (com.android.dx.rop.code.PlainInsn)5 ParseException (com.android.dx.cf.iface.ParseException)4 RegisterSpec (com.android.dx.rop.code.RegisterSpec)4 TypedConstant (com.android.dx.rop.cst.TypedConstant)4 Type (com.android.dx.rop.type.Type)4 TypeBearer (com.android.dx.rop.type.TypeBearer)4 PlainCstInsn (com.android.dx.rop.code.PlainCstInsn)3 ThrowingCstInsn (com.android.dx.rop.code.ThrowingCstInsn)3 ThrowingInsn (com.android.dx.rop.code.ThrowingInsn)3 ArrayList (java.util.ArrayList)3 Annotation (com.android.dx.rop.annotation.Annotation)2 AnnotationsList (com.android.dx.rop.annotation.AnnotationsList)2 FillArrayDataInsn (com.android.dx.rop.code.FillArrayDataInsn)2