Search in sources :

Example 6 with ParseException

use of com.taobao.android.dx.cf.iface.ParseException in project atlas by alibaba.

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.taobao.android.dx.rop.cst.Constant) CstInteger(com.taobao.android.dx.rop.cst.CstInteger) ParseException(com.taobao.android.dx.cf.iface.ParseException)

Example 7 with ParseException

use of com.taobao.android.dx.cf.iface.ParseException in project atlas by alibaba.

the class ConstantPoolParser method parse0.

/**
 * Parses the constant for the given index if it hasn't already been
 * parsed, also storing it in the constant pool. This will also
 * have the side effect of parsing any entries the indicated one
 * depends on.
 *
 * @param idx which constant
 * @return {@code non-null;} the parsed constant
 */
private Constant parse0(int idx, BitSet wasUtf8) {
    Constant cst = pool.getOrNull(idx);
    if (cst != null) {
        return cst;
    }
    int at = offsets[idx];
    try {
        int tag = bytes.getUnsignedByte(at);
        switch(tag) {
            case CONSTANT_Utf8:
                {
                    cst = parseUtf8(at);
                    wasUtf8.set(idx);
                    break;
                }
            case CONSTANT_Integer:
                {
                    int value = bytes.getInt(at + 1);
                    cst = CstInteger.make(value);
                    break;
                }
            case CONSTANT_Float:
                {
                    int bits = bytes.getInt(at + 1);
                    cst = CstFloat.make(bits);
                    break;
                }
            case CONSTANT_Long:
                {
                    long value = bytes.getLong(at + 1);
                    cst = CstLong.make(value);
                    break;
                }
            case CONSTANT_Double:
                {
                    long bits = bytes.getLong(at + 1);
                    cst = CstDouble.make(bits);
                    break;
                }
            case CONSTANT_Class:
                {
                    int nameIndex = bytes.getUnsignedShort(at + 1);
                    CstString name = (CstString) parse0(nameIndex, wasUtf8);
                    cst = new CstType(Type.internClassName(name.getString()));
                    break;
                }
            case CONSTANT_String:
                {
                    int stringIndex = bytes.getUnsignedShort(at + 1);
                    cst = parse0(stringIndex, wasUtf8);
                    break;
                }
            case CONSTANT_Fieldref:
                {
                    int classIndex = bytes.getUnsignedShort(at + 1);
                    CstType type = (CstType) parse0(classIndex, wasUtf8);
                    int natIndex = bytes.getUnsignedShort(at + 3);
                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
                    cst = new CstFieldRef(type, nat);
                    break;
                }
            case CONSTANT_Methodref:
                {
                    int classIndex = bytes.getUnsignedShort(at + 1);
                    CstType type = (CstType) parse0(classIndex, wasUtf8);
                    int natIndex = bytes.getUnsignedShort(at + 3);
                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
                    cst = new CstMethodRef(type, nat);
                    break;
                }
            case CONSTANT_InterfaceMethodref:
                {
                    int classIndex = bytes.getUnsignedShort(at + 1);
                    CstType type = (CstType) parse0(classIndex, wasUtf8);
                    int natIndex = bytes.getUnsignedShort(at + 3);
                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
                    cst = new CstInterfaceMethodRef(type, nat);
                    break;
                }
            case CONSTANT_NameAndType:
                {
                    int nameIndex = bytes.getUnsignedShort(at + 1);
                    CstString name = (CstString) parse0(nameIndex, wasUtf8);
                    int descriptorIndex = bytes.getUnsignedShort(at + 3);
                    CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8);
                    cst = new CstNat(name, descriptor);
                    break;
                }
            case CONSTANT_MethodHandle:
                {
                    throw new ParseException("MethodHandle not supported");
                }
            case CONSTANT_MethodType:
                {
                    throw new ParseException("MethodType not supported");
                }
            case CONSTANT_InvokeDynamic:
                {
                    throw new ParseException("InvokeDynamic not supported");
                }
            default:
                {
                    throw new ParseException("unknown tag byte: " + Hex.u1(tag));
                }
        }
    } catch (ParseException ex) {
        ex.addContext("...while parsing cst " + Hex.u2(idx) + " at offset " + Hex.u4(at));
        throw ex;
    } catch (RuntimeException ex) {
        ParseException pe = new ParseException(ex);
        pe.addContext("...while parsing cst " + Hex.u2(idx) + " at offset " + Hex.u4(at));
        throw pe;
    }
    pool.set(idx, cst);
    return cst;
}
Also used : CstNat(com.taobao.android.dx.rop.cst.CstNat) Constant(com.taobao.android.dx.rop.cst.Constant) CstType(com.taobao.android.dx.rop.cst.CstType) CstString(com.taobao.android.dx.rop.cst.CstString) CstFieldRef(com.taobao.android.dx.rop.cst.CstFieldRef) CstInterfaceMethodRef(com.taobao.android.dx.rop.cst.CstInterfaceMethodRef) ParseException(com.taobao.android.dx.cf.iface.ParseException) CstMethodRef(com.taobao.android.dx.rop.cst.CstMethodRef)

Example 8 with ParseException

use of com.taobao.android.dx.cf.iface.ParseException in project atlas by alibaba.

the class ConstantPoolParser method determineOffsets.

/**
 * Populates {@link #offsets} and also completely parse utf8 constants.
 */
private void determineOffsets() {
    // offset from the start of the file to the first cst
    int at = 10;
    int lastCategory;
    for (int i = 1; i < offsets.length; i += lastCategory) {
        offsets[i] = at;
        int tag = bytes.getUnsignedByte(at);
        try {
            switch(tag) {
                case CONSTANT_Integer:
                case CONSTANT_Float:
                case CONSTANT_Fieldref:
                case CONSTANT_Methodref:
                case CONSTANT_InterfaceMethodref:
                case CONSTANT_NameAndType:
                    {
                        lastCategory = 1;
                        at += 5;
                        break;
                    }
                case CONSTANT_Long:
                case CONSTANT_Double:
                    {
                        lastCategory = 2;
                        at += 9;
                        break;
                    }
                case CONSTANT_Class:
                case CONSTANT_String:
                    {
                        lastCategory = 1;
                        at += 3;
                        break;
                    }
                case CONSTANT_Utf8:
                    {
                        lastCategory = 1;
                        at += bytes.getUnsignedShort(at + 1) + 3;
                        break;
                    }
                case CONSTANT_MethodHandle:
                    {
                        throw new ParseException("MethodHandle not supported");
                    }
                case CONSTANT_MethodType:
                    {
                        throw new ParseException("MethodType not supported");
                    }
                case CONSTANT_InvokeDynamic:
                    {
                        throw new ParseException("InvokeDynamic not supported");
                    }
                default:
                    {
                        throw new ParseException("unknown tag byte: " + Hex.u1(tag));
                    }
            }
        } catch (ParseException ex) {
            ex.addContext("...while preparsing cst " + Hex.u2(i) + " at offset " + Hex.u4(at));
            throw ex;
        }
    }
    endOffset = at;
}
Also used : ParseException(com.taobao.android.dx.cf.iface.ParseException)

Example 9 with ParseException

use of com.taobao.android.dx.cf.iface.ParseException in project atlas by alibaba.

the class AnnotationParser method parseValue.

/**
 * Parses an annotation value.
 *
 * @return {@code non-null;} the parsed value
 */
private Constant parseValue() throws IOException {
    int tag = input.readUnsignedByte();
    if (observer != null) {
        CstString humanTag = new CstString(Character.toString((char) tag));
        parsed(1, "tag: " + humanTag.toQuoted());
    }
    switch(tag) {
        case 'B':
            {
                CstInteger value = (CstInteger) parseConstant();
                return CstByte.make(value.getValue());
            }
        case 'C':
            {
                CstInteger value = (CstInteger) parseConstant();
                int intValue = value.getValue();
                return CstChar.make(value.getValue());
            }
        case 'D':
            {
                CstDouble value = (CstDouble) parseConstant();
                return value;
            }
        case 'F':
            {
                CstFloat value = (CstFloat) parseConstant();
                return value;
            }
        case 'I':
            {
                CstInteger value = (CstInteger) parseConstant();
                return value;
            }
        case 'J':
            {
                CstLong value = (CstLong) parseConstant();
                return value;
            }
        case 'S':
            {
                CstInteger value = (CstInteger) parseConstant();
                return CstShort.make(value.getValue());
            }
        case 'Z':
            {
                CstInteger value = (CstInteger) parseConstant();
                return CstBoolean.make(value.getValue());
            }
        case 'c':
            {
                int classInfoIndex = input.readUnsignedShort();
                CstString value = (CstString) pool.get(classInfoIndex);
                Type type = Type.internReturnType(value.getString());
                if (observer != null) {
                    parsed(2, "class_info: " + type.toHuman());
                }
                return new CstType(type);
            }
        case 's':
            {
                return parseConstant();
            }
        case 'e':
            {
                requireLength(4);
                int typeNameIndex = input.readUnsignedShort();
                int constNameIndex = input.readUnsignedShort();
                CstString typeName = (CstString) pool.get(typeNameIndex);
                CstString constName = (CstString) pool.get(constNameIndex);
                if (observer != null) {
                    parsed(2, "type_name: " + typeName.toHuman());
                    parsed(2, "const_name: " + constName.toHuman());
                }
                return new CstEnumRef(new CstNat(constName, typeName));
            }
        case '@':
            {
                Annotation annotation = parseAnnotation(AnnotationVisibility.EMBEDDED);
                return new CstAnnotation(annotation);
            }
        case '[':
            {
                requireLength(2);
                int numValues = input.readUnsignedShort();
                CstArray.List list = new CstArray.List(numValues);
                if (observer != null) {
                    parsed(2, "num_values: " + numValues);
                    changeIndent(1);
                }
                for (int i = 0; i < numValues; i++) {
                    if (observer != null) {
                        changeIndent(-1);
                        parsed(0, "element_value[" + i + "]:");
                        changeIndent(1);
                    }
                    list.set(i, parseValue());
                }
                if (observer != null) {
                    changeIndent(-1);
                }
                list.setImmutable();
                return new CstArray(list);
            }
        default:
            {
                throw new ParseException("unknown annotation tag: " + Hex.u1(tag));
            }
    }
}
Also used : CstFloat(com.taobao.android.dx.rop.cst.CstFloat) CstNat(com.taobao.android.dx.rop.cst.CstNat) CstArray(com.taobao.android.dx.rop.cst.CstArray) CstLong(com.taobao.android.dx.rop.cst.CstLong) CstString(com.taobao.android.dx.rop.cst.CstString) CstAnnotation(com.taobao.android.dx.rop.cst.CstAnnotation) CstDouble(com.taobao.android.dx.rop.cst.CstDouble) CstEnumRef(com.taobao.android.dx.rop.cst.CstEnumRef) Annotation(com.taobao.android.dx.rop.annotation.Annotation) CstAnnotation(com.taobao.android.dx.rop.cst.CstAnnotation) CstType(com.taobao.android.dx.rop.cst.CstType) Type(com.taobao.android.dx.rop.type.Type) CstInteger(com.taobao.android.dx.rop.cst.CstInteger) CstType(com.taobao.android.dx.rop.cst.CstType) AnnotationsList(com.taobao.android.dx.rop.annotation.AnnotationsList) ParseException(com.taobao.android.dx.cf.iface.ParseException)

Example 10 with ParseException

use of com.taobao.android.dx.cf.iface.ParseException in project atlas by alibaba.

the class AttributeListParser method parse.

/**
 * Does the actual parsing.
 */
private void parse() {
    int sz = list.size();
    // Skip the count.
    int at = offset + 2;
    ByteArray bytes = cf.getBytes();
    if (observer != null) {
        observer.parsed(bytes, offset, 2, "attributes_count: " + Hex.u2(sz));
    }
    for (int i = 0; i < sz; i++) {
        try {
            if (observer != null) {
                observer.parsed(bytes, at, 0, "\nattributes[" + i + "]:\n");
                observer.changeIndent(1);
            }
            Attribute attrib = attributeFactory.parse(cf, context, at, observer);
            at += attrib.byteLength();
            list.set(i, attrib);
            if (observer != null) {
                observer.changeIndent(-1);
                observer.parsed(bytes, at, 0, "end attributes[" + i + "]\n");
            }
        } catch (ParseException ex) {
            ex.addContext("...while parsing attributes[" + i + "]");
            throw ex;
        } catch (RuntimeException ex) {
            ParseException pe = new ParseException(ex);
            pe.addContext("...while parsing attributes[" + i + "]");
            throw pe;
        }
    }
    endOffset = at;
}
Also used : Attribute(com.taobao.android.dx.cf.iface.Attribute) ByteArray(com.taobao.android.dx.util.ByteArray) ParseException(com.taobao.android.dx.cf.iface.ParseException)

Aggregations

ParseException (com.taobao.android.dx.cf.iface.ParseException)10 CstString (com.taobao.android.dx.rop.cst.CstString)6 ByteArray (com.taobao.android.dx.util.ByteArray)4 CstNat (com.taobao.android.dx.rop.cst.CstNat)3 Constant (com.taobao.android.dx.rop.cst.Constant)2 ConstantPool (com.taobao.android.dx.rop.cst.ConstantPool)2 CstInteger (com.taobao.android.dx.rop.cst.CstInteger)2 CstType (com.taobao.android.dx.rop.cst.CstType)2 ConstantPoolParser (com.taobao.android.dx.cf.cst.ConstantPoolParser)1 DirectClassFile (com.taobao.android.dx.cf.direct.DirectClassFile)1 Attribute (com.taobao.android.dx.cf.iface.Attribute)1 Member (com.taobao.android.dx.cf.iface.Member)1 StdAttributeList (com.taobao.android.dx.cf.iface.StdAttributeList)1 ClassDefItem (com.taobao.android.dx.dex.file.ClassDefItem)1 DexFile (com.taobao.android.dx.dex.file.DexFile)1 Annotation (com.taobao.android.dx.rop.annotation.Annotation)1 AnnotationsList (com.taobao.android.dx.rop.annotation.AnnotationsList)1 CstAnnotation (com.taobao.android.dx.rop.cst.CstAnnotation)1 CstArray (com.taobao.android.dx.rop.cst.CstArray)1 CstDouble (com.taobao.android.dx.rop.cst.CstDouble)1