";
-
/**
* Boolean data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_BOOLEAN = 4;
-
/**
* Char data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_CHAR = 5;
-
/**
* Float data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_FLOAT = 6;
-
/**
* Double data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_DOUBLE = 7;
-
/**
* Byte data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_BYTE = 8;
-
/**
* Short data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_SHORT = 9;
-
/**
* Int data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_INT = 10;
-
/**
* Long data type.
*
* @see Static Constraints in
- * the Java Virtual Machine Specification
+ * the Java Virtual Machine Specification
*/
public static final byte T_LONG = 11;
-
- /** Void data type (non-standard). */
+ /**
+ * Void data type (non-standard).
+ */
public static final byte T_VOID = 12; // Non-standard
-
- /** Array data type. */
+ /**
+ * Array data type.
+ */
public static final byte T_ARRAY = 13;
-
- /** Object data type. */
+ /**
+ * Object data type.
+ */
public static final byte T_OBJECT = 14;
-
- /** Reference data type (deprecated). */
+ /**
+ * Reference data type (deprecated).
+ */
public static final byte T_REFERENCE = 14; // Deprecated
-
- /** Unknown data type. */
+ /**
+ * Unknown data type.
+ */
public static final byte T_UNKNOWN = 15;
-
- /** Address data type. */
+ /**
+ * Address data type.
+ */
public static final byte T_ADDRESS = 16;
-
- /**
- * The primitive type names corresponding to the T_XX constants, e.g., TYPE_NAMES[T_INT] = "int"
- */
- private static final String[] TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "boolean", "char", "float", "double", "byte", "short",
- "int", "long", "void", "array", "object", "unknown", "address"};
-
- /**
- * The primitive class names corresponding to the T_XX constants, e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer"
- */
- private static final String[] CLASS_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "java.lang.Boolean", "java.lang.Character",
- "java.lang.Float", "java.lang.Double", "java.lang.Byte", "java.lang.Short", "java.lang.Integer", "java.lang.Long", "java.lang.Void", ILLEGAL_TYPE,
- ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE};
-
- /**
- * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I"
- */
- private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V",
- ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE};
-
- /**
- * Number of byte code operands for each opcode, i.e., number of bytes after the tag byte itself. Indexed by opcode, so
- * NO_OF_OPERANDS[BIPUSH] = the number of operands for a bipush instruction.
- */
- static final short[] NO_OF_OPERANDS = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */,
- 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */,
- 0/* dconst_1 */, 1/* bipush */, 2/* sipush */, 1/* ldc */, 2/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 1/* lload */, 1/* fload */, 1/* dload */,
- 1/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */,
- 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */,
- 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 0/* iaload */, 0/* laload */, 0/* faload */, 0/* daload */, 0/* aaload */, 0/* baload */, 0/* caload */,
- 0/* saload */, 1/* istore */, 1/* lstore */, 1/* fstore */, 1/* dstore */, 1/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */,
- 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */,
- 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */,
- 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 0/* dup */,
- 0/* dup_x1 */, 0/* dup_x2 */, 0/* dup2 */, 0/* dup2_x1 */, 0/* dup2_x2 */, 0/* swap */, 0/* iadd */, 0/* ladd */, 0/* fadd */, 0/* dadd */, 0/* isub */,
- 0/* lsub */, 0/* fsub */, 0/* dsub */, 0/* imul */, 0/* lmul */, 0/* fmul */, 0/* dmul */, 0/* idiv */, 0/* ldiv */, 0/* fdiv */, 0/* ddiv */,
- 0/* irem */, 0/* lrem */, 0/* frem */, 0/* drem */, 0/* ineg */, 0/* lneg */, 0/* fneg */, 0/* dneg */, 0/* ishl */, 0/* lshl */, 0/* ishr */,
- 0/* lshr */, 0/* iushr */, 0/* lushr */, 0/* iand */, 0/* land */, 0/* ior */, 0/* lor */, 0/* ixor */, 0/* lxor */, 2/* iinc */, 0/* i2l */,
- 0/* i2f */, 0/* i2d */, 0/* l2i */, 0/* l2f */, 0/* l2d */, 0/* f2i */, 0/* f2l */, 0/* f2d */, 0/* d2i */, 0/* d2l */, 0/* d2f */, 0/* i2b */,
- 0/* i2c */, 0/* i2s */, 0/* lcmp */, 0/* fcmpl */, 0/* fcmpg */, 0/* dcmpl */, 0/* dcmpg */, 2/* ifeq */, 2/* ifne */, 2/* iflt */, 2/* ifge */,
- 2/* ifgt */, 2/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2/* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */,
- 2/* if_acmpne */, 2/* goto */, 2/* jsr */, 1/* ret */, UNPREDICTABLE/* tableswitch */, UNPREDICTABLE/* lookupswitch */, 0/* ireturn */, 0/* lreturn */,
- 0/* freturn */, 0/* dreturn */, 0/* areturn */, 0/* return */, 2/* getstatic */, 2/* putstatic */, 2/* getfield */, 2/* putfield */,
- 2/* invokevirtual */, 2/* invokespecial */, 2/* invokestatic */, 4/* invokeinterface */, 4/* invokedynamic */, 2/* new */, 1/* newarray */,
- 2/* anewarray */, 0/* arraylength */, 0/* athrow */, 2/* checkcast */, 2/* instanceof */, 0/* monitorenter */, 0/* monitorexit */,
- UNPREDICTABLE/* wide */, 3/* multianewarray */, 2/* ifnull */, 2/* ifnonnull */, 4/* goto_w */, 4/* jsr_w */, 0/* breakpoint */, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, RESERVED/* impdep1 */,
- RESERVED/* impdep2 */
- };
-
- /**
- * How the byte code operands are to be interpreted for each opcode. Indexed by opcode. TYPE_OF_OPERANDS[ILOAD] = an
- * array of shorts describing the data types for the instruction.
- */
- static final short[][] TYPE_OF_OPERANDS = {{}/* nop */, {}/* aconst_null */, {}/* iconst_m1 */, {}/* iconst_0 */, {}/* iconst_1 */,
- {}/* iconst_2 */, {}/* iconst_3 */, {}/* iconst_4 */, {}/* iconst_5 */, {}/* lconst_0 */, {}/* lconst_1 */, {}/* fconst_0 */, {}/* fconst_1 */,
- {}/* fconst_2 */, {}/* dconst_0 */, {}/* dconst_1 */, {T_BYTE}/* bipush */, {T_SHORT}/* sipush */, {T_BYTE}/* ldc */, {T_SHORT}/* ldc_w */,
- {T_SHORT}/* ldc2_w */, {T_BYTE}/* iload */, {T_BYTE}/* lload */, {T_BYTE}/* fload */, {T_BYTE}/* dload */, {T_BYTE}/* aload */, {}/* iload_0 */,
- {}/* iload_1 */, {}/* iload_2 */, {}/* iload_3 */, {}/* lload_0 */, {}/* lload_1 */, {}/* lload_2 */, {}/* lload_3 */, {}/* fload_0 */, {}/* fload_1 */,
- {}/* fload_2 */, {}/* fload_3 */, {}/* dload_0 */, {}/* dload_1 */, {}/* dload_2 */, {}/* dload_3 */, {}/* aload_0 */, {}/* aload_1 */, {}/* aload_2 */,
- {}/* aload_3 */, {}/* iaload */, {}/* laload */, {}/* faload */, {}/* daload */, {}/* aaload */, {}/* baload */, {}/* caload */, {}/* saload */,
- {T_BYTE}/* istore */, {T_BYTE}/* lstore */, {T_BYTE}/* fstore */, {T_BYTE}/* dstore */, {T_BYTE}/* astore */, {}/* istore_0 */, {}/* istore_1 */,
- {}/* istore_2 */, {}/* istore_3 */, {}/* lstore_0 */, {}/* lstore_1 */, {}/* lstore_2 */, {}/* lstore_3 */, {}/* fstore_0 */, {}/* fstore_1 */,
- {}/* fstore_2 */, {}/* fstore_3 */, {}/* dstore_0 */, {}/* dstore_1 */, {}/* dstore_2 */, {}/* dstore_3 */, {}/* astore_0 */, {}/* astore_1 */,
- {}/* astore_2 */, {}/* astore_3 */, {}/* iastore */, {}/* lastore */, {}/* fastore */, {}/* dastore */, {}/* aastore */, {}/* bastore */,
- {}/* castore */, {}/* sastore */, {}/* pop */, {}/* pop2 */, {}/* dup */, {}/* dup_x1 */, {}/* dup_x2 */, {}/* dup2 */, {}/* dup2_x1 */,
- {}/* dup2_x2 */, {}/* swap */, {}/* iadd */, {}/* ladd */, {}/* fadd */, {}/* dadd */, {}/* isub */, {}/* lsub */, {}/* fsub */, {}/* dsub */,
- {}/* imul */, {}/* lmul */, {}/* fmul */, {}/* dmul */, {}/* idiv */, {}/* ldiv */, {}/* fdiv */, {}/* ddiv */, {}/* irem */, {}/* lrem */,
- {}/* frem */, {}/* drem */, {}/* ineg */, {}/* lneg */, {}/* fneg */, {}/* dneg */, {}/* ishl */, {}/* lshl */, {}/* ishr */, {}/* lshr */,
- {}/* iushr */, {}/* lushr */, {}/* iand */, {}/* land */, {}/* ior */, {}/* lor */, {}/* ixor */, {}/* lxor */, {T_BYTE, T_BYTE}/* iinc */, {}/* i2l */,
- {}/* i2f */, {}/* i2d */, {}/* l2i */, {}/* l2f */, {}/* l2d */, {}/* f2i */, {}/* f2l */, {}/* f2d */, {}/* d2i */, {}/* d2l */, {}/* d2f */,
- {}/* i2b */, {}/* i2c */, {}/* i2s */, {}/* lcmp */, {}/* fcmpl */, {}/* fcmpg */, {}/* dcmpl */, {}/* dcmpg */, {T_SHORT}/* ifeq */,
- {T_SHORT}/* ifne */, {T_SHORT}/* iflt */, {T_SHORT}/* ifge */, {T_SHORT}/* ifgt */, {T_SHORT}/* ifle */, {T_SHORT}/* if_icmpeq */,
- {T_SHORT}/* if_icmpne */, {T_SHORT}/* if_icmplt */, {T_SHORT}/* if_icmpge */, {T_SHORT}/* if_icmpgt */, {T_SHORT}/* if_icmple */,
- {T_SHORT}/* if_acmpeq */, {T_SHORT}/* if_acmpne */, {T_SHORT}/* goto */, {T_SHORT}/* jsr */, {T_BYTE}/* ret */, {}/* tableswitch */,
- {}/* lookupswitch */, {}/* ireturn */, {}/* lreturn */, {}/* freturn */, {}/* dreturn */, {}/* areturn */, {}/* return */, {T_SHORT}/* getstatic */,
- {T_SHORT}/* putstatic */, {T_SHORT}/* getfield */, {T_SHORT}/* putfield */, {T_SHORT}/* invokevirtual */, {T_SHORT}/* invokespecial */,
- {T_SHORT}/* invokestatic */, {T_SHORT, T_BYTE, T_BYTE}/* invokeinterface */, {T_SHORT, T_BYTE, T_BYTE}/* invokedynamic */, {T_SHORT}/* new */,
- {T_BYTE}/* newarray */, {T_SHORT}/* anewarray */, {}/* arraylength */, {}/* athrow */, {T_SHORT}/* checkcast */, {T_SHORT}/* instanceof */,
- {}/* monitorenter */, {}/* monitorexit */, {T_BYTE}/* wide */, {T_SHORT, T_BYTE}/* multianewarray */, {T_SHORT}/* ifnull */, {T_SHORT}/* ifnonnull */,
- {T_INT}/* goto_w */, {T_INT}/* jsr_w */, {}/* breakpoint */, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
- {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}/* impdep1 */, {}/* impdep2 */
- };
-
- /**
- * Names of opcodes. Indexed by opcode. OPCODE_NAMES[ALOAD] = "aload".
- */
- static final String[] OPCODE_NAMES = {"nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5",
- "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload",
- "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2",
- "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload",
- "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1",
- "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1",
- "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1",
- "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv",
- "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand",
- "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s",
- "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge",
- "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn",
- "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface",
- "invokedynamic", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide",
- "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
- ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
- ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
- ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
- ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
- ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
- ILLEGAL_OPCODE, ILLEGAL_OPCODE, "impdep1", "impdep2"};
-
- /**
- * @since 6.0
- */
- public static final int OPCODE_NAMES_LENGTH = OPCODE_NAMES.length;
-
- /**
- * Number of words consumed on operand stack by instructions. Indexed by opcode. CONSUME_STACK[FALOAD] = number of words
- * consumed from the stack by a faload instruction.
- */
- static final int[] CONSUME_STACK = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */,
- 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */,
- 0/* dconst_1 */, 0/* bipush */, 0/* sipush */, 0/* ldc */, 0/* ldc_w */, 0/* ldc2_w */, 0/* iload */, 0/* lload */, 0/* fload */, 0/* dload */,
- 0/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */,
- 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */,
- 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 2/* iaload */, 2/* laload */, 2/* faload */, 2/* daload */, 2/* aaload */, 2/* baload */, 2/* caload */,
- 2/* saload */, 1/* istore */, 2/* lstore */, 1/* fstore */, 2/* dstore */, 1/* astore */, 1/* istore_0 */, 1/* istore_1 */, 1/* istore_2 */,
- 1/* istore_3 */, 2/* lstore_0 */, 2/* lstore_1 */, 2/* lstore_2 */, 2/* lstore_3 */, 1/* fstore_0 */, 1/* fstore_1 */, 1/* fstore_2 */, 1/* fstore_3 */,
- 2/* dstore_0 */, 2/* dstore_1 */, 2/* dstore_2 */, 2/* dstore_3 */, 1/* astore_0 */, 1/* astore_1 */, 1/* astore_2 */, 1/* astore_3 */, 3/* iastore */,
- 4/* lastore */, 3/* fastore */, 4/* dastore */, 3/* aastore */, 3/* bastore */, 3/* castore */, 3/* sastore */, 1/* pop */, 2/* pop2 */, 1/* dup */,
- 2/* dup_x1 */, 3/* dup_x2 */, 2/* dup2 */, 3/* dup2_x1 */, 4/* dup2_x2 */, 2/* swap */, 2/* iadd */, 4/* ladd */, 2/* fadd */, 4/* dadd */, 2/* isub */,
- 4/* lsub */, 2/* fsub */, 4/* dsub */, 2/* imul */, 4/* lmul */, 2/* fmul */, 4/* dmul */, 2/* idiv */, 4/* ldiv */, 2/* fdiv */, 4/* ddiv */,
- 2/* irem */, 4/* lrem */, 2/* frem */, 4/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 2/* ishl */, 3/* lshl */, 2/* ishr */,
- 3/* lshr */, 2/* iushr */, 3/* lushr */, 2/* iand */, 4/* land */, 2/* ior */, 4/* lor */, 2/* ixor */, 4/* lxor */, 0/* iinc */, 1/* i2l */,
- 1/* i2f */, 1/* i2d */, 2/* l2i */, 2/* l2f */, 2/* l2d */, 1/* f2i */, 1/* f2l */, 1/* f2d */, 2/* d2i */, 2/* d2l */, 2/* d2f */, 1/* i2b */,
- 1/* i2c */, 1/* i2s */, 4/* lcmp */, 2/* fcmpl */, 2/* fcmpg */, 4/* dcmpl */, 4/* dcmpg */, 1/* ifeq */, 1/* ifne */, 1/* iflt */, 1/* ifge */,
- 1/* ifgt */, 1/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2 /* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */,
- 2/* if_acmpne */, 0/* goto */, 0/* jsr */, 0/* ret */, 1/* tableswitch */, 1/* lookupswitch */, 1/* ireturn */, 2/* lreturn */, 1/* freturn */,
- 2/* dreturn */, 1/* areturn */, 0/* return */, 0/* getstatic */, UNPREDICTABLE/* putstatic */, 1/* getfield */, UNPREDICTABLE/* putfield */,
- UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */,
- UNPREDICTABLE/* invokedynamic */, 0/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */,
- 1/* monitorenter */, 1/* monitorexit */, 0/* wide */, UNPREDICTABLE/* multianewarray */, 1/* ifnull */, 1/* ifnonnull */, 0/* goto_w */, 0/* jsr_w */,
- 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */
- };
-
- /**
- * Number of words produced onto operand stack by instructions. Indexed by opcode. CONSUME_STACK[DALOAD] = number of
- * words consumed from the stack by a daload instruction.
- */
- static final int[] PRODUCE_STACK = {0/* nop */, 1/* aconst_null */, 1/* iconst_m1 */, 1/* iconst_0 */, 1/* iconst_1 */, 1/* iconst_2 */,
- 1/* iconst_3 */, 1/* iconst_4 */, 1/* iconst_5 */, 2/* lconst_0 */, 2/* lconst_1 */, 1/* fconst_0 */, 1/* fconst_1 */, 1/* fconst_2 */, 2/* dconst_0 */,
- 2/* dconst_1 */, 1/* bipush */, 1/* sipush */, 1/* ldc */, 1/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 2/* lload */, 1/* fload */, 2/* dload */,
- 1/* aload */, 1/* iload_0 */, 1/* iload_1 */, 1/* iload_2 */, 1/* iload_3 */, 2/* lload_0 */, 2/* lload_1 */, 2/* lload_2 */, 2/* lload_3 */,
- 1/* fload_0 */, 1/* fload_1 */, 1/* fload_2 */, 1/* fload_3 */, 2/* dload_0 */, 2/* dload_1 */, 2/* dload_2 */, 2/* dload_3 */, 1/* aload_0 */,
- 1/* aload_1 */, 1/* aload_2 */, 1/* aload_3 */, 1/* iaload */, 2/* laload */, 1/* faload */, 2/* daload */, 1/* aaload */, 1/* baload */, 1/* caload */,
- 1/* saload */, 0/* istore */, 0/* lstore */, 0/* fstore */, 0/* dstore */, 0/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */,
- 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */,
- 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */,
- 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 2/* dup */,
- 3/* dup_x1 */, 4/* dup_x2 */, 4/* dup2 */, 5/* dup2_x1 */, 6/* dup2_x2 */, 2/* swap */, 1/* iadd */, 2/* ladd */, 1/* fadd */, 2/* dadd */, 1/* isub */,
- 2/* lsub */, 1/* fsub */, 2/* dsub */, 1/* imul */, 2/* lmul */, 1/* fmul */, 2/* dmul */, 1/* idiv */, 2/* ldiv */, 1/* fdiv */, 2/* ddiv */,
- 1/* irem */, 2/* lrem */, 1/* frem */, 2/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 1/* ishl */, 2/* lshl */, 1/* ishr */,
- 2/* lshr */, 1/* iushr */, 2/* lushr */, 1/* iand */, 2/* land */, 1/* ior */, 2/* lor */, 1/* ixor */, 2/* lxor */, 0/* iinc */, 2/* i2l */,
- 1/* i2f */, 2/* i2d */, 1/* l2i */, 1/* l2f */, 2/* l2d */, 1/* f2i */, 2/* f2l */, 2/* f2d */, 1/* d2i */, 2/* d2l */, 1/* d2f */, 1/* i2b */,
- 1/* i2c */, 1/* i2s */, 1/* lcmp */, 1/* fcmpl */, 1/* fcmpg */, 1/* dcmpl */, 1/* dcmpg */, 0/* ifeq */, 0/* ifne */, 0/* iflt */, 0/* ifge */,
- 0/* ifgt */, 0/* ifle */, 0/* if_icmpeq */, 0/* if_icmpne */, 0/* if_icmplt */, 0/* if_icmpge */, 0/* if_icmpgt */, 0/* if_icmple */, 0/* if_acmpeq */,
- 0/* if_acmpne */, 0/* goto */, 1/* jsr */, 0/* ret */, 0/* tableswitch */, 0/* lookupswitch */, 0/* ireturn */, 0/* lreturn */, 0/* freturn */,
- 0/* dreturn */, 0/* areturn */, 0/* return */, UNPREDICTABLE/* getstatic */, 0/* putstatic */, UNPREDICTABLE/* getfield */, 0/* putfield */,
- UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */,
- UNPREDICTABLE/* invokedynamic */, 1/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */,
- 0/* monitorenter */, 0/* monitorexit */, 0/* wide */, 1/* multianewarray */, 0/* ifnull */, 0/* ifnonnull */, 0/* goto_w */, 1/* jsr_w */,
- 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
- UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */
- };
-
/**
* Attributes and their corresponding names.
*/
public static final byte ATTR_UNKNOWN = -1;
-
public static final byte ATTR_SOURCE_FILE = 0;
-
public static final byte ATTR_CONSTANT_VALUE = 1;
-
public static final byte ATTR_CODE = 2;
-
public static final byte ATTR_EXCEPTIONS = 3;
-
public static final byte ATTR_LINE_NUMBER_TABLE = 4;
-
public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5;
-
public static final byte ATTR_INNER_CLASSES = 6;
-
public static final byte ATTR_SYNTHETIC = 7;
-
public static final byte ATTR_DEPRECATED = 8;
-
public static final byte ATTR_PMG = 9;
-
public static final byte ATTR_SIGNATURE = 10;
-
public static final byte ATTR_STACK_MAP = 11;
public static final byte ATTR_RUNTIME_VISIBLE_ANNOTATIONS = 12;
public static final byte ATTR_RUNTIME_INVISIBLE_ANNOTATIONS = 13;
@@ -3028,10 +2558,6 @@ public final class Const {
public static final byte ATTR_NEST_HOST = 25;
public static final byte ATTR_NEST_MEMBERS = 26;
public static final short KNOWN_ATTRIBUTES = 27; // count of attributes
- private static final String[] ATTRIBUTE_NAMES = {"SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable",
- "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations",
- "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod",
- "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers"};
/**
* Constants used in the StackMap attribute.
*/
@@ -3044,19 +2570,14 @@ public final class Const {
public static final byte ITEM_InitObject = 6;
public static final byte ITEM_Object = 7;
public static final byte ITEM_NewObject = 8;
- private static final String[] ITEM_NAMES = {"Bogus", "Integer", "Float", "Double", "Long", "Null", "InitObject", "Object", "NewObject"};
-
/**
* Constants used to identify StackMapEntry types.
- *
+ *
* For those types which can specify a range, the constant names the lowest value.
*/
public static final int SAME_FRAME = 0;
-
public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64;
-
public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247;
-
public static final int CHOP_FRAME = 248;
public static final int SAME_FRAME_EXTENDED = 251;
public static final int APPEND_FRAME = 252;
@@ -3070,22 +2591,219 @@ public final class Const {
public static final int CHOP_FRAME_MAX = 250;
public static final int APPEND_FRAME_MAX = 254;
public static final byte REF_getField = 1;
-
public static final byte REF_getStatic = 2;
-
public static final byte REF_putField = 3;
-
public static final byte REF_putStatic = 4;
public static final byte REF_invokeVirtual = 5;
public static final byte REF_invokeStatic = 6;
public static final byte REF_invokeSpecial = 7;
public static final byte REF_newInvokeSpecial = 8;
public static final byte REF_invokeInterface = 9;
+ /**
+ * Number of byte code operands for each opcode, i.e., number of bytes after the tag byte itself. Indexed by opcode, so
+ * NO_OF_OPERANDS[BIPUSH] = the number of operands for a bipush instruction.
+ */
+ static final short[] NO_OF_OPERANDS = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */,
+ 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */,
+ 0/* dconst_1 */, 1/* bipush */, 2/* sipush */, 1/* ldc */, 2/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 1/* lload */, 1/* fload */, 1/* dload */,
+ 1/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */,
+ 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */,
+ 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 0/* iaload */, 0/* laload */, 0/* faload */, 0/* daload */, 0/* aaload */, 0/* baload */, 0/* caload */,
+ 0/* saload */, 1/* istore */, 1/* lstore */, 1/* fstore */, 1/* dstore */, 1/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */,
+ 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */,
+ 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */,
+ 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 0/* dup */,
+ 0/* dup_x1 */, 0/* dup_x2 */, 0/* dup2 */, 0/* dup2_x1 */, 0/* dup2_x2 */, 0/* swap */, 0/* iadd */, 0/* ladd */, 0/* fadd */, 0/* dadd */, 0/* isub */,
+ 0/* lsub */, 0/* fsub */, 0/* dsub */, 0/* imul */, 0/* lmul */, 0/* fmul */, 0/* dmul */, 0/* idiv */, 0/* ldiv */, 0/* fdiv */, 0/* ddiv */,
+ 0/* irem */, 0/* lrem */, 0/* frem */, 0/* drem */, 0/* ineg */, 0/* lneg */, 0/* fneg */, 0/* dneg */, 0/* ishl */, 0/* lshl */, 0/* ishr */,
+ 0/* lshr */, 0/* iushr */, 0/* lushr */, 0/* iand */, 0/* land */, 0/* ior */, 0/* lor */, 0/* ixor */, 0/* lxor */, 2/* iinc */, 0/* i2l */,
+ 0/* i2f */, 0/* i2d */, 0/* l2i */, 0/* l2f */, 0/* l2d */, 0/* f2i */, 0/* f2l */, 0/* f2d */, 0/* d2i */, 0/* d2l */, 0/* d2f */, 0/* i2b */,
+ 0/* i2c */, 0/* i2s */, 0/* lcmp */, 0/* fcmpl */, 0/* fcmpg */, 0/* dcmpl */, 0/* dcmpg */, 2/* ifeq */, 2/* ifne */, 2/* iflt */, 2/* ifge */,
+ 2/* ifgt */, 2/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2/* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */,
+ 2/* if_acmpne */, 2/* goto */, 2/* jsr */, 1/* ret */, UNPREDICTABLE/* tableswitch */, UNPREDICTABLE/* lookupswitch */, 0/* ireturn */, 0/* lreturn */,
+ 0/* freturn */, 0/* dreturn */, 0/* areturn */, 0/* return */, 2/* getstatic */, 2/* putstatic */, 2/* getfield */, 2/* putfield */,
+ 2/* invokevirtual */, 2/* invokespecial */, 2/* invokestatic */, 4/* invokeinterface */, 4/* invokedynamic */, 2/* new */, 1/* newarray */,
+ 2/* anewarray */, 0/* arraylength */, 0/* athrow */, 2/* checkcast */, 2/* instanceof */, 0/* monitorenter */, 0/* monitorexit */,
+ UNPREDICTABLE/* wide */, 3/* multianewarray */, 2/* ifnull */, 2/* ifnonnull */, 4/* goto_w */, 4/* jsr_w */, 0/* breakpoint */, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, RESERVED/* impdep1 */,
+ RESERVED/* impdep2 */
+ };
+ /**
+ * How the byte code operands are to be interpreted for each opcode. Indexed by opcode. TYPE_OF_OPERANDS[ILOAD] = an
+ * array of shorts describing the data types for the instruction.
+ */
+ static final short[][] TYPE_OF_OPERANDS = {{}/* nop */, {}/* aconst_null */, {}/* iconst_m1 */, {}/* iconst_0 */, {}/* iconst_1 */,
+ {}/* iconst_2 */, {}/* iconst_3 */, {}/* iconst_4 */, {}/* iconst_5 */, {}/* lconst_0 */, {}/* lconst_1 */, {}/* fconst_0 */, {}/* fconst_1 */,
+ {}/* fconst_2 */, {}/* dconst_0 */, {}/* dconst_1 */, {T_BYTE}/* bipush */, {T_SHORT}/* sipush */, {T_BYTE}/* ldc */, {T_SHORT}/* ldc_w */,
+ {T_SHORT}/* ldc2_w */, {T_BYTE}/* iload */, {T_BYTE}/* lload */, {T_BYTE}/* fload */, {T_BYTE}/* dload */, {T_BYTE}/* aload */, {}/* iload_0 */,
+ {}/* iload_1 */, {}/* iload_2 */, {}/* iload_3 */, {}/* lload_0 */, {}/* lload_1 */, {}/* lload_2 */, {}/* lload_3 */, {}/* fload_0 */, {}/* fload_1 */,
+ {}/* fload_2 */, {}/* fload_3 */, {}/* dload_0 */, {}/* dload_1 */, {}/* dload_2 */, {}/* dload_3 */, {}/* aload_0 */, {}/* aload_1 */, {}/* aload_2 */,
+ {}/* aload_3 */, {}/* iaload */, {}/* laload */, {}/* faload */, {}/* daload */, {}/* aaload */, {}/* baload */, {}/* caload */, {}/* saload */,
+ {T_BYTE}/* istore */, {T_BYTE}/* lstore */, {T_BYTE}/* fstore */, {T_BYTE}/* dstore */, {T_BYTE}/* astore */, {}/* istore_0 */, {}/* istore_1 */,
+ {}/* istore_2 */, {}/* istore_3 */, {}/* lstore_0 */, {}/* lstore_1 */, {}/* lstore_2 */, {}/* lstore_3 */, {}/* fstore_0 */, {}/* fstore_1 */,
+ {}/* fstore_2 */, {}/* fstore_3 */, {}/* dstore_0 */, {}/* dstore_1 */, {}/* dstore_2 */, {}/* dstore_3 */, {}/* astore_0 */, {}/* astore_1 */,
+ {}/* astore_2 */, {}/* astore_3 */, {}/* iastore */, {}/* lastore */, {}/* fastore */, {}/* dastore */, {}/* aastore */, {}/* bastore */,
+ {}/* castore */, {}/* sastore */, {}/* pop */, {}/* pop2 */, {}/* dup */, {}/* dup_x1 */, {}/* dup_x2 */, {}/* dup2 */, {}/* dup2_x1 */,
+ {}/* dup2_x2 */, {}/* swap */, {}/* iadd */, {}/* ladd */, {}/* fadd */, {}/* dadd */, {}/* isub */, {}/* lsub */, {}/* fsub */, {}/* dsub */,
+ {}/* imul */, {}/* lmul */, {}/* fmul */, {}/* dmul */, {}/* idiv */, {}/* ldiv */, {}/* fdiv */, {}/* ddiv */, {}/* irem */, {}/* lrem */,
+ {}/* frem */, {}/* drem */, {}/* ineg */, {}/* lneg */, {}/* fneg */, {}/* dneg */, {}/* ishl */, {}/* lshl */, {}/* ishr */, {}/* lshr */,
+ {}/* iushr */, {}/* lushr */, {}/* iand */, {}/* land */, {}/* ior */, {}/* lor */, {}/* ixor */, {}/* lxor */, {T_BYTE, T_BYTE}/* iinc */, {}/* i2l */,
+ {}/* i2f */, {}/* i2d */, {}/* l2i */, {}/* l2f */, {}/* l2d */, {}/* f2i */, {}/* f2l */, {}/* f2d */, {}/* d2i */, {}/* d2l */, {}/* d2f */,
+ {}/* i2b */, {}/* i2c */, {}/* i2s */, {}/* lcmp */, {}/* fcmpl */, {}/* fcmpg */, {}/* dcmpl */, {}/* dcmpg */, {T_SHORT}/* ifeq */,
+ {T_SHORT}/* ifne */, {T_SHORT}/* iflt */, {T_SHORT}/* ifge */, {T_SHORT}/* ifgt */, {T_SHORT}/* ifle */, {T_SHORT}/* if_icmpeq */,
+ {T_SHORT}/* if_icmpne */, {T_SHORT}/* if_icmplt */, {T_SHORT}/* if_icmpge */, {T_SHORT}/* if_icmpgt */, {T_SHORT}/* if_icmple */,
+ {T_SHORT}/* if_acmpeq */, {T_SHORT}/* if_acmpne */, {T_SHORT}/* goto */, {T_SHORT}/* jsr */, {T_BYTE}/* ret */, {}/* tableswitch */,
+ {}/* lookupswitch */, {}/* ireturn */, {}/* lreturn */, {}/* freturn */, {}/* dreturn */, {}/* areturn */, {}/* return */, {T_SHORT}/* getstatic */,
+ {T_SHORT}/* putstatic */, {T_SHORT}/* getfield */, {T_SHORT}/* putfield */, {T_SHORT}/* invokevirtual */, {T_SHORT}/* invokespecial */,
+ {T_SHORT}/* invokestatic */, {T_SHORT, T_BYTE, T_BYTE}/* invokeinterface */, {T_SHORT, T_BYTE, T_BYTE}/* invokedynamic */, {T_SHORT}/* new */,
+ {T_BYTE}/* newarray */, {T_SHORT}/* anewarray */, {}/* arraylength */, {}/* athrow */, {T_SHORT}/* checkcast */, {T_SHORT}/* instanceof */,
+ {}/* monitorenter */, {}/* monitorexit */, {T_BYTE}/* wide */, {T_SHORT, T_BYTE}/* multianewarray */, {T_SHORT}/* ifnull */, {T_SHORT}/* ifnonnull */,
+ {T_INT}/* goto_w */, {T_INT}/* jsr_w */, {}/* breakpoint */, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
+ {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}/* impdep1 */, {}/* impdep2 */
+ };
+ /**
+ * Names of opcodes. Indexed by opcode. OPCODE_NAMES[ALOAD] = "aload".
+ */
+ static final String[] OPCODE_NAMES = {"nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5",
+ "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload",
+ "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2",
+ "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload",
+ "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1",
+ "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1",
+ "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1",
+ "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv",
+ "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand",
+ "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s",
+ "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge",
+ "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn",
+ "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface",
+ "invokedynamic", "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide",
+ "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
+ ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
+ ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
+ ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
+ ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
+ ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE,
+ ILLEGAL_OPCODE, ILLEGAL_OPCODE, "impdep1", "impdep2"};
+ /**
+ * @since 6.0
+ */
+ public static final int OPCODE_NAMES_LENGTH = OPCODE_NAMES.length;
+ /**
+ * Number of words consumed on operand stack by instructions. Indexed by opcode. CONSUME_STACK[FALOAD] = number of words
+ * consumed from the stack by a faload instruction.
+ */
+ static final int[] CONSUME_STACK = {0/* nop */, 0/* aconst_null */, 0/* iconst_m1 */, 0/* iconst_0 */, 0/* iconst_1 */, 0/* iconst_2 */,
+ 0/* iconst_3 */, 0/* iconst_4 */, 0/* iconst_5 */, 0/* lconst_0 */, 0/* lconst_1 */, 0/* fconst_0 */, 0/* fconst_1 */, 0/* fconst_2 */, 0/* dconst_0 */,
+ 0/* dconst_1 */, 0/* bipush */, 0/* sipush */, 0/* ldc */, 0/* ldc_w */, 0/* ldc2_w */, 0/* iload */, 0/* lload */, 0/* fload */, 0/* dload */,
+ 0/* aload */, 0/* iload_0 */, 0/* iload_1 */, 0/* iload_2 */, 0/* iload_3 */, 0/* lload_0 */, 0/* lload_1 */, 0/* lload_2 */, 0/* lload_3 */,
+ 0/* fload_0 */, 0/* fload_1 */, 0/* fload_2 */, 0/* fload_3 */, 0/* dload_0 */, 0/* dload_1 */, 0/* dload_2 */, 0/* dload_3 */, 0/* aload_0 */,
+ 0/* aload_1 */, 0/* aload_2 */, 0/* aload_3 */, 2/* iaload */, 2/* laload */, 2/* faload */, 2/* daload */, 2/* aaload */, 2/* baload */, 2/* caload */,
+ 2/* saload */, 1/* istore */, 2/* lstore */, 1/* fstore */, 2/* dstore */, 1/* astore */, 1/* istore_0 */, 1/* istore_1 */, 1/* istore_2 */,
+ 1/* istore_3 */, 2/* lstore_0 */, 2/* lstore_1 */, 2/* lstore_2 */, 2/* lstore_3 */, 1/* fstore_0 */, 1/* fstore_1 */, 1/* fstore_2 */, 1/* fstore_3 */,
+ 2/* dstore_0 */, 2/* dstore_1 */, 2/* dstore_2 */, 2/* dstore_3 */, 1/* astore_0 */, 1/* astore_1 */, 1/* astore_2 */, 1/* astore_3 */, 3/* iastore */,
+ 4/* lastore */, 3/* fastore */, 4/* dastore */, 3/* aastore */, 3/* bastore */, 3/* castore */, 3/* sastore */, 1/* pop */, 2/* pop2 */, 1/* dup */,
+ 2/* dup_x1 */, 3/* dup_x2 */, 2/* dup2 */, 3/* dup2_x1 */, 4/* dup2_x2 */, 2/* swap */, 2/* iadd */, 4/* ladd */, 2/* fadd */, 4/* dadd */, 2/* isub */,
+ 4/* lsub */, 2/* fsub */, 4/* dsub */, 2/* imul */, 4/* lmul */, 2/* fmul */, 4/* dmul */, 2/* idiv */, 4/* ldiv */, 2/* fdiv */, 4/* ddiv */,
+ 2/* irem */, 4/* lrem */, 2/* frem */, 4/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 2/* ishl */, 3/* lshl */, 2/* ishr */,
+ 3/* lshr */, 2/* iushr */, 3/* lushr */, 2/* iand */, 4/* land */, 2/* ior */, 4/* lor */, 2/* ixor */, 4/* lxor */, 0/* iinc */, 1/* i2l */,
+ 1/* i2f */, 1/* i2d */, 2/* l2i */, 2/* l2f */, 2/* l2d */, 1/* f2i */, 1/* f2l */, 1/* f2d */, 2/* d2i */, 2/* d2l */, 2/* d2f */, 1/* i2b */,
+ 1/* i2c */, 1/* i2s */, 4/* lcmp */, 2/* fcmpl */, 2/* fcmpg */, 4/* dcmpl */, 4/* dcmpg */, 1/* ifeq */, 1/* ifne */, 1/* iflt */, 1/* ifge */,
+ 1/* ifgt */, 1/* ifle */, 2/* if_icmpeq */, 2/* if_icmpne */, 2/* if_icmplt */, 2 /* if_icmpge */, 2/* if_icmpgt */, 2/* if_icmple */, 2/* if_acmpeq */,
+ 2/* if_acmpne */, 0/* goto */, 0/* jsr */, 0/* ret */, 1/* tableswitch */, 1/* lookupswitch */, 1/* ireturn */, 2/* lreturn */, 1/* freturn */,
+ 2/* dreturn */, 1/* areturn */, 0/* return */, 0/* getstatic */, UNPREDICTABLE/* putstatic */, 1/* getfield */, UNPREDICTABLE/* putfield */,
+ UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */,
+ UNPREDICTABLE/* invokedynamic */, 0/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */,
+ 1/* monitorenter */, 1/* monitorexit */, 0/* wide */, UNPREDICTABLE/* multianewarray */, 1/* ifnull */, 1/* ifnonnull */, 0/* goto_w */, 0/* jsr_w */,
+ 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */
+ };
+ /**
+ * Number of words produced onto operand stack by instructions. Indexed by opcode. CONSUME_STACK[DALOAD] = number of
+ * words consumed from the stack by a daload instruction.
+ */
+ static final int[] PRODUCE_STACK = {0/* nop */, 1/* aconst_null */, 1/* iconst_m1 */, 1/* iconst_0 */, 1/* iconst_1 */, 1/* iconst_2 */,
+ 1/* iconst_3 */, 1/* iconst_4 */, 1/* iconst_5 */, 2/* lconst_0 */, 2/* lconst_1 */, 1/* fconst_0 */, 1/* fconst_1 */, 1/* fconst_2 */, 2/* dconst_0 */,
+ 2/* dconst_1 */, 1/* bipush */, 1/* sipush */, 1/* ldc */, 1/* ldc_w */, 2/* ldc2_w */, 1/* iload */, 2/* lload */, 1/* fload */, 2/* dload */,
+ 1/* aload */, 1/* iload_0 */, 1/* iload_1 */, 1/* iload_2 */, 1/* iload_3 */, 2/* lload_0 */, 2/* lload_1 */, 2/* lload_2 */, 2/* lload_3 */,
+ 1/* fload_0 */, 1/* fload_1 */, 1/* fload_2 */, 1/* fload_3 */, 2/* dload_0 */, 2/* dload_1 */, 2/* dload_2 */, 2/* dload_3 */, 1/* aload_0 */,
+ 1/* aload_1 */, 1/* aload_2 */, 1/* aload_3 */, 1/* iaload */, 2/* laload */, 1/* faload */, 2/* daload */, 1/* aaload */, 1/* baload */, 1/* caload */,
+ 1/* saload */, 0/* istore */, 0/* lstore */, 0/* fstore */, 0/* dstore */, 0/* astore */, 0/* istore_0 */, 0/* istore_1 */, 0/* istore_2 */,
+ 0/* istore_3 */, 0/* lstore_0 */, 0/* lstore_1 */, 0/* lstore_2 */, 0/* lstore_3 */, 0/* fstore_0 */, 0/* fstore_1 */, 0/* fstore_2 */, 0/* fstore_3 */,
+ 0/* dstore_0 */, 0/* dstore_1 */, 0/* dstore_2 */, 0/* dstore_3 */, 0/* astore_0 */, 0/* astore_1 */, 0/* astore_2 */, 0/* astore_3 */, 0/* iastore */,
+ 0/* lastore */, 0/* fastore */, 0/* dastore */, 0/* aastore */, 0/* bastore */, 0/* castore */, 0/* sastore */, 0/* pop */, 0/* pop2 */, 2/* dup */,
+ 3/* dup_x1 */, 4/* dup_x2 */, 4/* dup2 */, 5/* dup2_x1 */, 6/* dup2_x2 */, 2/* swap */, 1/* iadd */, 2/* ladd */, 1/* fadd */, 2/* dadd */, 1/* isub */,
+ 2/* lsub */, 1/* fsub */, 2/* dsub */, 1/* imul */, 2/* lmul */, 1/* fmul */, 2/* dmul */, 1/* idiv */, 2/* ldiv */, 1/* fdiv */, 2/* ddiv */,
+ 1/* irem */, 2/* lrem */, 1/* frem */, 2/* drem */, 1/* ineg */, 2/* lneg */, 1/* fneg */, 2/* dneg */, 1/* ishl */, 2/* lshl */, 1/* ishr */,
+ 2/* lshr */, 1/* iushr */, 2/* lushr */, 1/* iand */, 2/* land */, 1/* ior */, 2/* lor */, 1/* ixor */, 2/* lxor */, 0/* iinc */, 2/* i2l */,
+ 1/* i2f */, 2/* i2d */, 1/* l2i */, 1/* l2f */, 2/* l2d */, 1/* f2i */, 2/* f2l */, 2/* f2d */, 1/* d2i */, 2/* d2l */, 1/* d2f */, 1/* i2b */,
+ 1/* i2c */, 1/* i2s */, 1/* lcmp */, 1/* fcmpl */, 1/* fcmpg */, 1/* dcmpl */, 1/* dcmpg */, 0/* ifeq */, 0/* ifne */, 0/* iflt */, 0/* ifge */,
+ 0/* ifgt */, 0/* ifle */, 0/* if_icmpeq */, 0/* if_icmpne */, 0/* if_icmplt */, 0/* if_icmpge */, 0/* if_icmpgt */, 0/* if_icmple */, 0/* if_acmpeq */,
+ 0/* if_acmpne */, 0/* goto */, 1/* jsr */, 0/* ret */, 0/* tableswitch */, 0/* lookupswitch */, 0/* ireturn */, 0/* lreturn */, 0/* freturn */,
+ 0/* dreturn */, 0/* areturn */, 0/* return */, UNPREDICTABLE/* getstatic */, 0/* putstatic */, UNPREDICTABLE/* getfield */, 0/* putfield */,
+ UNPREDICTABLE/* invokevirtual */, UNPREDICTABLE/* invokespecial */, UNPREDICTABLE/* invokestatic */, UNPREDICTABLE/* invokeinterface */,
+ UNPREDICTABLE/* invokedynamic */, 1/* new */, 1/* newarray */, 1/* anewarray */, 1/* arraylength */, 1/* athrow */, 1/* checkcast */, 1/* instanceof */,
+ 0/* monitorenter */, 0/* monitorexit */, 0/* wide */, 1/* multianewarray */, 0/* ifnull */, 0/* ifnonnull */, 0/* goto_w */, 1/* jsr_w */,
+ 0/* breakpoint */, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
+ UNPREDICTABLE/* impdep1 */, UNPREDICTABLE/* impdep2 */
+ };
+ /**
+ * The names of the access flags.
+ */
+ private static final String[] ACCESS_NAMES = {"public", "private", "protected", "static", "final", "synchronized", "volatile", "transient", "native",
+ "interface", "abstract", "strictfp", "synthetic", "annotation", "enum", "module"};
+ /**
+ * @since 6.0
+ */
+ public static final int ACCESS_NAMES_LENGTH = ACCESS_NAMES.length;
+ /**
+ * The names of the types of entries in a constant pool. Use getConstantName instead
+ */
+ private static final String[] CONSTANT_NAMES = {"", "CONSTANT_Utf8", "", "CONSTANT_Integer", "CONSTANT_Float", "CONSTANT_Long", "CONSTANT_Double",
+ "CONSTANT_Class", "CONSTANT_String", "CONSTANT_Fieldref", "CONSTANT_Methodref", "CONSTANT_InterfaceMethodref", "CONSTANT_NameAndType", "", "",
+ "CONSTANT_MethodHandle", "CONSTANT_MethodType", "CONSTANT_Dynamic", "CONSTANT_InvokeDynamic", "CONSTANT_Module", "CONSTANT_Package"};
+ /**
+ * The names of the interfaces implemented by arrays
+ */
+ private static final String[] INTERFACES_IMPLEMENTED_BY_ARRAYS = {"java.lang.Cloneable", "java.io.Serializable"};
+ /**
+ * The primitive type names corresponding to the T_XX constants, e.g., TYPE_NAMES[T_INT] = "int"
+ */
+ private static final String[] TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "boolean", "char", "float", "double", "byte", "short",
+ "int", "long", "void", "array", "object", "unknown", "address"};
+ /**
+ * The primitive class names corresponding to the T_XX constants, e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer"
+ */
+ private static final String[] CLASS_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "java.lang.Boolean", "java.lang.Character",
+ "java.lang.Float", "java.lang.Double", "java.lang.Byte", "java.lang.Short", "java.lang.Integer", "java.lang.Long", "java.lang.Void", ILLEGAL_TYPE,
+ ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE};
+ /**
+ * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I"
+ */
+ private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V",
+ ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE};
+ private static final String[] ATTRIBUTE_NAMES = {"SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable",
+ "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations",
+ "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod",
+ "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers"};
+ private static final String[] ITEM_NAMES = {"Bogus", "Integer", "Float", "Double", "Long", "Null", "InitObject", "Object", "NewObject"};
/**
* The names of the reference_kinds of a CONSTANT_MethodHandle_info.
*/
private static final String[] METHODHANDLE_NAMES = {"", "getField", "getStatic", "putField", "putStatic", "invokeVirtual", "invokeStatic", "invokeSpecial",
- "newInvokeSpecial", "invokeInterface"};
+ "newInvokeSpecial", "invokeInterface"};
+
+ private Const() {
+ } // not instantiable
/**
* @param index
@@ -3097,7 +2815,6 @@ public final class Const {
}
/**
- *
* @param index
* @return the attribute name
* @since 6.0
@@ -3117,8 +2834,9 @@ public final class Const {
return CLASS_TYPE_NAMES[index];
}
+ // Constants defining the behavior of the Method Handles (JVMS �5.4.3.5)
+
/**
- *
* @param index
* @return the CONSTANT_NAMES entry at the given index
* @since 6.0
@@ -3127,10 +2845,7 @@ public final class Const {
return CONSTANT_NAMES[index];
}
- // Constants defining the behavior of the Method Handles (JVMS �5.4.3.5)
-
/**
- *
* @param index
* @return Number of words consumed on operand stack
* @since 6.0
@@ -3147,7 +2862,6 @@ public final class Const {
}
/**
- *
* @param index
* @return the item name
* @since 6.0
@@ -3157,7 +2871,6 @@ public final class Const {
}
/**
- *
* @param index
* @return the method handle name
* @since 6.0
@@ -3167,7 +2880,6 @@ public final class Const {
}
/**
- *
* @param index
* @return Number of byte code operands
* @since 6.0
@@ -3198,7 +2910,6 @@ public final class Const {
}
/**
- *
* @param index
* @return Number of words produced onto operand stack
* @since 6.0
@@ -3208,7 +2919,6 @@ public final class Const {
}
/**
- *
* @param index
* @return the short type name
* @since 6.0
@@ -3228,7 +2938,4 @@ public final class Const {
return TYPE_NAMES[index];
}
- private Const() {
- } // not instantiable
-
}
diff --git a/src/main/java/haidnor/jvm/bcel/ExceptionConst.java b/src/main/java/haidnor/jvm/bcel/ExceptionConst.java
index e9a96df..ba3b4d8 100644
--- a/src/main/java/haidnor/jvm/bcel/ExceptionConst.java
+++ b/src/main/java/haidnor/jvm/bcel/ExceptionConst.java
@@ -25,24 +25,14 @@ import org.apache.commons.lang3.ArrayUtils;
*/
public final class ExceptionConst {
- /**
- * Enum corresponding to the various Exception Class arrays, used by
- * {@link ExceptionConst#createExceptions(EXCS, Class...)}
- */
- public enum EXCS {
- EXCS_CLASS_AND_INTERFACE_RESOLUTION, EXCS_FIELD_AND_METHOD_RESOLUTION, EXCS_INTERFACE_METHOD_RESOLUTION, EXCS_STRING_RESOLUTION, EXCS_ARRAY_EXCEPTION,
- }
-
/**
* The mother of all exceptions
*/
public static final Class THROWABLE = Throwable.class;
-
/**
* Super class of any run-time exception
*/
public static final Class RUNTIME_EXCEPTION = RuntimeException.class;
-
/**
* Super class of any linking exception (aka Linkage Error)
*/
@@ -61,62 +51,56 @@ public final class ExceptionConst {
public static final Class NO_SUCH_METHOD_ERROR = NoSuchMethodError.class;
public static final Class NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class;
public static final Class UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class;
-
public static final Class VERIFY_ERROR = VerifyError.class;
- /* UnsupportedClassVersionError is new in JDK 1.2 */
-// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class;
/**
* Run-Time Exceptions
*/
public static final Class NULL_POINTER_EXCEPTION = NullPointerException.class;
+ /* UnsupportedClassVersionError is new in JDK 1.2 */
+// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class;
public static final Class ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = ArrayIndexOutOfBoundsException.class;
public static final Class ARITHMETIC_EXCEPTION = ArithmeticException.class;
public static final Class NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class;
public static final Class CLASS_CAST_EXCEPTION = ClassCastException.class;
-
public static final Class ILLEGAL_MONITOR_STATE = IllegalMonitorStateException.class;
/**
* Pre-defined exception arrays according to chapters 5.1-5.4 of the Java Virtual Machine Specification
*/
private static final Class>[] EXCS_CLASS_AND_INTERFACE_RESOLUTION = {NO_CLASS_DEF_FOUND_ERROR, CLASS_FORMAT_ERROR, VERIFY_ERROR, ABSTRACT_METHOD_ERROR,
- EXCEPTION_IN_INITIALIZER_ERROR, ILLEGAL_ACCESS_ERROR}; // Chapter 5.1
-
+ EXCEPTION_IN_INITIALIZER_ERROR, ILLEGAL_ACCESS_ERROR}; // Chapter 5.1
private static final Class>[] EXCS_FIELD_AND_METHOD_RESOLUTION = {NO_SUCH_FIELD_ERROR, ILLEGAL_ACCESS_ERROR, NO_SUCH_METHOD_ERROR}; // Chapter 5.2
-
/**
* Empty array.
*/
private static final Class>[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class[0]; // Chapter 5.3 (as below)
-
/**
* Empty array.
*/
private static final Class>[] EXCS_STRING_RESOLUTION = new Class[0];
-
// Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.)
private static final Class>[] EXCS_ARRAY_EXCEPTION = {NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION};
/**
* Creates a copy of the specified Exception Class array combined with any additional Exception classes.
*
- * @param type the basic array type
+ * @param type the basic array type
* @param extraClasses additional classes, if any
* @return the merged array
*/
public static Class>[] createExceptions(final EXCS type, final Class>... extraClasses) {
switch (type) {
- case EXCS_CLASS_AND_INTERFACE_RESOLUTION:
- return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses);
- case EXCS_ARRAY_EXCEPTION:
- return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses);
- case EXCS_FIELD_AND_METHOD_RESOLUTION:
- return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses);
- case EXCS_INTERFACE_METHOD_RESOLUTION:
- return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses);
- case EXCS_STRING_RESOLUTION:
- return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses);
- default:
- throw new AssertionError("Cannot happen; unexpected enum value: " + type);
+ case EXCS_CLASS_AND_INTERFACE_RESOLUTION:
+ return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses);
+ case EXCS_ARRAY_EXCEPTION:
+ return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses);
+ case EXCS_FIELD_AND_METHOD_RESOLUTION:
+ return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses);
+ case EXCS_INTERFACE_METHOD_RESOLUTION:
+ return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses);
+ case EXCS_STRING_RESOLUTION:
+ return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses);
+ default:
+ throw new AssertionError("Cannot happen; unexpected enum value: " + type);
}
}
@@ -125,4 +109,12 @@ public final class ExceptionConst {
return ArrayUtils.addAll(input, extraClasses);
}
+ /**
+ * Enum corresponding to the various Exception Class arrays, used by
+ * {@link ExceptionConst#createExceptions(EXCS, Class...)}
+ */
+ public enum EXCS {
+ EXCS_CLASS_AND_INTERFACE_RESOLUTION, EXCS_FIELD_AND_METHOD_RESOLUTION, EXCS_INTERFACE_METHOD_RESOLUTION, EXCS_STRING_RESOLUTION, EXCS_ARRAY_EXCEPTION,
+ }
+
}
diff --git a/src/main/java/haidnor/jvm/bcel/Repository.java b/src/main/java/haidnor/jvm/bcel/Repository.java
index b05600d..881fbf5 100644
--- a/src/main/java/haidnor/jvm/bcel/Repository.java
+++ b/src/main/java/haidnor/jvm/bcel/Repository.java
@@ -53,7 +53,7 @@ public abstract class Repository {
/**
* @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend,
- * and so on. (Some people call this a transitive hull).
+ * and so on. (Some people call this a transitive hull).
* @throws ClassNotFoundException if any of the class's superclasses or superinterfaces can't be found
*/
public static JavaClass[] getInterfaces(final JavaClass clazz) throws ClassNotFoundException {
@@ -62,9 +62,9 @@ public abstract class Repository {
/**
* @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces,
- * and so on
+ * and so on
* @throws ClassNotFoundException if the named class can't be found, or if any of its superclasses or superinterfaces
- * can't be found
+ * can't be found
*/
public static JavaClass[] getInterfaces(final String className) throws ClassNotFoundException {
return getInterfaces(lookupClass(className));
@@ -77,6 +77,13 @@ public abstract class Repository {
return repository;
}
+ /**
+ * Sets repository instance to be used for class loading
+ */
+ public static void setRepository(final haidnor.jvm.bcel.util.Repository rep) {
+ repository = rep;
+ }
+
/**
* @return list of super classes of clazz in ascending order, i.e., Object is always the last element
* @throws ClassNotFoundException if any of the superclasses can't be found
@@ -162,9 +169,9 @@ public abstract class Repository {
/**
* Tries to find class source using the internal repository instance.
*
- * @see Class
* @return JavaClass object for given runtime class
* @throws ClassNotFoundException if the class could not be found or parsed correctly
+ * @see Class
*/
public static JavaClass lookupClass(final Class> clazz) throws ClassNotFoundException {
return repository.loadClass(clazz);
@@ -182,7 +189,7 @@ public abstract class Repository {
/**
* @return class file object for given Java class by looking on the system class path; returns null if the class file
- * can't be found
+ * can't be found
*/
public static ClassPath.ClassFile lookupClassFile(final String className) {
try (ClassPath path = repository.getClassPath()) {
@@ -205,11 +212,4 @@ public abstract class Repository {
public static void removeClass(final String clazz) {
repository.removeClass(repository.findClass(clazz));
}
-
- /**
- * Sets repository instance to be used for class loading
- */
- public static void setRepository(final haidnor.jvm.bcel.util.Repository rep) {
- repository = rep;
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java b/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java
index a631ad5..2e74ec6 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/AccessFlags.java
@@ -46,6 +46,15 @@ public abstract class AccessFlags {
return access_flags;
}
+ /**
+ * Set access flags aka "modifiers".
+ *
+ * @param accessFlags Access flags of the object.
+ */
+ public final void setAccessFlags(final int accessFlags) {
+ this.access_flags = accessFlags;
+ }
+
/**
* @return Access flags of the object aka. "modifiers".
*/
@@ -53,6 +62,15 @@ public abstract class AccessFlags {
return access_flags;
}
+ /**
+ * Set access flags aka "modifiers".
+ *
+ * @param accessFlags Access flags of the object.
+ */
+ public final void setModifiers(final int accessFlags) {
+ setAccessFlags(accessFlags);
+ }
+
public final boolean isAbstract() {
return (access_flags & Const.ACC_ABSTRACT) != 0;
}
@@ -181,15 +199,6 @@ public abstract class AccessFlags {
setFlag(Const.ACC_VOLATILE, flag);
}
- /**
- * Set access flags aka "modifiers".
- *
- * @param accessFlags Access flags of the object.
- */
- public final void setAccessFlags(final int accessFlags) {
- this.access_flags = accessFlags;
- }
-
private void setFlag(final int flag, final boolean set) {
if ((access_flags & flag) != 0) { // Flag is set already
if (!set) {
@@ -199,13 +208,4 @@ public abstract class AccessFlags {
access_flags |= flag;
}
}
-
- /**
- * Set access flags aka "modifiers".
- *
- * @param accessFlags Access flags of the object.
- */
- public final void setModifiers(final int accessFlags) {
- setAccessFlags(accessFlags);
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java
index c28cb33..7a9f590 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationDefault.java
@@ -33,9 +33,9 @@ public class AnnotationDefault extends Attribute {
private ElementValue defaultValue;
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
*/
AnnotationDefault(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
@@ -44,8 +44,8 @@ public class AnnotationDefault extends Attribute {
}
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
* @param defaultValue the annotation's default value
* @param constantPool Array of constants
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java
index f2776ac..c325942 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/AnnotationEntry.java
@@ -31,11 +31,21 @@ import java.util.stream.Stream;
public class AnnotationEntry implements Node {
public static final AnnotationEntry[] EMPTY_ARRAY = {};
+ private final int typeIndex;
+ private final ConstantPool constantPool;
+ private final boolean isRuntimeVisible;
+ private List elementValuePairs;
+
+ public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) {
+ this.typeIndex = typeIndex;
+ this.constantPool = constantPool;
+ this.isRuntimeVisible = isRuntimeVisible;
+ }
public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) {
// Find attributes that contain annotation data
return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
- .toArray(AnnotationEntry[]::new);
+ .toArray(AnnotationEntry[]::new);
}
/**
@@ -53,25 +63,11 @@ public class AnnotationEntry implements Node {
annotationEntry.elementValuePairs = new ArrayList<>();
for (int i = 0; i < numElementValuePairs; i++) {
annotationEntry.elementValuePairs
- .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
+ .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
}
return annotationEntry;
}
- private final int typeIndex;
-
- private final ConstantPool constantPool;
-
- private final boolean isRuntimeVisible;
-
- private List elementValuePairs;
-
- public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) {
- this.typeIndex = typeIndex;
- this.constantPool = constantPool;
- this.isRuntimeVisible = isRuntimeVisible;
- }
-
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java b/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java
index a2fe3c4..27eec58 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Annotations.java
@@ -31,8 +31,8 @@ import java.util.stream.Stream;
*/
public abstract class Annotations extends Attribute implements Iterable {
- private AnnotationEntry[] annotationTable;
private final boolean isRuntimeVisible;
+ private AnnotationEntry[] annotationTable;
/**
* Constructs an instance.
@@ -45,7 +45,7 @@ public abstract class Annotations extends Attribute implements Iterable READERS = new HashMap<>();
-
/**
* Empty array.
*
* @since 6.6.0
*/
public static final Attribute[] EMPTY_ARRAY = {};
+ private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off
+ private static final Map READERS = new HashMap<>();
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @java.lang.Deprecated
+ protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter)
+ /**
+ * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @java.lang.Deprecated
+ protected int length; // Content length of attribute field TODO make private (has getter & setter)
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @java.lang.Deprecated
+ protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @java.lang.Deprecated
+ protected ConstantPool constant_pool; // TODO make private (has getter & setter)
+
+ /**
+ * Constructs an instance.
+ *
+ *
+ * attribute_info {
+ * u2 attribute_name_index;
+ * u4 attribute_length;
+ * u1 info[attribute_length];
+ * }
+ *
+ *
+ * @param tag tag.
+ * @param nameIndex u2 name index.
+ * @param length u4 length.
+ * @param constantPool constant pool.
+ */
+ protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) {
+ this.tag = tag;
+ this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index");
+ this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length");
+ this.constant_pool = constantPool;
+ }
/**
* Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the
* standard attributes such as "LineNumberTable", because those are handled internally.
*
- * @param name the name of the attribute as stored in the class file
+ * @param name the name of the attribute as stored in the class file
* @param unknownAttributeReader the reader object
*/
public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
@@ -85,13 +126,12 @@ public abstract class Attribute implements Cloneable, Node {
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
* is called by the Field and Method constructor methods.
*
- * @see JavaField
- * @see JavaMethod
- *
- * @param dataInput Input stream
+ * @param dataInput Input stream
* @param constantPool Array of constants
* @return Attribute
* @throws IOException if an I/O error occurs.
+ * @see JavaField
+ * @see JavaMethod
* @since 6.0
*/
public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
@@ -113,74 +153,74 @@ public abstract class Attribute implements Cloneable, Node {
// Call proper constructor, depending on 'tag'
switch (tag) {
- case Const.ATTR_UNKNOWN:
- final Object r = READERS.get(name);
- if (r instanceof UnknownAttributeReader) {
- return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
- }
- return new Unknown(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_CONSTANT_VALUE:
- return new ConstantValue(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_SOURCE_FILE:
- return new SourceFile(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_CODE:
- return new Code(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_EXCEPTIONS:
- return new ExceptionTable(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_LINE_NUMBER_TABLE:
- return new LineNumberTable(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_LOCAL_VARIABLE_TABLE:
- return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_INNER_CLASSES:
- return new InnerClasses(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_SYNTHETIC:
- return new Synthetic(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_DEPRECATED:
- return new Deprecated(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_PMG:
- return new PMGClass(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_SIGNATURE:
- return new Signature(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_STACK_MAP:
- // old style stack map: unneeded for JDK5 and below;
- // illegal(?) for JDK6 and above. So just delete with a warning.
- println("Warning: Obsolete StackMap attribute ignored.");
- return new Unknown(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
- return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
- return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
- return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
- return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_ANNOTATION_DEFAULT:
- return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
- return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_ENCLOSING_METHOD:
- return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_STACK_MAP_TABLE:
- // read new style stack map: StackMapTable. The rest of the code
- // calls this a StackMap for historical reasons.
- return new StackMap(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_BOOTSTRAP_METHODS:
- return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_METHOD_PARAMETERS:
- return new MethodParameters(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_MODULE:
- return new Module(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_MODULE_PACKAGES:
- return new ModulePackages(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_MODULE_MAIN_CLASS:
- return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_NEST_HOST:
- return new NestHost(nameIndex, length, dataInput, constantPool);
- case Const.ATTR_NEST_MEMBERS:
- return new NestMembers(nameIndex, length, dataInput, constantPool);
- default:
- // Never reached
- throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
+ case Const.ATTR_UNKNOWN:
+ final Object r = READERS.get(name);
+ if (r instanceof UnknownAttributeReader) {
+ return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
+ }
+ return new Unknown(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_CONSTANT_VALUE:
+ return new ConstantValue(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_SOURCE_FILE:
+ return new SourceFile(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_CODE:
+ return new Code(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_EXCEPTIONS:
+ return new ExceptionTable(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_LINE_NUMBER_TABLE:
+ return new LineNumberTable(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_LOCAL_VARIABLE_TABLE:
+ return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_INNER_CLASSES:
+ return new InnerClasses(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_SYNTHETIC:
+ return new Synthetic(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_DEPRECATED:
+ return new Deprecated(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_PMG:
+ return new PMGClass(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_SIGNATURE:
+ return new Signature(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_STACK_MAP:
+ // old style stack map: unneeded for JDK5 and below;
+ // illegal(?) for JDK6 and above. So just delete with a warning.
+ println("Warning: Obsolete StackMap attribute ignored.");
+ return new Unknown(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
+ return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
+ return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
+ return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
+ return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_ANNOTATION_DEFAULT:
+ return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
+ return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_ENCLOSING_METHOD:
+ return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_STACK_MAP_TABLE:
+ // read new style stack map: StackMapTable. The rest of the code
+ // calls this a StackMap for historical reasons.
+ return new StackMap(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_BOOTSTRAP_METHODS:
+ return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_METHOD_PARAMETERS:
+ return new MethodParameters(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_MODULE:
+ return new Module(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_MODULE_PACKAGES:
+ return new ModulePackages(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_MODULE_MAIN_CLASS:
+ return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_NEST_HOST:
+ return new NestHost(nameIndex, length, dataInput, constantPool);
+ case Const.ATTR_NEST_MEMBERS:
+ return new NestMembers(nameIndex, length, dataInput, constantPool);
+ default:
+ // Never reached
+ throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
}
}
@@ -188,13 +228,12 @@ public abstract class Attribute implements Cloneable, Node {
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
* is called by the Field and Method constructor methods.
*
- * @see JavaField
- * @see JavaMethod
- *
* @param dataInputStream Input stream
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
* @return Attribute
* @throws IOException if an I/O error occurs.
+ * @see JavaField
+ * @see JavaMethod
*/
public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
return readAttribute((DataInput) dataInputStream, constantPool);
@@ -209,53 +248,6 @@ public abstract class Attribute implements Cloneable, Node {
READERS.remove(name);
}
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @java.lang.Deprecated
- protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter)
-
- /**
- * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @java.lang.Deprecated
- protected int length; // Content length of attribute field TODO make private (has getter & setter)
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @java.lang.Deprecated
- protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @java.lang.Deprecated
- protected ConstantPool constant_pool; // TODO make private (has getter & setter)
-
- /**
- * Constructs an instance.
- *
- *
- * attribute_info {
- * u2 attribute_name_index;
- * u4 attribute_length;
- * u1 info[attribute_length];
- * }
- *
- *
- * @param tag tag.
- * @param nameIndex u2 name index.
- * @param length u4 length.
- * @param constantPool constant pool.
- */
- protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) {
- this.tag = tag;
- this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index");
- this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length");
- this.constant_pool = constantPool;
- }
-
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
@@ -306,6 +298,14 @@ public abstract class Attribute implements Cloneable, Node {
return constant_pool;
}
+ /**
+ * @param constantPool Constant pool to be used for this object.
+ * @see ConstantPool
+ */
+ public final void setConstantPool(final ConstantPool constantPool) {
+ this.constant_pool = constantPool;
+ }
+
/**
* @return Length of attribute field in bytes.
*/
@@ -313,6 +313,13 @@ public abstract class Attribute implements Cloneable, Node {
return length;
}
+ /**
+ * @param length length in bytes.
+ */
+ public final void setLength(final int length) {
+ this.length = length;
+ }
+
/**
* @return Name of attribute
* @since 6.0
@@ -328,28 +335,6 @@ public abstract class Attribute implements Cloneable, Node {
return name_index;
}
- /**
- * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method.
- */
- public final byte getTag() {
- return tag;
- }
-
- /**
- * @param constantPool Constant pool to be used for this object.
- * @see ConstantPool
- */
- public final void setConstantPool(final ConstantPool constantPool) {
- this.constant_pool = constantPool;
- }
-
- /**
- * @param length length in bytes.
- */
- public final void setLength(final int length) {
- this.length = length;
- }
-
/**
* @param nameIndex of attribute.
*/
@@ -357,6 +342,13 @@ public abstract class Attribute implements Cloneable, Node {
this.name_index = nameIndex;
}
+ /**
+ * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method.
+ */
+ public final byte getTag() {
+ return tag;
+ }
+
/**
* @return attribute name.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java
index d310548..9c8761e 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethod.java
@@ -29,15 +29,19 @@ import java.util.Arrays;
* and an array of the bootstrap arguments.
*
* @see The class File Format :
- * The BootstrapMethods Attribute
+ * The BootstrapMethods Attribute
* @since 6.0
*/
public class BootstrapMethod implements Cloneable {
- /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
+ /**
+ * Index of the CONSTANT_MethodHandle_info structure in the constant_pool table
+ */
private int bootstrapMethodRef;
- /** Array of references to the constant_pool table */
+ /**
+ * Array of references to the constant_pool table
+ */
private int[] bootstrapArguments;
/**
@@ -110,20 +114,6 @@ public class BootstrapMethod implements Cloneable {
return bootstrapArguments;
}
- /**
- * @return index into constant_pool of bootstrap_method
- */
- public int getBootstrapMethodRef() {
- return bootstrapMethodRef;
- }
-
- /**
- * @return count of number of boostrap arguments
- */
- public int getNumBootstrapArguments() {
- return bootstrapArguments.length;
- }
-
/**
* @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
*/
@@ -131,6 +121,13 @@ public class BootstrapMethod implements Cloneable {
this.bootstrapArguments = bootstrapArguments;
}
+ /**
+ * @return index into constant_pool of bootstrap_method
+ */
+ public int getBootstrapMethodRef() {
+ return bootstrapMethodRef;
+ }
+
/**
* @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
*/
@@ -138,6 +135,13 @@ public class BootstrapMethod implements Cloneable {
this.bootstrapMethodRef = bootstrapMethodRef;
}
+ /**
+ * @return count of number of boostrap arguments
+ */
+ public int getNumBootstrapArguments() {
+ return bootstrapArguments.length;
+ }
+
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java
index fa94a19..3cda9eb 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/BootstrapMethods.java
@@ -29,7 +29,7 @@ import java.util.stream.Stream;
* This class represents a BootstrapMethods attribute.
*
* @see The class File Format :
- * The BootstrapMethods Attribute
+ * The BootstrapMethods Attribute
* @since 6.0
*/
public class BootstrapMethods extends Attribute implements Iterable {
@@ -47,10 +47,10 @@ public class BootstrapMethods extends Attribute implements Iterable iterator() {
- return Stream.of(bootstrapMethods).iterator();
- }
-
/**
* @param bootstrapMethods the array of bootstrap methods
*/
@@ -134,6 +129,11 @@ public class BootstrapMethods extends Attribute implements Iterable iterator() {
+ return Stream.of(bootstrapMethods).iterator();
+ }
+
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java b/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java
index e1b7cc3..5b7fb1e 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ClassParser.java
@@ -26,7 +26,7 @@ import java.util.zip.ZipFile;
* Wrapper class that parses a given Java .class file. The method parse returns a
* JavaClass object on success. When an I/O error or an inconsistency occurs an
* appropriate exception is propagated back to the caller.
- *
+ *
* The structure and the names comply, except for a few conveniences, exactly with the
* JVM specification 1.0 . See this paper for further details about
* the structure of a bytecode file.
@@ -34,9 +34,10 @@ import java.util.zip.ZipFile;
public final class ClassParser {
private static final int BUFSIZE = 8192;
- private DataInputStream dataInputStream;
private final boolean fileOwned;
private final String fileName;
+ private final boolean isZip; // Loaded from zip file
+ private DataInputStream dataInputStream;
private String zipFile;
private int classNameIndex;
private int superclassNameIndex;
@@ -48,13 +49,12 @@ public final class ClassParser {
private JavaField[] fields; // class fields, i.e., its variables
private JavaMethod[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class
- private final boolean isZip; // Loaded from zip file
/**
* Parses class from the given stream.
*
* @param inputStream Input stream
- * @param fileName File name
+ * @param fileName File name
*/
public ClassParser(final InputStream inputStream, final String fileName) {
this.fileName = fileName;
@@ -82,7 +82,7 @@ public final class ClassParser {
/**
* Parses class from given .class file in a ZIP-archive
*
- * @param zipFile zip file name
+ * @param zipFile zip file name
* @param fileName file name
*/
public ClassParser(final String zipFile, final String fileName) {
@@ -98,7 +98,7 @@ public final class ClassParser {
* not include verification of the byte code as it is performed by the java interpreter).
*
* @return Class object representing the parsed class file
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
public JavaClass parse() throws IOException, ClassFormatException {
@@ -172,13 +172,13 @@ public final class ClassParser {
}
// Return the information we have gathered in a new object
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes,
- isZip ? JavaClass.ZIP : JavaClass.FILE);
+ isZip ? JavaClass.ZIP : JavaClass.FILE);
}
/**
* Reads information about the attributes of the class.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readAttributes() throws IOException, ClassFormatException {
@@ -192,7 +192,7 @@ public final class ClassParser {
/**
* Reads information about the class and its super class.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readClassInfo() throws IOException, ClassFormatException {
@@ -213,7 +213,7 @@ public final class ClassParser {
/**
* Reads constant pool entries.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readConstantPool() throws IOException, ClassFormatException {
@@ -223,7 +223,7 @@ public final class ClassParser {
/**
* Reads information about the fields of the class, i.e., its variables.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readFields() throws IOException, ClassFormatException {
@@ -238,7 +238,7 @@ public final class ClassParser {
/**
* Checks whether the header of the file is ok. Of course, this has to be the first action on successive file reads.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readID() throws IOException, ClassFormatException {
@@ -250,7 +250,7 @@ public final class ClassParser {
/**
* Reads information about the interfaces implemented by this class.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readInterfaces() throws IOException, ClassFormatException {
@@ -264,7 +264,7 @@ public final class ClassParser {
/**
* Reads information about the methods of the class.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readMethods() throws IOException {
@@ -278,7 +278,7 @@ public final class ClassParser {
/**
* Reads major and minor version of compiler which created the file.
*
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readVersion() throws IOException, ClassFormatException {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Code.java b/src/main/java/haidnor/jvm/bcel/classfile/Code.java
index ef0d913..7df31f1 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Code.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Code.java
@@ -29,7 +29,7 @@ import java.util.Arrays;
* This class represents a chunk of Java byte code contained in a method. It is instantiated by the
* Attribute.readAttribute() method. A Code attribute contains informations about operand stack, local
* variables, byte code and the exceptions handled within this method.
- *
+ *
* This attribute has attributes itself, namely LineNumberTable which is used for debugging purposes and
* LocalVariableTable which contains information about the local variables.
*
@@ -52,6 +52,7 @@ import java.util.Arrays;
* attribute_info attributes[attributes_count];
* }
*
+ *
* @see Attribute
* @see CodeException
* @see LineNumberTable
@@ -77,9 +78,9 @@ public final class Code extends Attribute {
}
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param file Input stream
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param file Input stream
* @param constantPool Array of constants
*/
Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException {
@@ -113,17 +114,17 @@ public final class Code extends Attribute {
}
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param maxStack Maximum size of stack
- * @param maxLocals Number of local variables
- * @param code Actual byte code
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param maxStack Maximum size of stack
+ * @param maxLocals Number of local variables
+ * @param code Actual byte code
* @param exceptionTable of handled exceptions
- * @param attributes Attributes of code: LineNumber or LocalVariable
- * @param constantPool Array of constants
+ * @param attributes Attributes of code: LineNumber or LocalVariable
+ * @param constantPool Array of constants
*/
public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
- final Attribute[] attributes, final ConstantPool constantPool) {
+ final Attribute[] attributes, final ConstantPool constantPool) {
super(Const.ATTR_CODE, nameIndex, length, constantPool);
this.maxStack = Args.requireU2(maxStack, "maxStack");
this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
@@ -147,7 +148,7 @@ public final class Code extends Attribute {
/**
* @return the full size of this code attribute, minus its first 6 bytes, including the size of all its contained
- * attributes
+ * attributes
*/
private int calculateLength() {
int len = 0;
@@ -160,9 +161,8 @@ public final class Code extends Attribute {
}
/**
- * @return deep copy of this attribute
- *
* @param constantPool the constant pool to duplicate
+ * @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
@@ -209,6 +209,14 @@ public final class Code extends Attribute {
return attributes;
}
+ /**
+ * @param attributes the attributes to set for this Code
+ */
+ public void setAttributes(final Attribute[] attributes) {
+ this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
+ super.setLength(calculateLength()); // Adjust length
+ }
+
/**
* @return Actual byte code of the method.
*/
@@ -216,6 +224,14 @@ public final class Code extends Attribute {
return code;
}
+ /**
+ * @param code byte code
+ */
+ public void setCode(final byte[] code) {
+ this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY;
+ super.setLength(calculateLength()); // Adjust length
+ }
+
/**
* @return Table of handled exceptions.
* @see CodeException
@@ -224,15 +240,23 @@ public final class Code extends Attribute {
return exceptionTable;
}
+ /**
+ * @param exceptionTable exception table
+ */
+ public void setExceptionTable(final CodeException[] exceptionTable) {
+ this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
+ super.setLength(calculateLength()); // Adjust length
+ }
+
/**
* @return the internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes
*/
private int getInternalLength() {
return 2 /* maxStack */ + 2 /* maxLocals */ + 4 /* code length */
- + code.length /* byte-code */
- + 2 /* exception-table length */
- + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
- + 2 /* attributes count */;
+ + code.length /* byte-code */
+ + 2 /* exception-table length */
+ + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
+ + 2 /* attributes count */;
}
/**
@@ -266,37 +290,6 @@ public final class Code extends Attribute {
return maxLocals;
}
- /**
- * @return Maximum size of stack used by this method.
- */
- public int getMaxStack() {
- return maxStack;
- }
-
- /**
- * @param attributes the attributes to set for this Code
- */
- public void setAttributes(final Attribute[] attributes) {
- this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
- super.setLength(calculateLength()); // Adjust length
- }
-
- /**
- * @param code byte code
- */
- public void setCode(final byte[] code) {
- this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY;
- super.setLength(calculateLength()); // Adjust length
- }
-
- /**
- * @param exceptionTable exception table
- */
- public void setExceptionTable(final CodeException[] exceptionTable) {
- this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
- super.setLength(calculateLength()); // Adjust length
- }
-
/**
* @param maxLocals maximum number of local variables
*/
@@ -304,6 +297,13 @@ public final class Code extends Attribute {
this.maxLocals = maxLocals;
}
+ /**
+ * @return Maximum size of stack used by this method.
+ */
+ public int getMaxStack() {
+ return maxStack;
+ }
+
/**
* @param maxStack maximum stack size
*/
@@ -328,7 +328,7 @@ public final class Code extends Attribute {
public String toString(final boolean verbose) {
final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber
buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n")
- .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
+ .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
if (exceptionTable.length > 0) {
buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
for (final CodeException exception : exceptionTable) {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java b/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java
index 2588343..e8e9fde 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/CodeException.java
@@ -154,27 +154,6 @@ public final class CodeException implements Cloneable, Node {
return catchType;
}
- /**
- * @return Exclusive end index of the region where the handler is active.
- */
- public int getEndPC() {
- return endPc;
- }
-
- /**
- * @return Starting address of exception handler, relative to the code.
- */
- public int getHandlerPC() {
- return handlerPc;
- }
-
- /**
- * @return Inclusive start index of the region where the handler is active.
- */
- public int getStartPC() {
- return startPc;
- }
-
/**
* @param catchType the type of exception that is caught
*/
@@ -182,6 +161,13 @@ public final class CodeException implements Cloneable, Node {
this.catchType = catchType;
}
+ /**
+ * @return Exclusive end index of the region where the handler is active.
+ */
+ public int getEndPC() {
+ return endPc;
+ }
+
/**
* @param endPc end of handled block
*/
@@ -189,6 +175,13 @@ public final class CodeException implements Cloneable, Node {
this.endPc = endPc;
}
+ /**
+ * @return Starting address of exception handler, relative to the code.
+ */
+ public int getHandlerPC() {
+ return handlerPc;
+ }
+
/**
* @param handlerPc where the actual code is
*/
@@ -196,6 +189,13 @@ public final class CodeException implements Cloneable, Node {
this.handlerPc = handlerPc;
}
+ /**
+ * @return Inclusive start index of the region where the handler is active.
+ */
+ public int getStartPC() {
+ return startPc;
+ }
+
/**
* @param startPc start of handled block
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Constant.java b/src/main/java/haidnor/jvm/bcel/classfile/Constant.java
index bb899b5..41baeab 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Constant.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Constant.java
@@ -45,6 +45,15 @@ public abstract class Constant implements Cloneable, Node {
return THIS.toString().hashCode();
}
};
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @java.lang.Deprecated
+ protected byte tag; // TODO should be private & final
+
+ Constant(final byte tag) {
+ this.tag = tag;
+ }
/**
* @return Comparison strategy object
@@ -53,64 +62,6 @@ public abstract class Constant implements Cloneable, Node {
return bcelComparator;
}
- /**
- * Reads one constant from the given input, the type depends on a tag byte.
- *
- * @param dataInput Input stream
- * @return Constant object
- * @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
- * @throws ClassFormatException if the next byte is not recognized
- * @since 6.0 made public
- */
- public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
- final byte b = dataInput.readByte(); // Read tag byte
- switch (b) {
- case Const.CONSTANT_Class:
- return new ConstantClass(dataInput);
- case Const.CONSTANT_Fieldref:
- return new ConstantFieldref(dataInput);
- case Const.CONSTANT_Methodref:
- return new ConstantMethodref(dataInput);
- case Const.CONSTANT_InterfaceMethodref:
- return new ConstantInterfaceMethodref(dataInput);
- case Const.CONSTANT_String:
- return new ConstantString(dataInput);
- case Const.CONSTANT_Integer:
- return new ConstantInteger(dataInput);
- case Const.CONSTANT_Float:
- return new ConstantFloat(dataInput);
- case Const.CONSTANT_Long:
- return new ConstantLong(dataInput);
- case Const.CONSTANT_Double:
- return new ConstantDouble(dataInput);
- case Const.CONSTANT_NameAndType:
- return new ConstantNameAndType(dataInput);
- case Const.CONSTANT_Utf8:
- return ConstantUtf8.getInstance(dataInput);
- case Const.CONSTANT_MethodHandle:
- return new ConstantMethodHandle(dataInput);
- case Const.CONSTANT_MethodType:
- return new ConstantMethodType(dataInput);
- case Const.CONSTANT_Dynamic:
- return new ConstantDynamic(dataInput);
- case Const.CONSTANT_InvokeDynamic:
- return new ConstantInvokeDynamic(dataInput);
- case Const.CONSTANT_Module:
- return new ConstantModule(dataInput);
- case Const.CONSTANT_Package:
- return new ConstantPackage(dataInput);
- default:
- throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
- }
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
-
/*
* In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, i.e., via
* 'instanceof'. In some places we will use the tag for switch()es anyway.
@@ -118,14 +69,63 @@ public abstract class Constant implements Cloneable, Node {
* First, we want match the specification as closely as possible. Second we need the tag as an index to select the
* corresponding class name from the 'CONSTANT_NAMES' array.
*/
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @java.lang.Deprecated
- protected byte tag; // TODO should be private & final
- Constant(final byte tag) {
- this.tag = tag;
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
+ /**
+ * Reads one constant from the given input, the type depends on a tag byte.
+ *
+ * @param dataInput Input stream
+ * @return Constant object
+ * @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
+ * @throws ClassFormatException if the next byte is not recognized
+ * @since 6.0 made public
+ */
+ public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
+ final byte b = dataInput.readByte(); // Read tag byte
+ switch (b) {
+ case Const.CONSTANT_Class:
+ return new ConstantClass(dataInput);
+ case Const.CONSTANT_Fieldref:
+ return new ConstantFieldref(dataInput);
+ case Const.CONSTANT_Methodref:
+ return new ConstantMethodref(dataInput);
+ case Const.CONSTANT_InterfaceMethodref:
+ return new ConstantInterfaceMethodref(dataInput);
+ case Const.CONSTANT_String:
+ return new ConstantString(dataInput);
+ case Const.CONSTANT_Integer:
+ return new ConstantInteger(dataInput);
+ case Const.CONSTANT_Float:
+ return new ConstantFloat(dataInput);
+ case Const.CONSTANT_Long:
+ return new ConstantLong(dataInput);
+ case Const.CONSTANT_Double:
+ return new ConstantDouble(dataInput);
+ case Const.CONSTANT_NameAndType:
+ return new ConstantNameAndType(dataInput);
+ case Const.CONSTANT_Utf8:
+ return ConstantUtf8.getInstance(dataInput);
+ case Const.CONSTANT_MethodHandle:
+ return new ConstantMethodHandle(dataInput);
+ case Const.CONSTANT_MethodType:
+ return new ConstantMethodType(dataInput);
+ case Const.CONSTANT_Dynamic:
+ return new ConstantDynamic(dataInput);
+ case Const.CONSTANT_InvokeDynamic:
+ return new ConstantInvokeDynamic(dataInput);
+ case Const.CONSTANT_Module:
+ return new ConstantModule(dataInput);
+ case Const.CONSTANT_Package:
+ return new ConstantPackage(dataInput);
+ default:
+ throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
+ }
}
/**
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java
index 8f6a266..86c28fe 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantCP.java
@@ -53,7 +53,7 @@ public abstract class ConstantCP extends Constant {
/**
* Initialize instance from file data.
*
- * @param tag Constant type tag
+ * @param tag Constant type tag
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
@@ -62,7 +62,7 @@ public abstract class ConstantCP extends Constant {
}
/**
- * @param classIndex Reference to the class containing the field
+ * @param classIndex Reference to the class containing the field
* @param nameAndTypeIndex and the field signature
*/
protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) {
@@ -107,13 +107,6 @@ public abstract class ConstantCP extends Constant {
return class_index;
}
- /**
- * @return Reference (index) to signature of the field.
- */
- public final int getNameAndTypeIndex() {
- return name_and_type_index;
- }
-
/**
* @param classIndex points to Constant_class
*/
@@ -121,6 +114,13 @@ public abstract class ConstantCP extends Constant {
this.class_index = classIndex;
}
+ /**
+ * @return Reference (index) to signature of the field.
+ */
+ public final int getNameAndTypeIndex() {
+ return name_and_type_index;
+ }
+
/**
* @param nameAndTypeIndex points to Constant_NameAndType
*/
@@ -130,8 +130,8 @@ public abstract class ConstantCP extends Constant {
/**
* @return String representation.
- *
- * not final as ConstantInvokeDynamic needs to modify
+ *
+ * not final as ConstantInvokeDynamic needs to modify
*/
@Override
public String toString() {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java
index 745f9c3..82db2c4 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDouble.java
@@ -88,6 +88,13 @@ public final class ConstantDouble extends Constant implements ConstantObject {
return bytes;
}
+ /**
+ * @param bytes the raw bytes that represent the double value
+ */
+ public void setBytes(final double bytes) {
+ this.bytes = bytes;
+ }
+
/**
* @return Double object
*/
@@ -96,13 +103,6 @@ public final class ConstantDouble extends Constant implements ConstantObject {
return Double.valueOf(bytes);
}
- /**
- * @param bytes the raw bytes that represent the double value
- */
- public void setBytes(final double bytes) {
- this.bytes = bytes;
- }
-
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java
index bea3381..1700154 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantDynamic.java
@@ -27,7 +27,7 @@ import java.io.IOException;
*
* @see Constant
* @see Change request for JEP
- * 309
+ * 309
* @since 6.3
*/
public final class ConstantDynamic extends ConstantCP {
@@ -68,8 +68,8 @@ public final class ConstantDynamic extends ConstantCP {
/**
* @return Reference (index) to bootstrap method this constant refers to.
- *
- * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
+ *
+ * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
* @since 6.0
*/
public int getBootstrapMethodAttrIndex() {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java
index dfaffc2..a21edd0 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFieldref.java
@@ -46,7 +46,7 @@ public final class ConstantFieldref extends ConstantCP {
}
/**
- * @param classIndex Reference to the class containing the Field
+ * @param classIndex Reference to the class containing the Field
* @param nameAndTypeIndex and the Field signature
*/
public ConstantFieldref(final int classIndex, final int nameAndTypeIndex) {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java
index 5b2ece3..83a63e8 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantFloat.java
@@ -89,6 +89,13 @@ public final class ConstantFloat extends Constant implements ConstantObject {
return bytes;
}
+ /**
+ * @param bytes the raw bytes that represent this float
+ */
+ public void setBytes(final float bytes) {
+ this.bytes = bytes;
+ }
+
/**
* @return Float object
*/
@@ -97,13 +104,6 @@ public final class ConstantFloat extends Constant implements ConstantObject {
return Float.valueOf(bytes);
}
- /**
- * @param bytes the raw bytes that represent this float
- */
- public void setBytes(final float bytes) {
- this.bytes = bytes;
- }
-
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java
index 2540969..3d5cdcc 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInteger.java
@@ -88,6 +88,13 @@ public final class ConstantInteger extends Constant implements ConstantObject {
return bytes;
}
+ /**
+ * @param bytes the raw bytes that represent this integer
+ */
+ public void setBytes(final int bytes) {
+ this.bytes = bytes;
+ }
+
/**
* @return Integer object
*/
@@ -96,13 +103,6 @@ public final class ConstantInteger extends Constant implements ConstantObject {
return Integer.valueOf(bytes);
}
- /**
- * @param bytes the raw bytes that represent this integer
- */
- public void setBytes(final int bytes) {
- this.bytes = bytes;
- }
-
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java
index 28521c3..1f3e1d5 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInterfaceMethodref.java
@@ -46,7 +46,7 @@ public final class ConstantInterfaceMethodref extends ConstantCP {
}
/**
- * @param classIndex Reference to the class containing the method
+ * @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature
*/
public ConstantInterfaceMethodref(final int classIndex, final int nameAndTypeIndex) {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java
index 3cb848a..84f7065 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantInvokeDynamic.java
@@ -26,7 +26,7 @@ import java.io.IOException;
*
* @see Constant
* @see The
- * CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification
+ * CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification
* @since 6.0
*/
public final class ConstantInvokeDynamic extends ConstantCP {
@@ -67,8 +67,8 @@ public final class ConstantInvokeDynamic extends ConstantCP {
/**
* @return Reference (index) to bootstrap method this constant refers to.
- *
- * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
+ *
+ * Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
* @since 6.0
*/
public int getBootstrapMethodAttrIndex() {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java
index 7c57f20..48ef892 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantLong.java
@@ -88,6 +88,13 @@ public final class ConstantLong extends Constant implements ConstantObject {
return bytes;
}
+ /**
+ * @param bytes the raw bytes that represent this long
+ */
+ public void setBytes(final long bytes) {
+ this.bytes = bytes;
+ }
+
/**
* @return Long object
*/
@@ -96,13 +103,6 @@ public final class ConstantLong extends Constant implements ConstantObject {
return Long.valueOf(bytes);
}
- /**
- * @param bytes the raw bytes that represent this long
- */
- public void setBytes(final long bytes) {
- this.bytes = bytes;
- }
-
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java
index 98891fe..fe554a6 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodHandle.java
@@ -86,14 +86,14 @@ public final class ConstantMethodHandle extends Constant {
return referenceIndex;
}
- public int getReferenceKind() {
- return referenceKind;
- }
-
public void setReferenceIndex(final int referenceIndex) {
this.referenceIndex = referenceIndex;
}
+ public int getReferenceKind() {
+ return referenceKind;
+ }
+
public void setReferenceKind(final int referenceKind) {
this.referenceKind = referenceKind;
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java
index e9b02b3..322848d 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantMethodref.java
@@ -46,7 +46,7 @@ public final class ConstantMethodref extends ConstantCP {
}
/**
- * @param classIndex Reference to the class containing the method
+ * @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature
*/
public ConstantMethodref(final int classIndex, final int nameAndTypeIndex) {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java
index 547e4cd..be69787 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantNameAndType.java
@@ -53,7 +53,7 @@ public final class ConstantNameAndType extends Constant {
}
/**
- * @param nameIndex Name of field/method
+ * @param nameIndex Name of field/method
* @param signatureIndex and its signature
*/
public ConstantNameAndType(final int nameIndex, final int signatureIndex) {
@@ -100,6 +100,13 @@ public final class ConstantNameAndType extends Constant {
return nameIndex;
}
+ /**
+ * @param nameIndex the name index of this constant
+ */
+ public void setNameIndex(final int nameIndex) {
+ this.nameIndex = nameIndex;
+ }
+
/**
* @return signature
*/
@@ -114,13 +121,6 @@ public final class ConstantNameAndType extends Constant {
return signatureIndex;
}
- /**
- * @param nameIndex the name index of this constant
- */
- public void setNameIndex(final int nameIndex) {
- this.nameIndex = nameIndex;
- }
-
/**
* @param signatureIndex the signature index in the constant pool of this type
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java
index 29a8082..c453949 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantPool.java
@@ -35,34 +35,6 @@ import java.util.Iterator;
*/
public class ConstantPool implements Cloneable, Node, Iterable {
- private static String escape(final String str) {
- final int len = str.length();
- final StringBuilder buf = new StringBuilder(len + 5);
- final char[] ch = str.toCharArray();
- for (int i = 0; i < len; i++) {
- switch (ch[i]) {
- case '\n':
- buf.append("\\n");
- break;
- case '\r':
- buf.append("\\r");
- break;
- case '\t':
- buf.append("\\t");
- break;
- case '\b':
- buf.append("\\b");
- break;
- case '"':
- buf.append("\\\"");
- break;
- default:
- buf.append(ch[i]);
- }
- }
- return buf.toString();
- }
-
private Constant[] constantPool;
/**
@@ -100,6 +72,34 @@ public class ConstantPool implements Cloneable, Node, Iterable {
}
}
+ private static String escape(final String str) {
+ final int len = str.length();
+ final StringBuilder buf = new StringBuilder(len + 5);
+ final char[] ch = str.toCharArray();
+ for (int i = 0; i < len; i++) {
+ switch (ch[i]) {
+ case '\n':
+ buf.append("\\n");
+ break;
+ case '\r':
+ buf.append("\\r");
+ break;
+ case '\t':
+ buf.append("\\t");
+ break;
+ case '\b':
+ buf.append("\\b");
+ break;
+ case '"':
+ buf.append("\\\"");
+ break;
+ default:
+ buf.append(ch[i]);
+ }
+ }
+ return buf.toString();
+ }
+
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e., the hierarchy of methods, fields,
* attributes, etc. spawns a tree of objects.
@@ -123,72 +123,72 @@ public class ConstantPool implements Cloneable, Node, Iterable {
int i;
final byte tag = c.getTag();
switch (tag) {
- case Const.CONSTANT_Class:
- i = ((ConstantClass) c).getNameIndex();
- c = getConstantUtf8(i);
- str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
- break;
- case Const.CONSTANT_String:
- i = ((ConstantString) c).getStringIndex();
- c = getConstantUtf8(i);
- str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
- break;
- case Const.CONSTANT_Utf8:
- str = ((ConstantUtf8) c).getBytes();
- break;
- case Const.CONSTANT_Double:
- str = String.valueOf(((ConstantDouble) c).getBytes());
- break;
- case Const.CONSTANT_Float:
- str = String.valueOf(((ConstantFloat) c).getBytes());
- break;
- case Const.CONSTANT_Long:
- str = String.valueOf(((ConstantLong) c).getBytes());
- break;
- case Const.CONSTANT_Integer:
- str = String.valueOf(((ConstantInteger) c).getBytes());
- break;
- case Const.CONSTANT_NameAndType:
- str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " "
- + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8);
- break;
- case Const.CONSTANT_InterfaceMethodref:
- case Const.CONSTANT_Methodref:
- case Const.CONSTANT_Fieldref:
- str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "."
- + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
- break;
- case Const.CONSTANT_MethodHandle:
- // Note that the ReferenceIndex may point to a Fieldref, Methodref or
- // InterfaceMethodref - so we need to peek ahead to get the actual type.
- final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
- str = Const.getMethodHandleName(cmh.getReferenceKind()) + " "
- + constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag());
- break;
- case Const.CONSTANT_MethodType:
- final ConstantMethodType cmt = (ConstantMethodType) c;
- str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
- break;
- case Const.CONSTANT_InvokeDynamic:
- final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
- str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
- break;
- case Const.CONSTANT_Dynamic:
- final ConstantDynamic cd = (ConstantDynamic) c;
- str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
- break;
- case Const.CONSTANT_Module:
- i = ((ConstantModule) c).getNameIndex();
- c = getConstantUtf8(i);
- str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
- break;
- case Const.CONSTANT_Package:
- i = ((ConstantPackage) c).getNameIndex();
- c = getConstantUtf8(i);
- str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
- break;
- default: // Never reached
- throw new IllegalArgumentException("Unknown constant type " + tag);
+ case Const.CONSTANT_Class:
+ i = ((ConstantClass) c).getNameIndex();
+ c = getConstantUtf8(i);
+ str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
+ break;
+ case Const.CONSTANT_String:
+ i = ((ConstantString) c).getStringIndex();
+ c = getConstantUtf8(i);
+ str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
+ break;
+ case Const.CONSTANT_Utf8:
+ str = ((ConstantUtf8) c).getBytes();
+ break;
+ case Const.CONSTANT_Double:
+ str = String.valueOf(((ConstantDouble) c).getBytes());
+ break;
+ case Const.CONSTANT_Float:
+ str = String.valueOf(((ConstantFloat) c).getBytes());
+ break;
+ case Const.CONSTANT_Long:
+ str = String.valueOf(((ConstantLong) c).getBytes());
+ break;
+ case Const.CONSTANT_Integer:
+ str = String.valueOf(((ConstantInteger) c).getBytes());
+ break;
+ case Const.CONSTANT_NameAndType:
+ str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " "
+ + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8);
+ break;
+ case Const.CONSTANT_InterfaceMethodref:
+ case Const.CONSTANT_Methodref:
+ case Const.CONSTANT_Fieldref:
+ str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "."
+ + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
+ break;
+ case Const.CONSTANT_MethodHandle:
+ // Note that the ReferenceIndex may point to a Fieldref, Methodref or
+ // InterfaceMethodref - so we need to peek ahead to get the actual type.
+ final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
+ str = Const.getMethodHandleName(cmh.getReferenceKind()) + " "
+ + constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag());
+ break;
+ case Const.CONSTANT_MethodType:
+ final ConstantMethodType cmt = (ConstantMethodType) c;
+ str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
+ break;
+ case Const.CONSTANT_InvokeDynamic:
+ final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
+ str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
+ break;
+ case Const.CONSTANT_Dynamic:
+ final ConstantDynamic cd = (ConstantDynamic) c;
+ str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
+ break;
+ case Const.CONSTANT_Module:
+ i = ((ConstantModule) c).getNameIndex();
+ c = getConstantUtf8(i);
+ str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
+ break;
+ case Const.CONSTANT_Package:
+ i = ((ConstantPackage) c).getNameIndex();
+ c = getConstantUtf8(i);
+ str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
+ break;
+ default: // Never reached
+ throw new IllegalArgumentException("Unknown constant type " + tag);
}
return str;
}
@@ -249,8 +249,8 @@ public class ConstantPool implements Cloneable, Node, Iterable {
*
* @param index Index in constant pool
* @return Constant value
- * @see Constant
* @throws ClassFormatException if index is invalid
+ * @see Constant
*/
@SuppressWarnings("unchecked")
public T getConstant(final int index) throws ClassFormatException {
@@ -263,8 +263,8 @@ public class ConstantPool implements Cloneable, Node, Iterable {
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
- * @see Constant
* @throws ClassFormatException if constant type does not match tag
+ * @see Constant
*/
@SuppressWarnings("unchecked")
public T getConstant(final int index, final byte tag) throws ClassFormatException {
@@ -277,8 +277,8 @@ public class ConstantPool implements Cloneable, Node, Iterable {
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
- * @see Constant
* @throws ClassFormatException if constant type does not match tag
+ * @see Constant
* @since 6.6.0
*/
public T getConstant(final int index, final byte tag, final Class castTo) throws ClassFormatException {
@@ -292,12 +292,12 @@ public class ConstantPool implements Cloneable, Node, Iterable {
/**
* Gets constant from constant pool.
*
- * @param A {@link Constant} subclass
- * @param index Index in constant pool
+ * @param A {@link Constant} subclass
+ * @param index Index in constant pool
* @param castTo The {@link Constant} subclass to cast to.
* @return Constant value
- * @see Constant
* @throws ClassFormatException if index is invalid
+ * @see Constant
* @since 6.6.0
*/
public T getConstant(final int index, final Class castTo) throws ClassFormatException {
@@ -311,8 +311,8 @@ public class ConstantPool implements Cloneable, Node, Iterable {
// Previous check ensures this won't throw a ClassCastException
final T c = castTo.cast(constantPool[index]);
if (c == null
- // the 0th element is always null
- && index != 0) {
+ // the 0th element is always null
+ && index != 0) {
final Constant prev = constantPool[index - 1];
if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) {
throw new ClassFormatException("Constant pool at index " + index + " is null.");
@@ -326,8 +326,8 @@ public class ConstantPool implements Cloneable, Node, Iterable {
*
* @param index Index in constant pool
* @return ConstantInteger value
- * @see ConstantInteger
* @throws ClassFormatException if constant type does not match tag
+ * @see ConstantInteger
*/
public ConstantInteger getConstantInteger(final int index) {
return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class);
@@ -341,6 +341,13 @@ public class ConstantPool implements Cloneable, Node, Iterable {
return constantPool;
}
+ /**
+ * @param constantPool
+ */
+ public void setConstantPool(final Constant[] constantPool) {
+ this.constantPool = constantPool;
+ }
+
/**
* Gets string from constant pool and bypass the indirection of 'ConstantClass' and 'ConstantString' objects. I.e. these classes have an index field that
* points to another entry of the constant pool of type 'ConstantUtf8' which contains the real data.
@@ -348,9 +355,9 @@ public class ConstantPool implements Cloneable, Node, Iterable {
* @param index Index in constant pool
* @param tag Tag of expected constant, either ConstantClass or ConstantString
* @return Contents of string reference
+ * @throws IllegalArgumentException if tag is invalid
* @see ConstantClass
* @see ConstantString
- * @throws IllegalArgumentException if tag is invalid
*/
public String getConstantString(final int index, final byte tag) throws IllegalArgumentException {
int i;
@@ -360,22 +367,22 @@ public class ConstantPool implements Cloneable, Node, Iterable {
* subclassing.
*/
switch (tag) {
- case Const.CONSTANT_Class:
- i = getConstant(index, ConstantClass.class).getNameIndex();
- break;
- case Const.CONSTANT_String:
- i = getConstant(index, ConstantString.class).getStringIndex();
- break;
- case Const.CONSTANT_Module:
- i = getConstant(index, ConstantModule.class).getNameIndex();
- break;
- case Const.CONSTANT_Package:
- i = getConstant(index, ConstantPackage.class).getNameIndex();
- break;
- case Const.CONSTANT_Utf8:
- return getConstantUtf8(index).getBytes();
- default:
- throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
+ case Const.CONSTANT_Class:
+ i = getConstant(index, ConstantClass.class).getNameIndex();
+ break;
+ case Const.CONSTANT_String:
+ i = getConstant(index, ConstantString.class).getStringIndex();
+ break;
+ case Const.CONSTANT_Module:
+ i = getConstant(index, ConstantModule.class).getNameIndex();
+ break;
+ case Const.CONSTANT_Package:
+ i = getConstant(index, ConstantPackage.class).getNameIndex();
+ break;
+ case Const.CONSTANT_Utf8:
+ return getConstantUtf8(index).getBytes();
+ default:
+ throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
}
// Finally get the string from the constant pool
return getConstantUtf8(i).getBytes();
@@ -386,8 +393,8 @@ public class ConstantPool implements Cloneable, Node, Iterable {
*
* @param index Index in constant pool
* @return ConstantUtf8 value
- * @see ConstantUtf8
* @throws ClassFormatException if constant type does not match tag
+ * @see ConstantUtf8
*/
public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException {
return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class);
@@ -412,13 +419,6 @@ public class ConstantPool implements Cloneable, Node, Iterable {
constantPool[index] = constant;
}
- /**
- * @param constantPool
- */
- public void setConstantPool(final Constant[] constantPool) {
- this.constantPool = constantPool;
- }
-
/**
* @return String representation.
*/
@@ -430,4 +430,164 @@ public class ConstantPool implements Cloneable, Node, Iterable {
}
return buf.toString();
}
+
+
+ // ---------------------------------------------- haidnorJVM
+
+ public ConstantFieldref getConstantFieldref(int constantFieldrefIndex) {
+ return getConstant(constantFieldrefIndex);
+ }
+
+ public ConstantMethodref getConstantMethodref(int constantMethodrefIndex) {
+ return getConstant(constantMethodrefIndex);
+ }
+
+ public ConstantClass getConstantClass(int constantClassIndex) {
+ return getConstant(constantClassIndex);
+ }
+
+ public ConstantNameAndType getConstantNameAndType(int constantNameAndTypeIndex) {
+ return getConstant(constantNameAndTypeIndex);
+ }
+
+
+ // ConstantClass ---------------------------------------------------------------------------------------------------
+
+ /**
+ * 获取长类名, 例如 java/lang/String
+ */
+ public String constantClass_ClassName(final ConstantClass constantClass) {
+ ConstantUtf8 constantUtf8 = getConstant(constantClass.getNameIndex());
+ return constantUtf8.getBytes();
+ }
+
+ /**
+ * 获取长类名, 例如 java/lang/String
+ */
+ public String constantClass_ClassName(int constantClassIndex) {
+ ConstantClass constantClass = getConstant(constantClassIndex);
+ return constantClass_ClassName(constantClass);
+ }
+
+
+ // ConstantFieldref ------------------------------------------------------------------------------------------------
+
+ /**
+ * 获取字段所处于Java类的类名, 例如 java/lang/String
+ */
+ public String constantFieldref_ClassName(final ConstantFieldref constantFieldref) {
+ ConstantClass constClass = getConstant(constantFieldref.getClassIndex());
+ return (String) constClass.getConstantValue(this);
+ }
+
+ /**
+ * 获取字段所处于Java类的类名, 例如 java/lang/String
+ */
+ public String constantFieldref_ClassName(int constantFieldrefIndex) {
+ ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex);
+ return constantFieldref_ClassName(constantFieldref);
+ }
+
+ /**
+ * 获取字段名称
+ */
+ public String getFieldName(final ConstantFieldref constantFieldref) {
+ ConstantNameAndType constNameAndType = getConstant(constantFieldref.getNameAndTypeIndex());
+ return constNameAndType.getName(this);
+ }
+
+ /**
+ * 获取字段名称
+ */
+ public String getFieldName(int constantFieldrefIndex) {
+ ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex);
+ return getFieldName(constantFieldref);
+ }
+
+ /**
+ * 获取字段类型签名
+ */
+ public String getFieldSignature(final ConstantFieldref constantFieldref) {
+ ConstantNameAndType constNameAndType = getConstant(constantFieldref.getNameAndTypeIndex());
+ return constNameAndType.getSignature(this);
+ }
+
+ /**
+ * 获取字段类型签名
+ */
+ public String getFieldSignature(int constantFieldrefIndex) {
+ ConstantFieldref constantFieldref = getConstantFieldref(constantFieldrefIndex);
+ return getFieldSignature(constantFieldref);
+ }
+
+ // ConstantMethodref -----------------------------------------------------------------------------------------------
+
+ /**
+ * 获取方法所处于Java类的类名
+ * 名称使用/分割,例如 haidnor/jvm/test/instruction/references/NEW
+ */
+ public String constantMethodref_ClassName(final ConstantMethodref methodref) {
+ ConstantClass constClass = getConstant(methodref.getClassIndex());
+ return (String) constClass.getConstantValue(this);
+ }
+
+ /**
+ * 获取方法名
+ */
+ public String constantMethodref_MethodName(final ConstantMethodref methodref) {
+ ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
+ return constNameAndType.getName(this);
+ }
+
+ /**
+ * 获取方法签名
+ */
+ public String constantMethodref_MethodSignature(final ConstantMethodref methodref) {
+ ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
+ return constNameAndType.getSignature(this);
+ }
+
+ // ConstantInterfaceMethodref -----------------------------------------------------------------------------------------------
+
+ public String constantInterfaceMethodref_ClassName(final ConstantInterfaceMethodref methodref) {
+ ConstantClass constClass = getConstant(methodref.getClassIndex());
+ return (String) constClass.getConstantValue(this);
+ }
+
+ /**
+ * 获取方法名
+ */
+ public String constantInterfaceMethodref_MethodName(final ConstantInterfaceMethodref methodref) {
+ ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
+ return constNameAndType.getName(this);
+ }
+
+ /**
+ * 获取方法签名
+ */
+ public String constantInterfaceMethodref_MethodSignature(final ConstantInterfaceMethodref methodref) {
+ ConstantNameAndType constNameAndType = getConstant(methodref.getNameAndTypeIndex());
+ return constNameAndType.getSignature(this);
+ }
+
+
+ // ConstantNameAndType -----------------------------------------------------------------------------------------------
+
+ /**
+ * ConstantNameAndType
+ */
+ public ConstantNameAndType constantNameAndType(int constantNameAndTypeIndex) {
+ return getConstant(constantNameAndTypeIndex);
+ }
+
+ public String constantNameAndType_name(int constantNameAndTypeIndex) {
+ ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex);
+ return constantNameAndType.getName(this);
+ }
+
+ public String constantNameAndType_signature(int constantNameAndTypeIndex) {
+ ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex);
+ return constantNameAndType.getSignature(this);
+ }
+
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java
index 555a23e..5461ddc 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantUtf8.java
@@ -57,47 +57,53 @@ import java.util.Objects;
*/
public final class ConstantUtf8 extends Constant {
- private static class Cache {
-
- private static final boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS);
- private static final int MAX_ENTRIES = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRIES, 0).intValue();
- private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75);
-
- private static final HashMap CACHE = new LinkedHashMap(INITIAL_CAPACITY, 0.75f, true) {
-
- private static final long serialVersionUID = -8506975356158971766L;
-
- @Override
- protected boolean removeEldestEntry(final Map.Entry eldest) {
- return size() > MAX_ENTRIES;
- }
- };
-
- // Set the size to 0 or below to skip caching entirely
- private static final int MAX_ENTRY_SIZE = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRY_SIZE, 200).intValue();
-
- static boolean isEnabled() {
- return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
- }
-
- }
-
+ private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached";
+ private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size";
+ private static final String SYS_PROP_STATISTICS = "bcel.statistics";
// TODO these should perhaps be AtomicInt?
private static volatile int considered;
private static volatile int created;
private static volatile int hits;
private static volatile int skipped;
- private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached";
- private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size";
- private static final String SYS_PROP_STATISTICS = "bcel.statistics";
-
static {
if (Cache.BCEL_STATISTICS) {
Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats));
}
}
+ private final String value;
+
+ /**
+ * Initializes from another object.
+ *
+ * @param constantUtf8 the value.
+ */
+ public ConstantUtf8(final ConstantUtf8 constantUtf8) {
+ this(constantUtf8.getBytes());
+ }
+
+ /**
+ * Initializes instance from file data.
+ *
+ * @param dataInput Input stream
+ * @throws IOException if an I/O error occurs.
+ */
+ ConstantUtf8(final DataInput dataInput) throws IOException {
+ super(Const.CONSTANT_Utf8);
+ value = dataInput.readUTF();
+ created++;
+ }
+
+ /**
+ * @param value Data
+ */
+ public ConstantUtf8(final String value) {
+ super(Const.CONSTANT_Utf8);
+ this.value = Objects.requireNonNull(value, "value");
+ created++;
+ }
+
/**
* Clears the cache.
*
@@ -175,39 +181,7 @@ public final class ConstantUtf8 extends Constant {
System.err.printf("%s Cache hit %,d/%,d, %d skipped.%n", prefix, hits, considered, skipped);
System.err.printf("%s Total of %,d ConstantUtf8 objects created.%n", prefix, created);
System.err.printf("%s Configuration: %s=%,d, %s=%,d.%n", prefix, SYS_PROP_CACHE_MAX_ENTRIES, Cache.MAX_ENTRIES, SYS_PROP_CACHE_MAX_ENTRY_SIZE,
- Cache.MAX_ENTRY_SIZE);
- }
-
- private final String value;
-
- /**
- * Initializes from another object.
- *
- * @param constantUtf8 the value.
- */
- public ConstantUtf8(final ConstantUtf8 constantUtf8) {
- this(constantUtf8.getBytes());
- }
-
- /**
- * Initializes instance from file data.
- *
- * @param dataInput Input stream
- * @throws IOException if an I/O error occurs.
- */
- ConstantUtf8(final DataInput dataInput) throws IOException {
- super(Const.CONSTANT_Utf8);
- value = dataInput.readUTF();
- created++;
- }
-
- /**
- * @param value Data
- */
- public ConstantUtf8(final String value) {
- super(Const.CONSTANT_Utf8);
- this.value = Objects.requireNonNull(value, "value");
- created++;
+ Cache.MAX_ENTRY_SIZE);
}
/**
@@ -256,4 +230,29 @@ public final class ConstantUtf8 extends Constant {
public String toString() {
return super.toString() + "(\"" + Utility.replace(value, "\n", "\\n") + "\")";
}
+
+ private static class Cache {
+
+ private static final boolean BCEL_STATISTICS = Boolean.getBoolean(SYS_PROP_STATISTICS);
+ private static final int MAX_ENTRIES = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRIES, 0).intValue();
+ private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75);
+
+ private static final HashMap CACHE = new LinkedHashMap(INITIAL_CAPACITY, 0.75f, true) {
+
+ private static final long serialVersionUID = -8506975356158971766L;
+
+ @Override
+ protected boolean removeEldestEntry(final Map.Entry eldest) {
+ return size() > MAX_ENTRIES;
+ }
+ };
+
+ // Set the size to 0 or below to skip caching entirely
+ private static final int MAX_ENTRY_SIZE = Integer.getInteger(SYS_PROP_CACHE_MAX_ENTRY_SIZE, 200).intValue();
+
+ static boolean isEnabled() {
+ return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
+ }
+
+ }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java b/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java
index b5c2278..3c6737e 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ConstantValue.java
@@ -34,6 +34,7 @@ import java.io.IOException;
* u2 constantvalue_index;
* }
*
+ *
* @see Attribute
*/
public final class ConstantValue extends Attribute {
@@ -53,9 +54,9 @@ public final class ConstantValue extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Name index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Name index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -64,10 +65,10 @@ public final class ConstantValue extends Attribute {
}
/**
- * @param nameIndex Name index in constant pool
- * @param length Content length in bytes
+ * @param nameIndex Name index in constant pool
+ * @param length Content length in bytes
* @param constantValueIndex Index in constant pool
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public ConstantValue(final int nameIndex, final int length, final int constantValueIndex, final ConstantPool constantPool) {
super(Const.ATTR_CONSTANT_VALUE, nameIndex, Args.require(length, 2, "ConstantValue attribute length"), constantPool);
@@ -131,25 +132,25 @@ public final class ConstantValue extends Attribute {
int i;
// Print constant to string depending on its type
switch (c.getTag()) {
- case Const.CONSTANT_Long:
- buf = String.valueOf(((ConstantLong) c).getBytes());
- break;
- case Const.CONSTANT_Float:
- buf = String.valueOf(((ConstantFloat) c).getBytes());
- break;
- case Const.CONSTANT_Double:
- buf = String.valueOf(((ConstantDouble) c).getBytes());
- break;
- case Const.CONSTANT_Integer:
- buf = String.valueOf(((ConstantInteger) c).getBytes());
- break;
- case Const.CONSTANT_String:
- i = ((ConstantString) c).getStringIndex();
- c = super.getConstantPool().getConstantUtf8(i);
- buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
- break;
- default:
- throw new IllegalStateException("Type of ConstValue invalid: " + c);
+ case Const.CONSTANT_Long:
+ buf = String.valueOf(((ConstantLong) c).getBytes());
+ break;
+ case Const.CONSTANT_Float:
+ buf = String.valueOf(((ConstantFloat) c).getBytes());
+ break;
+ case Const.CONSTANT_Double:
+ buf = String.valueOf(((ConstantDouble) c).getBytes());
+ break;
+ case Const.CONSTANT_Integer:
+ buf = String.valueOf(((ConstantInteger) c).getBytes());
+ break;
+ case Const.CONSTANT_String:
+ i = ((ConstantString) c).getStringIndex();
+ c = super.getConstantPool().getConstantUtf8(i);
+ buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
+ break;
+ default:
+ throw new IllegalStateException("Type of ConstValue invalid: " + c);
}
return buf;
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java b/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java
index fc2024c..50d188b 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Deprecated.java
@@ -44,9 +44,9 @@ public final class Deprecated extends Attribute {
}
/**
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param bytes Attribute contents
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param bytes Attribute contents
* @param constantPool Array of constants
*/
public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
@@ -57,9 +57,9 @@ public final class Deprecated extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java b/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java
index 355da57..19a8329 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/DescendingVisitor.java
@@ -32,7 +32,7 @@ public class DescendingVisitor implements Visitor {
private final Stack stack = new Stack<>();
/**
- * @param clazz Class to traverse
+ * @param clazz Class to traverse
* @param visitor visitor object to apply to all components
*/
public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
@@ -153,7 +153,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.3 */
+ /**
+ * @since 6.3
+ */
@Override
public void visitConstantDynamic(final ConstantDynamic obj) {
stack.push(obj);
@@ -206,7 +208,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.0 */
+ /**
+ * @since 6.0
+ */
@Override
public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
stack.push(obj);
@@ -221,7 +225,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.0 */
+ /**
+ * @since 6.0
+ */
@Override
public void visitConstantMethodType(final ConstantMethodType obj) {
stack.push(obj);
@@ -229,7 +235,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.1 */
+ /**
+ * @since 6.1
+ */
@Override
public void visitConstantModule(final ConstantModule obj) {
stack.push(obj);
@@ -244,7 +252,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.1 */
+ /**
+ * @since 6.1
+ */
@Override
public void visitConstantPackage(final ConstantPackage obj) {
stack.push(obj);
@@ -408,7 +418,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModule(final Module obj) {
stack.push(obj);
@@ -420,7 +432,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleExports(final ModuleExports obj) {
stack.push(obj);
@@ -428,7 +442,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleMainClass(final ModuleMainClass obj) {
stack.push(obj);
@@ -436,7 +452,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleOpens(final ModuleOpens obj) {
stack.push(obj);
@@ -444,7 +462,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModulePackages(final ModulePackages obj) {
stack.push(obj);
@@ -452,7 +472,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleProvides(final ModuleProvides obj) {
stack.push(obj);
@@ -460,7 +482,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
stack.push(obj);
@@ -468,7 +492,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitNestHost(final NestHost obj) {
stack.push(obj);
@@ -476,7 +502,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitNestMembers(final NestMembers obj) {
stack.push(obj);
@@ -494,7 +522,9 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- /** @since 6.0 */
+ /**
+ * @since 6.0
+ */
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
stack.push(obj);
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java b/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java
index fe950f5..aa55c07 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ElementValue.java
@@ -44,8 +44,9 @@ import java.io.IOException;
* element_value values[num_values];
* } array_value;
* } value;
- *}
- *
+ * }
+ *
+ *
* @since 6.0
*/
public abstract class ElementValue {
@@ -63,72 +64,6 @@ public abstract class ElementValue {
public static final byte PRIMITIVE_LONG = 'J';
public static final byte PRIMITIVE_SHORT = 'S';
public static final byte PRIMITIVE_BOOLEAN = 'Z';
-
- /**
- * Reads an {@code element_value} as an {@code ElementValue}.
- *
- * @param input Raw data input.
- * @param cpool Constant pool.
- * @return a new ElementValue.
- * @throws IOException if an I/O error occurs.
- */
- public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
- return readElementValue(input, cpool, 0);
- }
-
- /**
- * Reads an {@code element_value} as an {@code ElementValue}.
- *
- * @param input Raw data input.
- * @param cpool Constant pool.
- * @param arrayNesting level of current array nesting.
- * @return a new ElementValue.
- * @throws IOException if an I/O error occurs.
- * @since 6.7.0
- */
- public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
- throws IOException {
- final byte tag = input.readByte();
- switch (tag) {
- case PRIMITIVE_BYTE:
- case PRIMITIVE_CHAR:
- case PRIMITIVE_DOUBLE:
- case PRIMITIVE_FLOAT:
- case PRIMITIVE_INT:
- case PRIMITIVE_LONG:
- case PRIMITIVE_SHORT:
- case PRIMITIVE_BOOLEAN:
- case STRING:
- return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
-
- case ENUM_CONSTANT:
- return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
-
- case CLASS:
- return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
-
- case ANNOTATION:
- // TODO isRuntimeVisible
- return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
-
- case ARRAY:
- arrayNesting++;
- if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
- // JVM spec 4.4.1
- throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
- }
- final int numArrayVals = input.readUnsignedShort();
- final ElementValue[] evalues = new ElementValue[numArrayVals];
- for (int j = 0; j < numArrayVals; j++) {
- evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
- }
- return new ArrayElementValue(ARRAY, evalues, cpool);
-
- default:
- throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
- }
- }
-
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@@ -145,9 +80,76 @@ public abstract class ElementValue {
this.cpool = cpool;
}
+ /**
+ * Reads an {@code element_value} as an {@code ElementValue}.
+ *
+ * @param input Raw data input.
+ * @param cpool Constant pool.
+ * @return a new ElementValue.
+ * @throws IOException if an I/O error occurs.
+ */
+ public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
+ return readElementValue(input, cpool, 0);
+ }
+
+ /**
+ * Reads an {@code element_value} as an {@code ElementValue}.
+ *
+ * @param input Raw data input.
+ * @param cpool Constant pool.
+ * @param arrayNesting level of current array nesting.
+ * @return a new ElementValue.
+ * @throws IOException if an I/O error occurs.
+ * @since 6.7.0
+ */
+ public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
+ throws IOException {
+ final byte tag = input.readByte();
+ switch (tag) {
+ case PRIMITIVE_BYTE:
+ case PRIMITIVE_CHAR:
+ case PRIMITIVE_DOUBLE:
+ case PRIMITIVE_FLOAT:
+ case PRIMITIVE_INT:
+ case PRIMITIVE_LONG:
+ case PRIMITIVE_SHORT:
+ case PRIMITIVE_BOOLEAN:
+ case STRING:
+ return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
+
+ case ENUM_CONSTANT:
+ return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
+
+ case CLASS:
+ return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
+
+ case ANNOTATION:
+ // TODO isRuntimeVisible
+ return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
+
+ case ARRAY:
+ arrayNesting++;
+ if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
+ // JVM spec 4.4.1
+ throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
+ }
+ final int numArrayVals = input.readUnsignedShort();
+ final ElementValue[] evalues = new ElementValue[numArrayVals];
+ for (int j = 0; j < numArrayVals; j++) {
+ evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
+ }
+ return new ArrayElementValue(ARRAY, evalues, cpool);
+
+ default:
+ throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
+ }
+ }
+
public abstract void dump(DataOutputStream dos) throws IOException;
- /** @since 6.0 */
+ /**
+ * @since 6.0
+ */
final ConstantPool getConstantPool() {
return cpool;
}
@@ -156,7 +158,9 @@ public abstract class ElementValue {
return type;
}
- /** @since 6.0 */
+ /**
+ * @since 6.0
+ */
final int getType() {
return type;
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java b/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java
index 2763aed..61eea60 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/EmptyVisitor.java
@@ -235,47 +235,65 @@ public class EmptyVisitor implements Visitor {
public void visitMethodParameters(final MethodParameters obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModule(final Module obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleExports(final ModuleExports obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleMainClass(final ModuleMainClass obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleOpens(final ModuleOpens obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModulePackages(final ModulePackages obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleProvides(final ModuleProvides obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitNestHost(final NestHost obj) {
}
- /** @since 6.4.0 */
+ /**
+ * @since 6.4.0
+ */
@Override
public void visitNestMembers(final NestMembers obj) {
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java
index c81d27d..0cf7791 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/EnclosingMethod.java
@@ -1,18 +1,18 @@
/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package haidnor.jvm.bcel.classfile;
@@ -81,6 +81,10 @@ public class EnclosingMethod extends Attribute {
return classIndex;
}
+ public final void setEnclosingClassIndex(final int idx) {
+ classIndex = idx;
+ }
+
public final ConstantNameAndType getEnclosingMethod() {
if (methodIndex == 0) {
return null;
@@ -92,10 +96,6 @@ public class EnclosingMethod extends Attribute {
return methodIndex;
}
- public final void setEnclosingClassIndex(final int idx) {
- classIndex = idx;
- }
-
public final void setEnclosingMethodIndex(final int idx) {
methodIndex = idx;
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java b/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java
index 51385bc..4b22ab8 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ExceptionTable.java
@@ -40,6 +40,7 @@ import java.util.Arrays;
* u2 exception_index_table[number_of_exceptions];
* }
*
+ *
* @see Code
*/
public final class ExceptionTable extends Attribute {
@@ -59,9 +60,9 @@ public final class ExceptionTable extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -75,10 +76,10 @@ public final class ExceptionTable extends Attribute {
}
/**
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
* @param exceptionIndexTable Table of indices in constant pool
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
@@ -132,6 +133,14 @@ public final class ExceptionTable extends Attribute {
return exceptionIndexTable;
}
+ /**
+ * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
+ * length.
+ */
+ public void setExceptionIndexTable(final int[] exceptionIndexTable) {
+ this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
+ }
+
/**
* @return class names of thrown exceptions
*/
@@ -148,14 +157,6 @@ public final class ExceptionTable extends Attribute {
return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
}
- /**
- * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
- * length.
- */
- public void setExceptionIndexTable(final int[] exceptionIndexTable) {
- this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
- }
-
/**
* @return String representation, i.e., a list of thrown exceptions.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java
index e1da2e5..59018b9 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/FieldOrMethod.java
@@ -50,16 +50,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
*/
@java.lang.Deprecated
protected int attributes_count; // No. of attributes
-
- // @since 6.0
- private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected ConstantPool constant_pool;
-
+ // @since 6.0
+ private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
private String signatureAttributeString;
private boolean searchedForSignatureAttribute;
@@ -105,14 +102,14 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
/**
- * @param accessFlags Access rights of method
- * @param nameIndex Points to field name in constant pool
+ * @param accessFlags Access rights of method
+ * @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
- * @param attributes Collection of attributes
- * @param constantPool Array of constants
+ * @param attributes Collection of attributes
+ * @param constantPool Array of constants
*/
protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
- final ConstantPool constantPool) {
+ final ConstantPool constantPool) {
super(accessFlags);
this.name_index = nameIndex;
this.signature_index = signatureIndex;
@@ -173,6 +170,14 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return attributes;
}
+ /**
+ * @param attributes Collection of object attributes.
+ */
+ public final void setAttributes(final Attribute[] attributes) {
+ this.attributes = attributes;
+ this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field
+ }
+
/**
* @return Constant pool used by this object.
*/
@@ -180,6 +185,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return constant_pool;
}
+ /**
+ * @param constantPool Constant pool to be used for this object.
+ */
+ public final void setConstantPool(final ConstantPool constantPool) {
+ this.constant_pool = constantPool;
+ }
+
/**
* Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
* (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' Coded for
@@ -215,6 +227,13 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return name_index;
}
+ /**
+ * @param nameIndex Index in constant pool of object's name.
+ */
+ public final void setNameIndex(final int nameIndex) {
+ this.name_index = nameIndex;
+ }
+
/**
* @return String representation of object's type signature (java style)
*/
@@ -229,28 +248,6 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
return signature_index;
}
- /**
- * @param attributes Collection of object attributes.
- */
- public final void setAttributes(final Attribute[] attributes) {
- this.attributes = attributes;
- this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field
- }
-
- /**
- * @param constantPool Constant pool to be used for this object.
- */
- public final void setConstantPool(final ConstantPool constantPool) {
- this.constant_pool = constantPool;
- }
-
- /**
- * @param nameIndex Index in constant pool of object's name.
- */
- public final void setNameIndex(final int nameIndex) {
- this.name_index = nameIndex;
- }
-
/**
* @param signatureIndex Index in constant pool of field signature.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java b/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java
index 719e8ba..edf3529 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/InnerClass.java
@@ -55,9 +55,9 @@ public final class InnerClass implements Cloneable, Node {
}
/**
- * @param innerClassIndex Class index in constant pool of inner class
- * @param outerClassIndex Class index in constant pool of outer class
- * @param innerNameIndex Name index in constant pool of inner class
+ * @param innerClassIndex Class index in constant pool of inner class
+ * @param outerClassIndex Class index in constant pool of outer class
+ * @param innerNameIndex Name index in constant pool of inner class
* @param innerAccessFlags Access flags of inner class
*/
public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) {
@@ -110,27 +110,6 @@ public final class InnerClass implements Cloneable, Node {
return innerAccessFlags;
}
- /**
- * @return class index of inner class.
- */
- public int getInnerClassIndex() {
- return innerClassIndex;
- }
-
- /**
- * @return name index of inner class.
- */
- public int getInnerNameIndex() {
- return innerNameIndex;
- }
-
- /**
- * @return class index of outer class.
- */
- public int getOuterClassIndex() {
- return outerClassIndex;
- }
-
/**
* @param innerAccessFlags access flags for this inner class
*/
@@ -138,6 +117,13 @@ public final class InnerClass implements Cloneable, Node {
this.innerAccessFlags = innerAccessFlags;
}
+ /**
+ * @return class index of inner class.
+ */
+ public int getInnerClassIndex() {
+ return innerClassIndex;
+ }
+
/**
* @param innerClassIndex index into the constant pool for this class
*/
@@ -145,6 +131,13 @@ public final class InnerClass implements Cloneable, Node {
this.innerClassIndex = innerClassIndex;
}
+ /**
+ * @return name index of inner class.
+ */
+ public int getInnerNameIndex() {
+ return innerNameIndex;
+ }
+
/**
* @param innerNameIndex index into the constant pool for this class's name
*/
@@ -152,6 +145,13 @@ public final class InnerClass implements Cloneable, Node {
this.innerNameIndex = innerNameIndex;
}
+ /**
+ * @return class index of outer class.
+ */
+ public int getOuterClassIndex() {
+ return outerClassIndex;
+ }
+
/**
* @param outerClassIndex index into the constant pool for the owning class
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java b/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java
index 398d2c1..b3b7b33 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/InnerClasses.java
@@ -54,9 +54,9 @@ public final class InnerClasses extends Attribute implements Iterable iterator() {
- return Stream.of(innerClasses).iterator();
- }
-
/**
* @param innerClasses the array of inner classes
*/
@@ -139,6 +134,11 @@ public final class InnerClasses extends Attribute implements Iterable iterator() {
+ return Stream.of(innerClasses).iterator();
+ }
+
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java b/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java
index c0076b8..0150703 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/JavaClass.java
@@ -23,6 +23,9 @@ import haidnor.jvm.bcel.util.BCELComparator;
import haidnor.jvm.bcel.util.ClassQueue;
import haidnor.jvm.bcel.util.Repository;
import haidnor.jvm.bcel.util.SyntheticRepository;
+import haidnor.jvm.classloader.JVMClassLoader;
+import lombok.Getter;
+import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils;
import java.io.*;
@@ -71,41 +74,10 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return THIS.getClassName().hashCode();
}
};
-
- /*
- * Print debug information depending on 'JavaClass.debug'
- */
- static void Debug(final String str) {
- if (debug) {
- System.out.println(str);
- }
- }
-
- /**
- * @return Comparison strategy object
- */
- public static BCELComparator getComparator() {
- return bcelComparator;
- }
-
- private static String indent(final Object obj) {
- final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n");
- final StringBuilder buf = new StringBuilder();
- while (tokenizer.hasMoreTokens()) {
- buf.append("\t").append(tokenizer.nextToken()).append("\n");
- }
- return buf.toString();
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
-
- private String fileName;
private final String packageName;
+ @Getter
+ private final Map staticJavaFieldMap = new HashMap<>();
+ private String fileName;
private String sourceFileName = "";
private int classNameIndex;
private int superclassNameIndex;
@@ -119,36 +91,38 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
private JavaField[] fields; // Fields, i.e., variables of class
private JavaMethod[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class
-
private AnnotationEntry[] annotations; // annotations defined on the class
private byte source = HEAP; // Generated in memory
-
private boolean isAnonymous;
-
private boolean isNested;
-
private boolean computedNestedTypeStatus;
+ // ---------------------------------------------- haidnorJVM >
/**
* In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any
* better.
*/
private transient Repository repository = SyntheticRepository.getInstance();
+ @Getter
+ @Setter
+ private JVMClassLoader JVMClassLoader;
+
+ // ---------------------------------------------- haidnorJVM <
/**
* Constructor gets all contents as arguments.
*
- * @param classNameIndex Class name
+ * @param classNameIndex Class name
* @param superclassNameIndex Superclass name
- * @param fileName File name
- * @param major Major compiler version
- * @param minor Minor compiler version
- * @param accessFlags Access rights defined by bit flags
- * @param constantPool Array of constants
- * @param interfaces Implemented interfaces
- * @param fields Class fields
- * @param methods Class methods
- * @param attributes Class attributes
+ * @param fileName File name
+ * @param major Major compiler version
+ * @param minor Minor compiler version
+ * @param accessFlags Access rights defined by bit flags
+ * @param constantPool Array of constants
+ * @param interfaces Implemented interfaces
+ * @param fields Class fields
+ * @param methods Class methods
+ * @param attributes Class attributes
*/
public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
final ConstantPool constantPool, final int[] interfaces, final JavaField[] fields, final JavaMethod[] methods, final Attribute[] attributes) {
@@ -158,19 +132,19 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
/**
* Constructor gets all contents as arguments.
*
- * @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class.
+ * @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class.
* @param superclassNameIndex Index into constant pool referencing a ConstantClass that represents this class's
- * superclass.
- * @param fileName File name
- * @param major Major compiler version
- * @param minor Minor compiler version
- * @param accessFlags Access rights defined by bit flags
- * @param constantPool Array of constants
- * @param interfaces Implemented interfaces
- * @param fields Class fields
- * @param methods Class methods
- * @param attributes Class attributes
- * @param source Read from file or generated in memory?
+ * superclass.
+ * @param fileName File name
+ * @param major Major compiler version
+ * @param minor Minor compiler version
+ * @param accessFlags Access rights defined by bit flags
+ * @param constantPool Array of constants
+ * @param interfaces Implemented interfaces
+ * @param fields Class fields
+ * @param methods Class methods
+ * @param attributes Class attributes
+ * @param source Read from file or generated in memory?
*/
public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
final ConstantPool constantPool, int[] interfaces, JavaField[] fields, JavaMethod[] methods, Attribute[] attributes, final byte source) {
@@ -229,6 +203,45 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class);
interfaceNames[i] = Utility.compactClassName(str, false);
}
+
+ // 初始化静态字段
+ for (JavaField field : getFields()) {
+ if (field.isStatic()) {
+ staticJavaFieldMap.put(field.getName(), field);
+ }
+ }
+ }
+
+ /*
+ * Print debug information depending on 'JavaClass.debug'
+ */
+ static void Debug(final String str) {
+ if (debug) {
+ System.out.println(str);
+ }
+ }
+
+ /**
+ * @return Comparison strategy object
+ */
+ public static BCELComparator getComparator() {
+ return bcelComparator;
+ }
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
+ private static String indent(final Object obj) {
+ final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n");
+ final StringBuilder buf = new StringBuilder();
+ while (tokenizer.hasMoreTokens()) {
+ buf.append("\t").append(tokenizer.nextToken()).append("\n");
+ }
+ return buf.toString();
}
/**
@@ -258,7 +271,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
for (final Attribute attribute : this.attributes) {
if (attribute instanceof InnerClasses) {
- ((InnerClasses) attribute).forEach(innerClass -> {
+ ((InnerClasses) attribute).forEach(innerClass -> {
boolean innerClassAttributeRefersToMe = false;
String innerClassName = constantPool.getConstantString(innerClass.getInnerClassIndex(), Const.CONSTANT_Class);
innerClassName = Utility.compactClassName(innerClassName, false);
@@ -429,6 +442,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return attributes;
}
+ /**
+ * @param attributes .
+ */
+ public void setAttributes(final Attribute[] attributes) {
+ this.attributes = attributes;
+ }
+
/**
* @return class in binary format
*/
@@ -449,6 +469,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return className;
}
+ /**
+ * @param className .
+ */
+ public void setClassName(final String className) {
+ this.className = className;
+ }
+
/**
* @return Class name index.
*/
@@ -456,6 +483,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return classNameIndex;
}
+ /**
+ * @param classNameIndex .
+ */
+ public void setClassNameIndex(final int classNameIndex) {
+ this.classNameIndex = classNameIndex;
+ }
+
/**
* @return Constant pool.
*/
@@ -463,14 +497,28 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return constantPool;
}
+ /**
+ * @param constantPool .
+ */
+ public void setConstantPool(final ConstantPool constantPool) {
+ this.constantPool = constantPool;
+ }
+
/**
* @return Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are
- * those specific to this class, and not those of the superclass or superinterfaces.
+ * those specific to this class, and not those of the superclass or superinterfaces.
*/
public JavaField[] getFields() {
return fields;
}
+ /**
+ * @param fields .
+ */
+ public void setFields(final JavaField[] fields) {
+ this.fields = fields;
+ }
+
/**
* @return File name of class, aka SourceFile attribute value
*/
@@ -478,6 +526,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return fileName;
}
+ /**
+ * Set File name of class, aka SourceFile attribute value
+ */
+ public void setFileName(final String fileName) {
+ this.fileName = fileName;
+ }
+
/**
* @return Indices in constant pool of implemented interfaces.
*/
@@ -492,6 +547,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return interfaceNames;
}
+ /**
+ * @param interfaceNames .
+ */
+ public void setInterfaceNames(final String[] interfaceNames) {
+ this.interfaceNames = interfaceNames;
+ }
+
/**
* Get interfaces directly implemented by this JavaClass.
*
@@ -506,6 +568,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return classes;
}
+ /**
+ * @param interfaces .
+ */
+ public void setInterfaces(final int[] interfaces) {
+ this.interfaces = interfaces;
+ }
+
/**
* @return Major number of class file version.
*/
@@ -513,6 +582,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return major;
}
+ /**
+ * @param major .
+ */
+ public void setMajor(final int major) {
+ this.major = major;
+ }
+
/**
* @return A {@link JavaMethod} corresponding to java.lang.reflect.Method if any
*/
@@ -532,6 +608,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return methods;
}
+ /**
+ * @param methods .
+ */
+ public void setMethods(final JavaMethod[] methods) {
+ this.methods = methods;
+ }
+
/**
* @return Minor number of class file version.
*/
@@ -539,6 +622,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return minor;
}
+ /**
+ * @param minor .
+ */
+ public void setMinor(final int minor) {
+ this.minor = minor;
+ }
+
/**
* @return Package name.
*/
@@ -554,6 +644,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return repository;
}
+ /**
+ * Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
+ */
+ public void setRepository(final Repository repository) { // TODO make protected?
+ this.repository = repository;
+ }
+
/**
* @return returns either HEAP (generated), FILE, or ZIP
*/
@@ -568,6 +665,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return sourceFileName;
}
+ /**
+ * Set absolute path to file this class was read from.
+ */
+ public void setSourceFileName(final String sourceFileName) {
+ this.sourceFileName = sourceFileName;
+ }
+
/**
* Gets the source file path including the package path.
*
@@ -618,6 +722,13 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return superclassName;
}
+ /**
+ * @param superclassName .
+ */
+ public void setSuperclassName(final String superclassName) {
+ this.superclassName = superclassName;
+ }
+
/**
* @return Class name index.
*/
@@ -625,6 +736,17 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return superclassNameIndex;
}
+ /**
+ * @param superclassNameIndex .
+ */
+ public void setSuperclassNameIndex(final int superclassNameIndex) {
+ this.superclassNameIndex = superclassNameIndex;
+ }
+
+ public JavaField getStaticField(String filedName) {
+ return staticJavaFieldMap.get(filedName);
+ }
+
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name.
*
@@ -700,111 +822,6 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
return (super.getAccessFlags() & Const.ACC_SUPER) != 0;
}
- /**
- * @param attributes .
- */
- public void setAttributes(final Attribute[] attributes) {
- this.attributes = attributes;
- }
-
- /**
- * @param className .
- */
- public void setClassName(final String className) {
- this.className = className;
- }
-
- /**
- * @param classNameIndex .
- */
- public void setClassNameIndex(final int classNameIndex) {
- this.classNameIndex = classNameIndex;
- }
-
- /**
- * @param constantPool .
- */
- public void setConstantPool(final ConstantPool constantPool) {
- this.constantPool = constantPool;
- }
-
- /**
- * @param fields .
- */
- public void setFields(final JavaField[] fields) {
- this.fields = fields;
- }
-
- /**
- * Set File name of class, aka SourceFile attribute value
- */
- public void setFileName(final String fileName) {
- this.fileName = fileName;
- }
-
- /**
- * @param interfaceNames .
- */
- public void setInterfaceNames(final String[] interfaceNames) {
- this.interfaceNames = interfaceNames;
- }
-
- /**
- * @param interfaces .
- */
- public void setInterfaces(final int[] interfaces) {
- this.interfaces = interfaces;
- }
-
- /**
- * @param major .
- */
- public void setMajor(final int major) {
- this.major = major;
- }
-
- /**
- * @param methods .
- */
- public void setMethods(final JavaMethod[] methods) {
- this.methods = methods;
- }
-
- /**
- * @param minor .
- */
- public void setMinor(final int minor) {
- this.minor = minor;
- }
-
- /**
- * Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
- */
- public void setRepository(final Repository repository) { // TODO make protected?
- this.repository = repository;
- }
-
- /**
- * Set absolute path to file this class was read from.
- */
- public void setSourceFileName(final String sourceFileName) {
- this.sourceFileName = sourceFileName;
- }
-
- /**
- * @param superclassName .
- */
- public void setSuperclassName(final String superclassName) {
- this.superclassName = superclassName;
- }
-
- /**
- * @param superclassNameIndex .
- */
- public void setSuperclassNameIndex(final int superclassNameIndex) {
- this.superclassNameIndex = superclassNameIndex;
- }
-
/**
* @return String representing class contents.
*/
@@ -814,7 +831,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
access = access.isEmpty() ? "" : access + " ";
final StringBuilder buf = new StringBuilder(128);
buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(className).append(" extends ")
- .append(Utility.compactClassName(superclassName, false)).append('\n');
+ .append(Utility.compactClassName(superclassName, false)).append('\n');
final int size = interfaces.length;
if (size > 0) {
buf.append("implements\t\t");
@@ -859,4 +876,20 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
return buf.toString();
}
+
+ // ---------------------------------------------- haidnorJVM
+
+ /**
+ * 获取 main 方法
+ */
+ public JavaMethod getMainMethod() {
+ for (JavaMethod javaMethod : getMethods()) {
+ if (javaMethod.toString().startsWith("public static void main(String[] args)")) {
+ return javaMethod;
+ }
+ }
+ return null;
+ }
+
+
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java b/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java
index cf1f7fd..71d326c 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/JavaField.java
@@ -28,7 +28,7 @@ import java.util.Objects;
* This class represents the field info structure, i.e., the representation for a variable in the class. See JVM
* specification for details.
*/
-public final class JavaField extends FieldOrMethod {
+public class JavaField extends FieldOrMethod {
/**
* Empty array constant.
@@ -36,7 +36,10 @@ public final class JavaField extends FieldOrMethod {
* @since 6.6.0
*/
public static final JavaField[] EMPTY_ARRAY = {};
-
+ /**
+ * Empty array.
+ */
+ static final JavaField[] EMPTY_FIELD_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() {
@Override
@@ -52,25 +55,14 @@ public final class JavaField extends FieldOrMethod {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
}
};
-
/**
- * Empty array.
+ * 值类型
*/
- static final JavaField[] EMPTY_FIELD_ARRAY = {};
-
+ private int valueType;
/**
- * @return Comparison strategy object
+ * 值
*/
- public static BCELComparator getComparator() {
- return bcelComparator;
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
+ private Object value;
/**
* Construct object from file stream.
@@ -92,16 +84,30 @@ public final class JavaField extends FieldOrMethod {
}
/**
- * @param accessFlags Access rights of field
- * @param nameIndex Points to field name in constant pool
+ * @param accessFlags Access rights of field
+ * @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
- * @param attributes Collection of attributes
- * @param constantPool Array of constants
+ * @param attributes Collection of attributes
+ * @param constantPool Array of constants
*/
public JavaField(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
}
+ /**
+ * @return Comparison strategy object
+ */
+ public static BCELComparator getComparator() {
+ return bcelComparator;
+ }
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
@@ -150,6 +156,22 @@ public final class JavaField extends FieldOrMethod {
return Type.getReturnType(getSignature());
}
+ public int getValueType() {
+ return valueType;
+ }
+
+ public void setValueType(int valueType) {
+ this.valueType = valueType;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
* signature.
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java b/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java
index d83f245..4f2e62d 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/JavaMethod.java
@@ -27,7 +27,7 @@ import java.util.Objects;
* This class represents the method info structure, i.e., the representation for a method in the class. See JVM
* specification for details. A method has access flags, a name, a signature and a number of attributes.
*/
-public final class JavaMethod extends FieldOrMethod {
+public class JavaMethod extends FieldOrMethod {
/**
* Empty array constant.
@@ -35,7 +35,10 @@ public final class JavaMethod extends FieldOrMethod {
* @since 6.6.0
*/
public static final JavaMethod[] EMPTY_ARRAY = {};
-
+ /**
+ * Empty array.
+ */
+ static final JavaMethod[] EMPTY_METHOD_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() {
@Override
@@ -51,26 +54,6 @@ public final class JavaMethod extends FieldOrMethod {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
}
};
-
- /**
- * Empty array.
- */
- static final JavaMethod[] EMPTY_METHOD_ARRAY = {};
-
- /**
- * @return Comparison strategy object
- */
- public static BCELComparator getComparator() {
- return bcelComparator;
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
-
// annotations defined on the parameters of a method
private ParameterAnnotationEntry[] parameterAnnotationEntries;
@@ -84,7 +67,7 @@ public final class JavaMethod extends FieldOrMethod {
* Construct object from file stream.
*
* @param file Input stream
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
JavaMethod(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
@@ -92,11 +75,11 @@ public final class JavaMethod extends FieldOrMethod {
}
/**
- * @param accessFlags Access rights of method
- * @param nameIndex Points to field name in constant pool
+ * @param accessFlags Access rights of method
+ * @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
- * @param attributes Collection of attributes
- * @param constantPool Array of constants
+ * @param attributes Collection of attributes
+ * @param constantPool Array of constants
*/
public JavaMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
@@ -112,6 +95,20 @@ public final class JavaMethod extends FieldOrMethod {
super(c);
}
+ /**
+ * @return Comparison strategy object
+ */
+ public static BCELComparator getComparator() {
+ return bcelComparator;
+ }
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
@@ -162,7 +159,7 @@ public final class JavaMethod extends FieldOrMethod {
/**
* @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
- * handlers!
+ * handlers!
*/
public ExceptionTable getExceptionTable() {
for (final Attribute attribute : super.getAttributes()) {
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java b/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java
index 8f45505..7be245d 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/LineNumber.java
@@ -32,10 +32,14 @@ public final class LineNumber implements Cloneable, Node {
static final LineNumber[] EMPTY_ARRAY = {};
- /** Program Counter (PC) corresponds to line */
+ /**
+ * Program Counter (PC) corresponds to line
+ */
private int startPc;
- /** number in source file */
+ /**
+ * number in source file
+ */
private int lineNumber;
/**
@@ -49,7 +53,7 @@ public final class LineNumber implements Cloneable, Node {
}
/**
- * @param startPc Program Counter (PC) corresponds to
+ * @param startPc Program Counter (PC) corresponds to
* @param lineNumber line number in source file
*/
public LineNumber(final int startPc, final int lineNumber) {
@@ -107,13 +111,6 @@ public final class LineNumber implements Cloneable, Node {
return lineNumber & 0xffff;
}
- /**
- * @return PC in code
- */
- public int getStartPC() {
- return startPc & 0xffff;
- }
-
/**
* @param lineNumber the source line number
*/
@@ -121,6 +118,13 @@ public final class LineNumber implements Cloneable, Node {
this.lineNumber = (short) lineNumber;
}
+ /**
+ * @return PC in code
+ */
+ public int getStartPC() {
+ return startPc & 0xffff;
+ }
+
/**
* @param startPc the pc for this line number
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java b/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java
index 28ec9f9..702e0b6 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/LineNumberTable.java
@@ -41,9 +41,9 @@ public final class LineNumberTable extends Attribute implements Iterable
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package haidnor.jvm.bcel.classfile;
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java
index 0b0e9ca..c49446a 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameter.java
@@ -27,15 +27,19 @@ import java.io.IOException;
* Entry of the parameters table.
*
* @see The class File Format :
- * The MethodParameters Attribute
+ * The MethodParameters Attribute
* @since 6.0
*/
public class MethodParameter implements Cloneable, Node {
- /** Index of the CONSTANT_Utf8_info structure in the constant_pool table representing the name of the parameter */
+ /**
+ * Index of the CONSTANT_Utf8_info structure in the constant_pool table representing the name of the parameter
+ */
private int nameIndex;
- /** The access flags */
+ /**
+ * The access flags
+ */
private int accessFlags;
public MethodParameter() {
@@ -45,7 +49,7 @@ public class MethodParameter implements Cloneable, Node {
* Construct object from input stream.
*
* @param input Input stream
- * @throws IOException if an I/O error occurs.
+ * @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
MethodParameter(final DataInput input) throws IOException {
@@ -85,10 +89,18 @@ public class MethodParameter implements Cloneable, Node {
return accessFlags;
}
+ public void setAccessFlags(final int accessFlags) {
+ this.accessFlags = accessFlags;
+ }
+
public int getNameIndex() {
return nameIndex;
}
+ public void setNameIndex(final int nameIndex) {
+ this.nameIndex = nameIndex;
+ }
+
/**
* Returns the name of the parameter.
*/
@@ -110,12 +122,4 @@ public class MethodParameter implements Cloneable, Node {
public boolean isSynthetic() {
return (accessFlags & Const.ACC_SYNTHETIC) != 0;
}
-
- public void setAccessFlags(final int accessFlags) {
- this.accessFlags = accessFlags;
- }
-
- public void setNameIndex(final int nameIndex) {
- this.nameIndex = nameIndex;
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java
index 86b6337..0ca62b1 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/MethodParameters.java
@@ -30,7 +30,7 @@ import java.util.stream.Stream;
* This class represents a MethodParameters attribute.
*
* @see The class File Format :
- * The MethodParameters Attribute
+ * The MethodParameters Attribute
* @since 6.0
*/
public class MethodParameters extends Attribute implements Iterable {
@@ -86,12 +86,12 @@ public class MethodParameters extends Attribute implements Iterable iterator() {
return Stream.of(parameters).iterator();
}
-
- public void setParameters(final MethodParameter[] parameters) {
- this.parameters = parameters;
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Module.java b/src/main/java/haidnor/jvm/bcel/classfile/Module.java
index b4379ca..19f22cf 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Module.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Module.java
@@ -43,20 +43,19 @@ public final class Module extends Attribute {
private final int moduleNameIndex;
private final int moduleFlags;
private final int moduleVersionIndex;
-
+ private final int usesCount;
+ private final int[] usesIndex;
private ModuleRequires[] requiresTable;
private ModuleExports[] exportsTable;
private ModuleOpens[] opensTable;
- private final int usesCount;
- private final int[] usesIndex;
private ModuleProvides[] providesTable;
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java b/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java
index 37c3d8b..8e39f59 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ModuleMainClass.java
@@ -37,9 +37,9 @@ public final class ModuleMainClass extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -49,10 +49,10 @@ public final class ModuleMainClass extends Attribute {
}
/**
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
* @param mainClassIndex Host class index
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public ModuleMainClass(final int nameIndex, final int length, final int mainClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java b/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java
index 2bce0ba..66b5af3 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ModulePackages.java
@@ -39,9 +39,9 @@ public final class ModulePackages extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -55,10 +55,10 @@ public final class ModulePackages extends Attribute {
}
/**
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
* @param packageIndexTable Table of indices in constant pool
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool);
@@ -129,6 +129,13 @@ public final class ModulePackages extends Attribute {
return packageIndexTable;
}
+ /**
+ * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
+ */
+ public void setPackageIndexTable(final int[] packageIndexTable) {
+ this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
+ }
+
/**
* @return string array of package names
*/
@@ -138,13 +145,6 @@ public final class ModulePackages extends Attribute {
return names;
}
- /**
- * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
- */
- public void setPackageIndexTable(final int[] packageIndexTable) {
- this.packageIndexTable = packageIndexTable != null ? packageIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
- }
-
/**
* @return String representation, i.e., a list of packages.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java b/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java
index 6f3e654..c62c73b 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/NestHost.java
@@ -37,9 +37,9 @@ public final class NestHost extends Attribute {
/**
* Constructs object from input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -49,10 +49,10 @@ public final class NestHost extends Attribute {
}
/**
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
* @param hostClassIndex Host class index
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public NestHost(final int nameIndex, final int length, final int hostClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java b/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java
index 1019688..479e69a 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/NestMembers.java
@@ -40,9 +40,9 @@ public final class NestMembers extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -56,9 +56,9 @@ public final class NestMembers extends Attribute {
}
/**
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param classes Table of indices in constant pool
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param classes Table of indices in constant pool
* @param constantPool Array of constants
*/
public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) {
@@ -123,6 +123,13 @@ public final class NestMembers extends Attribute {
return classes;
}
+ /**
+ * @param classes the list of class indexes Also redefines number_of_classes according to table length.
+ */
+ public void setClasses(final int[] classes) {
+ this.classes = classes != null ? classes : ArrayUtils.EMPTY_INT_ARRAY;
+ }
+
/**
* @return string array of class names
*/
@@ -139,13 +146,6 @@ public final class NestMembers extends Attribute {
return classes.length;
}
- /**
- * @param classes the list of class indexes Also redefines number_of_classes according to table length.
- */
- public void setClasses(final int[] classes) {
- this.classes = classes != null ? classes : ArrayUtils.EMPTY_INT_ARRAY;
- }
-
/**
* @return String representation, i.e., a list of classes.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java b/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java
index 87ecb31..bba4af8 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/PMGClass.java
@@ -35,9 +35,9 @@ public final class PMGClass extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -46,11 +46,11 @@ public final class PMGClass extends Attribute {
}
/**
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param pmgIndex index in constant pool for source file name
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param pmgIndex index in constant pool for source file name
* @param pmgClassIndex Index in constant pool to CONSTANT_Utf8
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public PMGClass(final int nameIndex, final int length, final int pmgIndex, final int pmgClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_PMG, nameIndex, length, constantPool);
@@ -107,6 +107,13 @@ public final class PMGClass extends Attribute {
return pmgClassIndex;
}
+ /**
+ * @param pmgClassIndex
+ */
+ public void setPMGClassIndex(final int pmgClassIndex) {
+ this.pmgClassIndex = pmgClassIndex;
+ }
+
/**
* @return PMG class name.
*/
@@ -121,20 +128,6 @@ public final class PMGClass extends Attribute {
return pmgIndex;
}
- /**
- * @return PMG name.
- */
- public String getPMGName() {
- return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
- }
-
- /**
- * @param pmgClassIndex
- */
- public void setPMGClassIndex(final int pmgClassIndex) {
- this.pmgClassIndex = pmgClassIndex;
- }
-
/**
* @param pmgIndex
*/
@@ -142,6 +135,13 @@ public final class PMGClass extends Attribute {
this.pmgIndex = pmgIndex;
}
+ /**
+ * @return PMG name.
+ */
+ public String getPMGName() {
+ return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
+ }
+
/**
* @return String representation
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java
index 99b1397..f236066 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotationEntry.java
@@ -31,19 +31,6 @@ import java.util.List;
public class ParameterAnnotationEntry implements Node {
static final ParameterAnnotationEntry[] EMPTY_ARRAY = {};
-
- public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) {
- // Find attributes that contain parameter annotation data
- final List accumulatedAnnotations = new ArrayList<>(attrs.length);
- for (final Attribute attribute : attrs) {
- if (attribute instanceof ParameterAnnotations) {
- final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute;
- Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries());
- }
- }
- return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY);
- }
-
private final AnnotationEntry[] annotationTable;
/**
@@ -61,6 +48,18 @@ public class ParameterAnnotationEntry implements Node {
}
}
+ public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) {
+ // Find attributes that contain parameter annotation data
+ final List accumulatedAnnotations = new ArrayList<>(attrs.length);
+ for (final Attribute attribute : attrs) {
+ if (attribute instanceof ParameterAnnotations) {
+ final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute;
+ Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries());
+ }
+ }
+ return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY);
+ }
+
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java
index 8b3071c..15c61af 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/ParameterAnnotations.java
@@ -29,18 +29,20 @@ import java.util.stream.Stream;
*/
public abstract class ParameterAnnotations extends Attribute implements Iterable {
- /** Table of parameter annotations */
+ /**
+ * Table of parameter annotations
+ */
private ParameterAnnotationEntry[] parameterAnnotationTable;
/**
* @param parameterAnnotationType the subclass type of the parameter annotation
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param input Input stream
- * @param constantPool Array of constants
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param input Input stream
+ * @param constantPool Array of constants
*/
ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
- throws IOException {
+ throws IOException {
this(parameterAnnotationType, nameIndex, length, (ParameterAnnotationEntry[]) null, constantPool);
final int numParameters = input.readUnsignedByte();
parameterAnnotationTable = new ParameterAnnotationEntry[numParameters];
@@ -50,14 +52,14 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
}
/**
- * @param parameterAnnotationType the subclass type of the parameter annotation
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
+ * @param parameterAnnotationType the subclass type of the parameter annotation
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
* @param parameterAnnotationTable the actual parameter annotations
- * @param constantPool Array of constants
+ * @param constantPool Array of constants
*/
public ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length,
- final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) {
+ final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) {
super(parameterAnnotationType, nameIndex, length, constantPool);
this.parameterAnnotationTable = parameterAnnotationTable;
}
@@ -106,15 +108,15 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
return parameterAnnotationTable;
}
- @Override
- public Iterator iterator() {
- return Stream.of(parameterAnnotationTable).iterator();
- }
-
/**
* @param parameterAnnotationTable the entries to set in this parameter annotation
*/
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) {
this.parameterAnnotationTable = parameterAnnotationTable;
}
+
+ @Override
+ public Iterator iterator() {
+ return Stream.of(parameterAnnotationTable).iterator();
+ }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java
index 4120d07..7f80e3b 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleAnnotations.java
@@ -30,9 +30,9 @@ import java.io.IOException;
public class RuntimeInvisibleAnnotations extends Annotations {
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
index cd799b5..4cfdd42 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeInvisibleParameterAnnotations.java
@@ -29,14 +29,14 @@ import java.io.IOException;
public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations {
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
- throws IOException {
+ throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java
index b523905..5a4049d 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleAnnotations.java
@@ -30,9 +30,9 @@ import java.io.IOException;
public class RuntimeVisibleAnnotations extends Annotations {
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java
index 2e311cd..b3a0800 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/RuntimeVisibleParameterAnnotations.java
@@ -29,14 +29,14 @@ import java.io.IOException;
public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations {
/**
- * @param nameIndex Index pointing to the name Code
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index pointing to the name Code
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeVisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
- throws IOException {
+ throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Signature.java b/src/main/java/haidnor/jvm/bcel/classfile/Signature.java
index ca0b000..d47bfd6 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Signature.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Signature.java
@@ -33,24 +33,42 @@ import java.util.Objects;
*/
public final class Signature extends Attribute {
+ private int signatureIndex;
+
/**
- * Extends ByteArrayInputStream to make 'unreading' chars possible.
+ * Construct object from file stream.
+ *
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param input Input stream
+ * @param constantPool Array of constants
+ * @throws IOException if an I/O error occurs.
*/
- private static final class MyByteArrayInputStream extends ByteArrayInputStream {
+ Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
+ this(nameIndex, length, input.readUnsignedShort(), constantPool);
+ }
- MyByteArrayInputStream(final String data) {
- super(data.getBytes(StandardCharsets.UTF_8));
- }
+ /**
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param signatureIndex Index in constant pool to CONSTANT_Utf8
+ * @param constantPool Array of constants
+ */
+ public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
+ super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
+ this.signatureIndex = signatureIndex;
+ // validate:
+ Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
+ }
- String getData() {
- return new String(buf, StandardCharsets.UTF_8);
- }
-
- void unread() {
- if (pos > 0) {
- pos--;
- }
- }
+ /**
+ * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
+ * physical copy.
+ *
+ * @param c Source to copy.
+ */
+ public Signature(final Signature c) {
+ this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
}
private static boolean identStart(final int ch) {
@@ -152,44 +170,6 @@ public final class Signature extends Attribute {
return buf.toString();
}
- private int signatureIndex;
-
- /**
- * Construct object from file stream.
- *
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param input Input stream
- * @param constantPool Array of constants
- * @throws IOException if an I/O error occurs.
- */
- Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
- this(nameIndex, length, input.readUnsignedShort(), constantPool);
- }
-
- /**
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param signatureIndex Index in constant pool to CONSTANT_Utf8
- * @param constantPool Array of constants
- */
- public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
- super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
- this.signatureIndex = signatureIndex;
- // validate:
- Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
- }
-
- /**
- * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
- * physical copy.
- *
- * @param c Source to copy.
- */
- public Signature(final Signature c) {
- this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
- }
-
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
@@ -250,4 +230,24 @@ public final class Signature extends Attribute {
public String toString() {
return "Signature: " + getSignature();
}
+
+ /**
+ * Extends ByteArrayInputStream to make 'unreading' chars possible.
+ */
+ private static final class MyByteArrayInputStream extends ByteArrayInputStream {
+
+ MyByteArrayInputStream(final String data) {
+ super(data.getBytes(StandardCharsets.UTF_8));
+ }
+
+ String getData() {
+ return new String(buf, StandardCharsets.UTF_8);
+ }
+
+ void unread() {
+ if (pos > 0) {
+ pos--;
+ }
+ }
+ }
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java b/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java
index 892c35b..6a94d4c 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/SimpleElementValue.java
@@ -37,19 +37,19 @@ public class SimpleElementValue extends ElementValue {
final int type = super.getType();
dos.writeByte(type); // u1 kind of value
switch (type) {
- case PRIMITIVE_INT:
- case PRIMITIVE_BYTE:
- case PRIMITIVE_CHAR:
- case PRIMITIVE_FLOAT:
- case PRIMITIVE_LONG:
- case PRIMITIVE_BOOLEAN:
- case PRIMITIVE_SHORT:
- case PRIMITIVE_DOUBLE:
- case STRING:
- dos.writeShort(getIndex());
- break;
- default:
- throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type);
+ case PRIMITIVE_INT:
+ case PRIMITIVE_BYTE:
+ case PRIMITIVE_CHAR:
+ case PRIMITIVE_FLOAT:
+ case PRIMITIVE_LONG:
+ case PRIMITIVE_BOOLEAN:
+ case PRIMITIVE_SHORT:
+ case PRIMITIVE_DOUBLE:
+ case STRING:
+ dos.writeShort(getIndex());
+ break;
+ default:
+ throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type);
}
}
@@ -60,6 +60,10 @@ public class SimpleElementValue extends ElementValue {
return index;
}
+ public void setIndex(final int index) {
+ this.index = index;
+ }
+
public boolean getValueBoolean() {
if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue");
@@ -128,46 +132,42 @@ public class SimpleElementValue extends ElementValue {
return super.getConstantPool().getConstantUtf8(getIndex()).getBytes();
}
- public void setIndex(final int index) {
- this.index = index;
- }
-
// Whatever kind of value it is, return it as a string
@Override
public String stringifyValue() {
final ConstantPool cpool = super.getConstantPool();
final int type = super.getType();
switch (type) {
- case PRIMITIVE_INT:
- return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes());
- case PRIMITIVE_LONG:
- final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class);
- return Long.toString(j.getBytes());
- case PRIMITIVE_DOUBLE:
- final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class);
- return Double.toString(d.getBytes());
- case PRIMITIVE_FLOAT:
- final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class);
- return Float.toString(f.getBytes());
- case PRIMITIVE_SHORT:
- final ConstantInteger s = cpool.getConstantInteger(getIndex());
- return Integer.toString(s.getBytes());
- case PRIMITIVE_BYTE:
- final ConstantInteger b = cpool.getConstantInteger(getIndex());
- return Integer.toString(b.getBytes());
- case PRIMITIVE_CHAR:
- final ConstantInteger ch = cpool.getConstantInteger(getIndex());
- return String.valueOf((char) ch.getBytes());
- case PRIMITIVE_BOOLEAN:
- final ConstantInteger bo = cpool.getConstantInteger(getIndex());
- if (bo.getBytes() == 0) {
- return "false";
- }
- return "true";
- case STRING:
- return cpool.getConstantUtf8(getIndex()).getBytes();
- default:
- throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type);
+ case PRIMITIVE_INT:
+ return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes());
+ case PRIMITIVE_LONG:
+ final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class);
+ return Long.toString(j.getBytes());
+ case PRIMITIVE_DOUBLE:
+ final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class);
+ return Double.toString(d.getBytes());
+ case PRIMITIVE_FLOAT:
+ final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class);
+ return Float.toString(f.getBytes());
+ case PRIMITIVE_SHORT:
+ final ConstantInteger s = cpool.getConstantInteger(getIndex());
+ return Integer.toString(s.getBytes());
+ case PRIMITIVE_BYTE:
+ final ConstantInteger b = cpool.getConstantInteger(getIndex());
+ return Integer.toString(b.getBytes());
+ case PRIMITIVE_CHAR:
+ final ConstantInteger ch = cpool.getConstantInteger(getIndex());
+ return String.valueOf((char) ch.getBytes());
+ case PRIMITIVE_BOOLEAN:
+ final ConstantInteger bo = cpool.getConstantInteger(getIndex());
+ if (bo.getBytes() == 0) {
+ return "false";
+ }
+ return "true";
+ case STRING:
+ return cpool.getConstantUtf8(getIndex()).getBytes();
+ default:
+ throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java b/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java
index c61f9ed..6e2e1a2 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/SourceFile.java
@@ -37,9 +37,9 @@ public final class SourceFile extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -48,13 +48,13 @@ public final class SourceFile extends Attribute {
}
/**
- * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile".
- * @param length Content length in bytes, the value should be 2.
- * @param constantPool The constant pool that this attribute is associated with.
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile".
+ * @param length Content length in bytes, the value should be 2.
+ * @param constantPool The constant pool that this attribute is associated with.
* @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This string will be interpreted as the name of the
- * file from which this class was compiled. It will not be interpreted as indicating the name of the directory
- * contqining the file or an absolute path; this information has to be supplied the consumer of this attribute -
- * in many cases, the JVM.
+ * file from which this class was compiled. It will not be interpreted as indicating the name of the directory
+ * contqining the file or an absolute path; this information has to be supplied the consumer of this attribute -
+ * in many cases, the JVM.
*/
public SourceFile(final int nameIndex, final int length, final int sourceFileIndex, final ConstantPool constantPool) {
super(Const.ATTR_SOURCE_FILE, nameIndex, Args.require(length, 2, "SourceFile length attribute"), constantPool);
@@ -109,13 +109,6 @@ public final class SourceFile extends Attribute {
return sourceFileIndex;
}
- /**
- * @return Source file name.
- */
- public String getSourceFileName() {
- return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
- }
-
/**
* @param sourceFileIndex
*/
@@ -123,6 +116,13 @@ public final class SourceFile extends Attribute {
this.sourceFileIndex = sourceFileIndex;
}
+ /**
+ * @return Source file name.
+ */
+ public String getSourceFileName() {
+ return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
+ }
+
/**
* @return String representation
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java b/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java
index 543db9f..e6f7ef4 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/StackMap.java
@@ -50,9 +50,9 @@ public final class StackMap extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index of name
- * @param length Content length in bytes
- * @param dataInput Input stream
+ * @param nameIndex Index of name
+ * @param length Content length in bytes
+ * @param dataInput Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java b/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java
index 58413c7..65be1aa 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/StackMapEntry.java
@@ -27,7 +27,7 @@ import java.util.Arrays;
/**
* This class represents a stack map entry recording the types of local variables and the of stack items at a given
* byte code offset. See CLDC specification 5.3.1.2.
- *
+ *
* See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
*
*
@@ -41,6 +41,7 @@ import java.util.Arrays;
* full_frame;
* }
*
+ *
* @see StackMap
* @see StackMapType
*/
@@ -67,10 +68,10 @@ public final class StackMapEntry implements Node, Cloneable {
byteCodeOffset = frameType - Const.SAME_FRAME;
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = frameType - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
- typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
+ typesOfStackItems = new StackMapType[]{new StackMapType(dataInput, constantPool)};
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
byteCodeOffset = dataInput.readUnsignedShort();
- typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
+ typesOfStackItems = new StackMapType[]{new StackMapType(dataInput, constantPool)};
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
@@ -104,16 +105,16 @@ public final class StackMapEntry implements Node, Cloneable {
* DO NOT USE
*
* @param byteCodeOffset
- * @param numberOfLocals NOT USED
- * @param typesOfLocals array of {@link StackMapType}s of locals
+ * @param numberOfLocals NOT USED
+ * @param typesOfLocals array of {@link StackMapType}s of locals
* @param numberOfStackItems NOT USED
- * @param typesOfStackItems array ot {@link StackMapType}s of stack items
- * @param constantPool the constant pool
+ * @param typesOfStackItems array ot {@link StackMapType}s of stack items
+ * @param constantPool the constant pool
* @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} instead
*/
@java.lang.Deprecated
public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems,
- final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
+ final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
@@ -129,14 +130,14 @@ public final class StackMapEntry implements Node, Cloneable {
/**
* Create an instance
*
- * @param tag the frameType to use
+ * @param tag the frameType to use
* @param byteCodeOffset
- * @param typesOfLocals array of {@link StackMapType}s of locals
+ * @param typesOfLocals array of {@link StackMapType}s of locals
* @param typesOfStackItems array ot {@link StackMapType}s of stack items
- * @param constantPool the constant pool
+ * @param constantPool the constant pool
*/
public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems,
- final ConstantPool constantPool) {
+ final ConstantPool constantPool) {
this.frameType = tag;
this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
@@ -215,6 +216,29 @@ public final class StackMapEntry implements Node, Cloneable {
return byteCodeOffset;
}
+ public void setByteCodeOffset(final int newOffset) {
+ if (newOffset < 0 || newOffset > 32767) {
+ throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset);
+ }
+
+ if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
+ if (newOffset > Const.SAME_FRAME_MAX) {
+ frameType = Const.SAME_FRAME_EXTENDED;
+ } else {
+ frameType = newOffset;
+ }
+ } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
+ if (newOffset > Const.SAME_FRAME_MAX) {
+ frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
+ } else {
+ frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset;
+ }
+ } else if (invalidFrameType(frameType)) {
+ throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
+ }
+ byteCodeOffset = newOffset;
+ }
+
/**
* @return Constant pool used by this object.
*/
@@ -222,13 +246,30 @@ public final class StackMapEntry implements Node, Cloneable {
return constantPool;
}
+ /**
+ * @param constantPool Constant pool to be used for this object.
+ */
+ public void setConstantPool(final ConstantPool constantPool) {
+ this.constantPool = constantPool;
+ }
+
public int getFrameType() {
return frameType;
}
+ public void setFrameType(final int ft) {
+ if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) {
+ byteCodeOffset = ft - Const.SAME_FRAME;
+ } else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
+ byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
+ } else if (invalidFrameType(ft)) {
+ throw new IllegalArgumentException("Invalid StackMap frameType");
+ }
+ frameType = ft;
+ }
+
/**
* Calculate stack map entry size
- *
*/
int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
@@ -267,18 +308,40 @@ public final class StackMapEntry implements Node, Cloneable {
return typesOfLocals.length;
}
+ /**
+ * @deprecated since 6.0
+ */
+ @java.lang.Deprecated
+ public void setNumberOfLocals(final int n) { // TODO unused
+ }
+
public int getNumberOfStackItems() {
return typesOfStackItems.length;
}
+ /**
+ * @deprecated since 6.0
+ */
+ @java.lang.Deprecated
+ public void setNumberOfStackItems(final int n) { // TODO unused
+ }
+
public StackMapType[] getTypesOfLocals() {
return typesOfLocals;
}
+ public void setTypesOfLocals(final StackMapType[] types) {
+ typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
+ }
+
public StackMapType[] getTypesOfStackItems() {
return typesOfStackItems;
}
+ public void setTypesOfStackItems(final StackMapType[] types) {
+ typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
+ }
+
private boolean invalidFrameType(final int f) {
// @formatter:off
return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
@@ -289,71 +352,6 @@ public final class StackMapEntry implements Node, Cloneable {
// @formatter:on
}
- public void setByteCodeOffset(final int newOffset) {
- if (newOffset < 0 || newOffset > 32767) {
- throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset);
- }
-
- if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
- if (newOffset > Const.SAME_FRAME_MAX) {
- frameType = Const.SAME_FRAME_EXTENDED;
- } else {
- frameType = newOffset;
- }
- } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
- if (newOffset > Const.SAME_FRAME_MAX) {
- frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
- } else {
- frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset;
- }
- } else if (invalidFrameType(frameType)) {
- throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
- }
- byteCodeOffset = newOffset;
- }
-
- /**
- * @param constantPool Constant pool to be used for this object.
- */
- public void setConstantPool(final ConstantPool constantPool) {
- this.constantPool = constantPool;
- }
-
- public void setFrameType(final int ft) {
- if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) {
- byteCodeOffset = ft - Const.SAME_FRAME;
- } else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
- byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
- } else if (invalidFrameType(ft)) {
- throw new IllegalArgumentException("Invalid StackMap frameType");
- }
- frameType = ft;
- }
-
- /**
- *
- * @deprecated since 6.0
- */
- @java.lang.Deprecated
- public void setNumberOfLocals(final int n) { // TODO unused
- }
-
- /**
- *
- * @deprecated since 6.0
- */
- @java.lang.Deprecated
- public void setNumberOfStackItems(final int n) { // TODO unused
- }
-
- public void setTypesOfLocals(final StackMapType[] types) {
- typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
- }
-
- public void setTypesOfStackItems(final StackMapType[] types) {
- typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
- }
-
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java b/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java
index 6d3b61e..9033842 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/StackMapType.java
@@ -38,7 +38,7 @@ public final class StackMapType implements Cloneable {
private ConstantPool constantPool;
/**
- * @param type type tag as defined in the Constants interface
+ * @param type type tag as defined in the Constants interface
* @param index index to constant pool, or byte code offset
*/
public StackMapType(final byte type, final int index, final ConstantPool constantPool) {
@@ -100,18 +100,33 @@ public final class StackMapType implements Cloneable {
return constantPool;
}
+ /**
+ * @param constantPool Constant pool to be used for this object.
+ */
+ public void setConstantPool(final ConstantPool constantPool) {
+ this.constantPool = constantPool;
+ }
+
/**
* @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
- * otherwise
+ * otherwise
*/
public int getIndex() {
return index;
}
+ public void setIndex(final int index) {
+ this.index = index;
+ }
+
public byte getType() {
return type;
}
+ public void setType(final byte type) {
+ this.type = checkType(type);
+ }
+
/**
* @return true, if type is either ITEM_Object or ITEM_NewObject
*/
@@ -132,21 +147,6 @@ public final class StackMapType implements Cloneable {
return "";
}
- /**
- * @param constantPool Constant pool to be used for this object.
- */
- public void setConstantPool(final ConstantPool constantPool) {
- this.constantPool = constantPool;
- }
-
- public void setIndex(final int index) {
- this.index = index;
- }
-
- public void setType(final byte type) {
- this.type = checkType(type);
- }
-
/**
* @return String representation
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java b/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java
index f2e8864..9b74b4c 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Synthetic.java
@@ -36,9 +36,9 @@ public final class Synthetic extends Attribute {
private byte[] bytes;
/**
- * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic".
- * @param length Content length in bytes - should be zero.
- * @param bytes Attribute contents
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic".
+ * @param length Content length in bytes - should be zero.
+ * @param bytes Attribute contents
* @param constantPool The constant pool this attribute is associated with.
*/
public Synthetic(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
@@ -49,9 +49,9 @@ public final class Synthetic extends Attribute {
/**
* Construct object from input stream.
*
- * @param nameIndex Index in constant pool to CONSTANT_Utf8
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool to CONSTANT_Utf8
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java b/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java
index 84e59dc..9dbc3a1 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Unknown.java
@@ -34,16 +34,15 @@ import java.util.Arrays;
*/
public final class Unknown extends Attribute {
- private byte[] bytes;
-
private final String name;
+ private byte[] bytes;
/**
* Constructs a new instance for a non-standard attribute.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param bytes Attribute contents
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param bytes Attribute contents
* @param constantPool Array of constants
*/
public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
@@ -55,9 +54,9 @@ public final class Unknown extends Attribute {
/**
* Constructs a new instance from an input stream.
*
- * @param nameIndex Index in constant pool
- * @param length Content length in bytes
- * @param input Input stream
+ * @param nameIndex Index in constant pool
+ * @param length Content length in bytes
+ * @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
@@ -123,6 +122,13 @@ public final class Unknown extends Attribute {
return bytes;
}
+ /**
+ * @param bytes the bytes to set
+ */
+ public void setBytes(final byte[] bytes) {
+ this.bytes = bytes;
+ }
+
/**
* @return name of attribute.
*/
@@ -131,13 +137,6 @@ public final class Unknown extends Attribute {
return name;
}
- /**
- * @param bytes the bytes to set
- */
- public void setBytes(final byte[] bytes) {
- this.bytes = bytes;
- }
-
/**
* @return String representation.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java b/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java
index 7822992..eab6e14 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/UnknownAttributeReader.java
@@ -31,15 +31,13 @@ public interface UnknownAttributeReader {
* associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the
* name of the attributes it is constructing.
*
- * @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
- * @param length The length of the data contained in the attribute. This is written into the constant pool and should
- * agree with what the factory expects the length to be.
- * @param file This is the data input that the factory needs to read its data from.
+ * @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
+ * @param length The length of the data contained in the attribute. This is written into the constant pool and should
+ * agree with what the factory expects the length to be.
+ * @param file This is the data input that the factory needs to read its data from.
* @param constantPool This is the constant pool associated with the Attribute that we are constructing.
- *
* @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of
- * errors, a null can be returned which will cause the parsing of the class file to fail.
- *
+ * errors, a null can be returned which will cause the parsing of the class file to fail.
* @see Attribute#addAttributeReader(String, UnknownAttributeReader)
*/
Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool);
diff --git a/src/main/java/haidnor/jvm/bcel/classfile/Utility.java b/src/main/java/haidnor/jvm/bcel/classfile/Utility.java
index 07db873..a0ff788 100644
--- a/src/main/java/haidnor/jvm/bcel/classfile/Utility.java
+++ b/src/main/java/haidnor/jvm/bcel/classfile/Utility.java
@@ -35,96 +35,16 @@ import java.util.zip.GZIPOutputStream;
// @since 6.0 methods are no longer final
public abstract class Utility {
- /**
- * Decode characters into bytes. Used by decode()
- */
- private static class JavaReader extends FilterReader {
-
- public JavaReader(final Reader in) {
- super(in);
- }
-
- @Override
- public int read() throws IOException {
- final int b = in.read();
- if (b != ESCAPE_CHAR) {
- return b;
- }
- final int i = in.read();
- if (i < 0) {
- return -1;
- }
- if (i >= '0' && i <= '9' || i >= 'a' && i <= 'f') { // Normal escape
- final int j = in.read();
- if (j < 0) {
- return -1;
- }
- final char[] tmp = {(char) i, (char) j};
- return Integer.parseInt(new String(tmp), 16);
- }
- return MAP_CHAR[i];
- }
-
- @Override
- public int read(final char[] cbuf, final int off, final int len) throws IOException {
- for (int i = 0; i < len; i++) {
- cbuf[off + i] = (char) read();
- }
- return len;
- }
- }
-
- /**
- * Encode bytes into valid java identifier characters. Used by
- * encode()
- */
- private static class JavaWriter extends FilterWriter {
-
- public JavaWriter(final Writer out) {
- super(out);
- }
-
- @Override
- public void write(final char[] cbuf, final int off, final int len) throws IOException {
- for (int i = 0; i < len; i++) {
- write(cbuf[off + i]);
- }
- }
-
- @Override
- public void write(final int b) throws IOException {
- if (isJavaIdentifierPart((char) b) && b != ESCAPE_CHAR) {
- out.write(b);
- } else {
- out.write(ESCAPE_CHAR); // Escape character
- // Special escape
- if (b >= 0 && b < FREE_CHARS) {
- out.write(CHAR_MAP[b]);
- } else { // Normal escape
- final char[] tmp = Integer.toHexString(b).toCharArray();
- if (tmp.length == 1) {
- out.write('0');
- out.write(tmp[0]);
- } else {
- out.write(tmp[0]);
- out.write(tmp[1]);
- }
- }
- }
- }
-
- @Override
- public void write(final String str, final int off, final int len) throws IOException {
- write(str.toCharArray(), off, len);
- }
- }
-
/*
* How many chars have been consumed during parsing in typeSignatureToString(). Read by methodSignatureToString(). Set
* by side effect, but only internally.
*/
private static final ThreadLocal CONSUMER_CHARS = ThreadLocal.withInitial(() -> Integer.valueOf(0));
-
+ // A-Z, g-z, _, $
+ private static final int FREE_CHARS = 48;
+ private static final int[] CHAR_MAP = new int[FREE_CHARS];
+ private static final int[] MAP_CHAR = new int[256]; // Reverse map
+ private static final char ESCAPE_CHAR = '$';
/*
* The 'WIDE' instruction is used in the byte code to allow 16-bit wide indices for local variables. This opcode
* precedes an 'ILOAD', e.g.. The opcode immediately following takes an extra byte which is combined with the following
@@ -132,15 +52,6 @@ public abstract class Utility {
*/
private static boolean wide;
- // A-Z, g-z, _, $
- private static final int FREE_CHARS = 48;
-
- private static final int[] CHAR_MAP = new int[FREE_CHARS];
-
- private static final int[] MAP_CHAR = new int[256]; // Reverse map
-
- private static final char ESCAPE_CHAR = '$';
-
static {
int j = 0;
for (int i = 'A'; i <= 'Z'; i++) {
@@ -172,12 +83,12 @@ public abstract class Utility {
/**
* Convert bit field of flags into string such as 'static final'.
- *
+ *
* Special case: Classes compiled with new compilers and with the 'ACC_SUPER' flag would be said to be "synchronized".
* This is because SUN used the same value for the flags 'ACC_SUPER' and 'ACC_SYNCHRONIZED'.
*
* @param accessFlags Access flags
- * @param forClass access flags are for class qualifiers ?
+ * @param forClass access flags are for class qualifiers ?
* @return String representation of flags
*/
public static String accessToString(final int accessFlags, final boolean forClass) {
@@ -208,7 +119,6 @@ public abstract class Utility {
/**
* @param accessFlags the class flags
- *
* @return "class" or "interface", depending on the ACC_INTERFACE flag
*/
public static String classOrInterface(final int accessFlags) {
@@ -231,11 +141,11 @@ public abstract class Utility {
* Disassemble a byte array of JVM byte codes starting from code line 'index' and return the disassembled string
* representation. Decode only 'num' opcodes (including their operands), use -1 if you want to decompile everything.
*
- * @param code byte code array
+ * @param code byte code array
* @param constantPool Array of constants
- * @param index offset in 'code' array (number of opcodes, not bytes!)
- * @param length number of opcodes to decompile, -1 for all
- * @param verbose be verbose, e.g. print constant pool index
+ * @param index offset in 'code' array (number of opcodes, not bytes!)
+ * @param length number of opcodes to decompile, -1 for all
+ * @param verbose be verbose, e.g. print constant pool index
* @return String representation of byte codes
*/
public static String codeToString(final byte[] code, final ConstantPool constantPool, final int index, final int length, final boolean verbose) {
@@ -263,11 +173,10 @@ public abstract class Utility {
/**
* Disassemble a stream of byte codes and return the string representation.
*
- * @param bytes stream of bytes
+ * @param bytes stream of bytes
* @param constantPool Array of constants
- * @param verbose be verbose, e.g. print constant pool index
+ * @param verbose be verbose, e.g. print constant pool index
* @return String representation of byte code
- *
* @throws IOException if a failure from reading from the bytes argument occurs
*/
public static String codeToString(final ByteSequence bytes, final ConstantPool constantPool, final boolean verbose) throws IOException {
@@ -300,225 +209,225 @@ public abstract class Utility {
defaultOffset = bytes.readInt();
}
switch (opcode) {
- /*
- * Table switch has variable length arguments.
- */
- case Const.TABLESWITCH:
- low = bytes.readInt();
- high = bytes.readInt();
- offset = bytes.getIndex() - 12 - noPadBytes - 1;
- defaultOffset += offset;
- buf.append("\tdefault = ").append(defaultOffset).append(", low = ").append(low).append(", high = ").append(high).append("(");
- jumpTable = new int[high - low + 1];
- for (int i = 0; i < jumpTable.length; i++) {
- jumpTable[i] = offset + bytes.readInt();
- buf.append(jumpTable[i]);
- if (i < jumpTable.length - 1) {
- buf.append(", ");
- }
- }
- buf.append(")");
- break;
- /*
- * Lookup switch has variable length arguments.
- */
- case Const.LOOKUPSWITCH: {
- npairs = bytes.readInt();
- offset = bytes.getIndex() - 8 - noPadBytes - 1;
- match = new int[npairs];
- jumpTable = new int[npairs];
- defaultOffset += offset;
- buf.append("\tdefault = ").append(defaultOffset).append(", npairs = ").append(npairs).append(" (");
- for (int i = 0; i < npairs; i++) {
- match[i] = bytes.readInt();
- jumpTable[i] = offset + bytes.readInt();
- buf.append("(").append(match[i]).append(", ").append(jumpTable[i]).append(")");
- if (i < npairs - 1) {
- buf.append(", ");
- }
- }
- buf.append(")");
- }
- break;
- /*
- * Two address bytes + offset from start of byte stream form the jump target
- */
- case Const.GOTO:
- case Const.IFEQ:
- case Const.IFGE:
- case Const.IFGT:
- case Const.IFLE:
- case Const.IFLT:
- case Const.JSR:
- case Const.IFNE:
- case Const.IFNONNULL:
- case Const.IFNULL:
- case Const.IF_ACMPEQ:
- case Const.IF_ACMPNE:
- case Const.IF_ICMPEQ:
- case Const.IF_ICMPGE:
- case Const.IF_ICMPGT:
- case Const.IF_ICMPLE:
- case Const.IF_ICMPLT:
- case Const.IF_ICMPNE:
- buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readShort());
- break;
- /*
- * 32-bit wide jumps
- */
- case Const.GOTO_W:
- case Const.JSR_W:
- buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readInt());
- break;
- /*
- * Index byte references local variable (register)
- */
- case Const.ALOAD:
- case Const.ASTORE:
- case Const.DLOAD:
- case Const.DSTORE:
- case Const.FLOAD:
- case Const.FSTORE:
- case Const.ILOAD:
- case Const.ISTORE:
- case Const.LLOAD:
- case Const.LSTORE:
- case Const.RET:
- if (wide) {
- vindex = bytes.readUnsignedShort();
- wide = false; // Clear flag
- } else {
- vindex = bytes.readUnsignedByte();
- }
- buf.append("\t\t%").append(vindex);
- break;
- /*
- * Remember wide byte which is used to form a 16-bit address in the following instruction. Relies on that the method is
- * called again with the following opcode.
- */
- case Const.WIDE:
- wide = true;
- buf.append("\t(wide)");
- break;
- /*
- * Array of basic type.
- */
- case Const.NEWARRAY:
- buf.append("\t\t<").append(Const.getTypeName(bytes.readByte())).append(">");
- break;
- /*
- * Access object/class fields.
- */
- case Const.GETFIELD:
- case Const.GETSTATIC:
- case Const.PUTFIELD:
- case Const.PUTSTATIC:
- index = bytes.readUnsignedShort();
- buf.append("\t\t").append(constantPool.constantToString(index, Const.CONSTANT_Fieldref)).append(verbose ? " (" + index + ")" : "");
- break;
- /*
- * Operands are references to classes in constant pool
- */
- case Const.NEW:
- case Const.CHECKCAST:
- buf.append("\t");
- //$FALL-THROUGH$
- case Const.INSTANCEOF:
- index = bytes.readUnsignedShort();
- buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
- break;
- /*
- * Operands are references to methods in constant pool
- */
- case Const.INVOKESPECIAL:
- case Const.INVOKESTATIC:
- index = bytes.readUnsignedShort();
- final Constant c = constantPool.getConstant(index);
- // With Java8 operand may be either a CONSTANT_Methodref
- // or a CONSTANT_InterfaceMethodref. (markro)
- buf.append("\t").append(constantPool.constantToString(index, c.getTag())).append(verbose ? " (" + index + ")" : "");
- break;
- case Const.INVOKEVIRTUAL:
- index = bytes.readUnsignedShort();
- buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_Methodref)).append(verbose ? " (" + index + ")" : "");
- break;
- case Const.INVOKEINTERFACE:
- index = bytes.readUnsignedShort();
- final int nargs = bytes.readUnsignedByte(); // historical, redundant
- buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InterfaceMethodref)).append(verbose ? " (" + index + ")\t" : "")
- .append(nargs).append("\t").append(bytes.readUnsignedByte()); // Last byte is a reserved space
- break;
- case Const.INVOKEDYNAMIC:
- index = bytes.readUnsignedShort();
- buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InvokeDynamic)).append(verbose ? " (" + index + ")\t" : "")
- .append(bytes.readUnsignedByte()) // Thrid byte is a reserved space
- .append(bytes.readUnsignedByte()); // Last byte is a reserved space
- break;
- /*
- * Operands are references to items in constant pool
- */
- case Const.LDC_W:
- case Const.LDC2_W:
- index = bytes.readUnsignedShort();
- buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag()))
- .append(verbose ? " (" + index + ")" : "");
- break;
- case Const.LDC:
- index = bytes.readUnsignedByte();
- buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag()))
- .append(verbose ? " (" + index + ")" : "");
- break;
- /*
- * Array of references.
- */
- case Const.ANEWARRAY:
- index = bytes.readUnsignedShort();
- buf.append("\t\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">")
- .append(verbose ? " (" + index + ")" : "");
- break;
- /*
- * Multidimensional array of references.
- */
- case Const.MULTIANEWARRAY: {
- index = bytes.readUnsignedShort();
- final int dimensions = bytes.readUnsignedByte();
- buf.append("\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">\t").append(dimensions)
- .append(verbose ? " (" + index + ")" : "");
- }
- break;
- /*
- * Increment local variable.
- */
- case Const.IINC:
- if (wide) {
- vindex = bytes.readUnsignedShort();
- constant = bytes.readShort();
- wide = false;
- } else {
- vindex = bytes.readUnsignedByte();
- constant = bytes.readByte();
- }
- buf.append("\t\t%").append(vindex).append("\t").append(constant);
- break;
- default:
- if (Const.getNoOfOperands(opcode) > 0) {
- for (int i = 0; i < Const.getOperandTypeCount(opcode); i++) {
- buf.append("\t\t");
- switch (Const.getOperandType(opcode, i)) {
- case Const.T_BYTE:
- buf.append(bytes.readByte());
- break;
- case Const.T_SHORT:
- buf.append(bytes.readShort());
- break;
- case Const.T_INT:
- buf.append(bytes.readInt());
- break;
- default: // Never reached
- throw new IllegalStateException("Unreachable default case reached!");
+ /*
+ * Table switch has variable length arguments.
+ */
+ case Const.TABLESWITCH:
+ low = bytes.readInt();
+ high = bytes.readInt();
+ offset = bytes.getIndex() - 12 - noPadBytes - 1;
+ defaultOffset += offset;
+ buf.append("\tdefault = ").append(defaultOffset).append(", low = ").append(low).append(", high = ").append(high).append("(");
+ jumpTable = new int[high - low + 1];
+ for (int i = 0; i < jumpTable.length; i++) {
+ jumpTable[i] = offset + bytes.readInt();
+ buf.append(jumpTable[i]);
+ if (i < jumpTable.length - 1) {
+ buf.append(", ");
}
}
+ buf.append(")");
+ break;
+ /*
+ * Lookup switch has variable length arguments.
+ */
+ case Const.LOOKUPSWITCH: {
+ npairs = bytes.readInt();
+ offset = bytes.getIndex() - 8 - noPadBytes - 1;
+ match = new int[npairs];
+ jumpTable = new int[npairs];
+ defaultOffset += offset;
+ buf.append("\tdefault = ").append(defaultOffset).append(", npairs = ").append(npairs).append(" (");
+ for (int i = 0; i < npairs; i++) {
+ match[i] = bytes.readInt();
+ jumpTable[i] = offset + bytes.readInt();
+ buf.append("(").append(match[i]).append(", ").append(jumpTable[i]).append(")");
+ if (i < npairs - 1) {
+ buf.append(", ");
+ }
+ }
+ buf.append(")");
}
+ break;
+ /*
+ * Two address bytes + offset from start of byte stream form the jump target
+ */
+ case Const.GOTO:
+ case Const.IFEQ:
+ case Const.IFGE:
+ case Const.IFGT:
+ case Const.IFLE:
+ case Const.IFLT:
+ case Const.JSR:
+ case Const.IFNE:
+ case Const.IFNONNULL:
+ case Const.IFNULL:
+ case Const.IF_ACMPEQ:
+ case Const.IF_ACMPNE:
+ case Const.IF_ICMPEQ:
+ case Const.IF_ICMPGE:
+ case Const.IF_ICMPGT:
+ case Const.IF_ICMPLE:
+ case Const.IF_ICMPLT:
+ case Const.IF_ICMPNE:
+ buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readShort());
+ break;
+ /*
+ * 32-bit wide jumps
+ */
+ case Const.GOTO_W:
+ case Const.JSR_W:
+ buf.append("\t\t#").append(bytes.getIndex() - 1 + bytes.readInt());
+ break;
+ /*
+ * Index byte references local variable (register)
+ */
+ case Const.ALOAD:
+ case Const.ASTORE:
+ case Const.DLOAD:
+ case Const.DSTORE:
+ case Const.FLOAD:
+ case Const.FSTORE:
+ case Const.ILOAD:
+ case Const.ISTORE:
+ case Const.LLOAD:
+ case Const.LSTORE:
+ case Const.RET:
+ if (wide) {
+ vindex = bytes.readUnsignedShort();
+ wide = false; // Clear flag
+ } else {
+ vindex = bytes.readUnsignedByte();
+ }
+ buf.append("\t\t%").append(vindex);
+ break;
+ /*
+ * Remember wide byte which is used to form a 16-bit address in the following instruction. Relies on that the method is
+ * called again with the following opcode.
+ */
+ case Const.WIDE:
+ wide = true;
+ buf.append("\t(wide)");
+ break;
+ /*
+ * Array of basic type.
+ */
+ case Const.NEWARRAY:
+ buf.append("\t\t<").append(Const.getTypeName(bytes.readByte())).append(">");
+ break;
+ /*
+ * Access object/class fields.
+ */
+ case Const.GETFIELD:
+ case Const.GETSTATIC:
+ case Const.PUTFIELD:
+ case Const.PUTSTATIC:
+ index = bytes.readUnsignedShort();
+ buf.append("\t\t").append(constantPool.constantToString(index, Const.CONSTANT_Fieldref)).append(verbose ? " (" + index + ")" : "");
+ break;
+ /*
+ * Operands are references to classes in constant pool
+ */
+ case Const.NEW:
+ case Const.CHECKCAST:
+ buf.append("\t");
+ //$FALL-THROUGH$
+ case Const.INSTANCEOF:
+ index = bytes.readUnsignedShort();
+ buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
+ break;
+ /*
+ * Operands are references to methods in constant pool
+ */
+ case Const.INVOKESPECIAL:
+ case Const.INVOKESTATIC:
+ index = bytes.readUnsignedShort();
+ final Constant c = constantPool.getConstant(index);
+ // With Java8 operand may be either a CONSTANT_Methodref
+ // or a CONSTANT_InterfaceMethodref. (markro)
+ buf.append("\t").append(constantPool.constantToString(index, c.getTag())).append(verbose ? " (" + index + ")" : "");
+ break;
+ case Const.INVOKEVIRTUAL:
+ index = bytes.readUnsignedShort();
+ buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_Methodref)).append(verbose ? " (" + index + ")" : "");
+ break;
+ case Const.INVOKEINTERFACE:
+ index = bytes.readUnsignedShort();
+ final int nargs = bytes.readUnsignedByte(); // historical, redundant
+ buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InterfaceMethodref)).append(verbose ? " (" + index + ")\t" : "")
+ .append(nargs).append("\t").append(bytes.readUnsignedByte()); // Last byte is a reserved space
+ break;
+ case Const.INVOKEDYNAMIC:
+ index = bytes.readUnsignedShort();
+ buf.append("\t").append(constantPool.constantToString(index, Const.CONSTANT_InvokeDynamic)).append(verbose ? " (" + index + ")\t" : "")
+ .append(bytes.readUnsignedByte()) // Thrid byte is a reserved space
+ .append(bytes.readUnsignedByte()); // Last byte is a reserved space
+ break;
+ /*
+ * Operands are references to items in constant pool
+ */
+ case Const.LDC_W:
+ case Const.LDC2_W:
+ index = bytes.readUnsignedShort();
+ buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag()))
+ .append(verbose ? " (" + index + ")" : "");
+ break;
+ case Const.LDC:
+ index = bytes.readUnsignedByte();
+ buf.append("\t\t").append(constantPool.constantToString(index, constantPool.getConstant(index).getTag()))
+ .append(verbose ? " (" + index + ")" : "");
+ break;
+ /*
+ * Array of references.
+ */
+ case Const.ANEWARRAY:
+ index = bytes.readUnsignedShort();
+ buf.append("\t\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">")
+ .append(verbose ? " (" + index + ")" : "");
+ break;
+ /*
+ * Multidimensional array of references.
+ */
+ case Const.MULTIANEWARRAY: {
+ index = bytes.readUnsignedShort();
+ final int dimensions = bytes.readUnsignedByte();
+ buf.append("\t<").append(compactClassName(constantPool.getConstantString(index, Const.CONSTANT_Class), false)).append(">\t").append(dimensions)
+ .append(verbose ? " (" + index + ")" : "");
+ }
+ break;
+ /*
+ * Increment local variable.
+ */
+ case Const.IINC:
+ if (wide) {
+ vindex = bytes.readUnsignedShort();
+ constant = bytes.readShort();
+ wide = false;
+ } else {
+ vindex = bytes.readUnsignedByte();
+ constant = bytes.readByte();
+ }
+ buf.append("\t\t%").append(vindex).append("\t").append(constant);
+ break;
+ default:
+ if (Const.getNoOfOperands(opcode) > 0) {
+ for (int i = 0; i < Const.getOperandTypeCount(opcode); i++) {
+ buf.append("\t\t");
+ switch (Const.getOperandType(opcode, i)) {
+ case Const.T_BYTE:
+ buf.append(bytes.readByte());
+ break;
+ case Const.T_SHORT:
+ buf.append(bytes.readShort());
+ break;
+ case Const.T_INT:
+ buf.append(bytes.readInt());
+ break;
+ default: // Never reached
+ throw new IllegalStateException("Unreachable default case reached!");
+ }
+ }
+ }
}
return buf.toString();
}
@@ -537,7 +446,7 @@ public abstract class Utility {
* Shorten long class names, java/lang/String becomes java.lang.String , e.g.. If chopit is
* true the prefix java.lang is also removed.
*
- * @param str The long class name
+ * @param str The long class name
* @param chopit flag that determines whether chopping is executed or not
* @return Compacted class name
*/
@@ -549,7 +458,7 @@ public abstract class Utility {
* Shorten long class name str , i.e., chop off the prefix , if the class name starts with this string
* and the flag chopit is true. Slashes / are converted to dots . .
*
- * @param str The long class name
+ * @param str The long class name
* @param prefix The prefix the get rid off
* @param chopit flag that determines whether chopping is executed or not
* @return Compacted class name
@@ -572,24 +481,24 @@ public abstract class Utility {
final StringBuilder buf = new StringBuilder();
for (final char element : ch) {
switch (element) {
- case '\n':
- buf.append("\\n");
- break;
- case '\r':
- buf.append("\\r");
- break;
- case '\"':
- buf.append("\\\"");
- break;
- case '\'':
- buf.append("\\'");
- break;
- case '\\':
- buf.append("\\\\");
- break;
- default:
- buf.append(element);
- break;
+ case '\n':
+ buf.append("\\n");
+ break;
+ case '\r':
+ buf.append("\\r");
+ break;
+ case '\"':
+ buf.append("\\\"");
+ break;
+ case '\'':
+ buf.append("\\'");
+ break;
+ case '\\':
+ buf.append("\\\\");
+ break;
+ default:
+ buf.append(element);
+ break;
}
}
return buf.toString();
@@ -601,22 +510,22 @@ public abstract class Utility {
boolean open = false;
for (final char c : chars) {
switch (c) {
- case '[':
- if (open) {
- throw new IllegalArgumentException("Illegally nested brackets:" + brackets);
- }
- open = true;
- break;
- case ']':
- if (!open) {
- throw new IllegalArgumentException("Illegally nested brackets:" + brackets);
- }
- open = false;
- count++;
- break;
- default:
- // Don't care
- break;
+ case '[':
+ if (open) {
+ throw new IllegalArgumentException("Illegally nested brackets:" + brackets);
+ }
+ open = true;
+ break;
+ case ']':
+ if (!open) {
+ throw new IllegalArgumentException("Illegally nested brackets:" + brackets);
+ }
+ open = false;
+ count++;
+ break;
+ default:
+ // Don't care
+ break;
}
}
if (open) {
@@ -628,9 +537,8 @@ public abstract class Utility {
/**
* Decode a string back to a byte array.
*
- * @param s the string to convert
+ * @param s the string to convert
* @param uncompress use gzip to uncompress the stream of bytes
- *
* @throws IOException if there's a gzip exception
*/
public static byte[] decode(final String s, final boolean uncompress) throws IOException {
@@ -669,9 +577,8 @@ public abstract class Utility {
* This operation inflates the original byte array by roughly 40-50%
*
*
- * @param bytes the byte array to convert
+ * @param bytes the byte array to convert
* @param compress use gzip to minimize string
- *
* @throws IOException if there's a gzip exception
*/
public static String encode(byte[] bytes, final boolean compress) throws IOException {
@@ -695,10 +602,10 @@ public abstract class Utility {
/**
* Fillup char with up to length characters with char 'fill' and justify it left or right.
*
- * @param str string to format
- * @param length length of desired string
+ * @param str string to format
+ * @param length length of desired string
* @param leftJustify format left or right
- * @param fill fill character
+ * @param fill fill character
* @return formatted string
*/
public static String fillup(final String str, final int length, final boolean leftJustify, final char fill) {
@@ -714,16 +621,84 @@ public abstract class Utility {
/**
* Return a string for an integer justified left or right and filled up with 'fill' characters if necessary.
*
- * @param i integer to format
- * @param length length of desired string
+ * @param i integer to format
+ * @param length length of desired string
* @param leftJustify format left or right
- * @param fill fill character
+ * @param fill fill character
* @return formatted int
*/
public static String format(final int i, final int length, final boolean leftJustify, final char fill) {
return fillup(Integer.toString(i), length, leftJustify, fill);
}
+ /**
+ * Parse Java type such as "char", or "java.lang.String[]" and return the signature in byte code format, e.g. "C" or
+ * "[Ljava/lang/String;" respectively.
+ *
+ * @param type Java type
+ * @return byte code signature
+ */
+ public static String getSignature(String type) {
+ final StringBuilder buf = new StringBuilder();
+ final char[] chars = type.toCharArray();
+ boolean charFound = false;
+ boolean delim = false;
+ int index = -1;
+ loop:
+ for (int i = 0; i < chars.length; i++) {
+ switch (chars[i]) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ if (charFound) {
+ delim = true;
+ }
+ break;
+ case '[':
+ if (!charFound) {
+ throw new IllegalArgumentException("Illegal type: " + type);
+ }
+ index = i;
+ break loop;
+ default:
+ charFound = true;
+ if (!delim) {
+ buf.append(chars[i]);
+ }
+ }
+ }
+ int brackets = 0;
+ if (index > 0) {
+ brackets = countBrackets(type.substring(index));
+ }
+ type = buf.toString();
+ buf.setLength(0);
+ for (int i = 0; i < brackets; i++) {
+ buf.append('[');
+ }
+ boolean found = false;
+ for (int i = Const.T_BOOLEAN; i <= Const.T_VOID && !found; i++) {
+ if (Const.getTypeName(i).equals(type)) {
+ found = true;
+ buf.append(Const.getShortTypeName(i));
+ }
+ }
+ if (!found) {
+ buf.append('L').append(packageToPath(type)).append(';');
+ }
+ return buf.toString();
+ }
+
+ /**
+ * @param ch the character to test if it's part of an identifier
+ * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
+ */
+ public static boolean isJavaIdentifierPart(final char ch) {
+ return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '_';
+ }
+
/**
* WARNING:
*
@@ -748,74 +723,6 @@ public abstract class Utility {
* you should call typeSignatureToString directly.
*/
- /**
- * Parse Java type such as "char", or "java.lang.String[]" and return the signature in byte code format, e.g. "C" or
- * "[Ljava/lang/String;" respectively.
- *
- * @param type Java type
- * @return byte code signature
- */
- public static String getSignature(String type) {
- final StringBuilder buf = new StringBuilder();
- final char[] chars = type.toCharArray();
- boolean charFound = false;
- boolean delim = false;
- int index = -1;
- loop: for (int i = 0; i < chars.length; i++) {
- switch (chars[i]) {
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- case '\f':
- if (charFound) {
- delim = true;
- }
- break;
- case '[':
- if (!charFound) {
- throw new IllegalArgumentException("Illegal type: " + type);
- }
- index = i;
- break loop;
- default:
- charFound = true;
- if (!delim) {
- buf.append(chars[i]);
- }
- }
- }
- int brackets = 0;
- if (index > 0) {
- brackets = countBrackets(type.substring(index));
- }
- type = buf.toString();
- buf.setLength(0);
- for (int i = 0; i < brackets; i++) {
- buf.append('[');
- }
- boolean found = false;
- for (int i = Const.T_BOOLEAN; i <= Const.T_VOID && !found; i++) {
- if (Const.getTypeName(i).equals(type)) {
- found = true;
- buf.append(Const.getShortTypeName(i));
- }
- }
- if (!found) {
- buf.append('L').append(packageToPath(type)).append(';');
- }
- return buf.toString();
- }
-
- /**
- * @param ch the character to test if it's part of an identifier
- *
- * @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
- */
- public static boolean isJavaIdentifierPart(final char ch) {
- return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '_';
- }
-
/**
* @return true, if bit 'i' in 'flag' is set
*/
@@ -838,7 +745,7 @@ public abstract class Utility {
* Converts argument list portion of method signature to string.
*
* @param signature Method signature
- * @param chopit flag that determines whether chopping is executed or not
+ * @param chopit flag that determines whether chopping is executed or not
* @return String Array of argument types
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
@@ -877,7 +784,7 @@ public abstract class Utility {
* Converts return type portion of method signature to string.
*
* @param signature Method signature
- * @param chopit flag that determines whether chopping is executed or not
+ * @param chopit flag that determines whether chopping is executed or not
* @return String representation of method return type
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
@@ -901,8 +808,8 @@ public abstract class Utility {
* Converts method signature to string with all class names compacted.
*
* @param signature to convert
- * @param name of method
- * @param access flags of method
+ * @param name of method
+ * @param access flags of method
* @return Human readable signature
*/
public static String methodSignatureToString(final String signature, final String name, final String access) {
@@ -913,9 +820,9 @@ public abstract class Utility {
* Converts method signature to string.
*
* @param signature to convert
- * @param name of method
- * @param access flags of method
- * @param chopit flag that determines whether chopping is executed or not
+ * @param name of method
+ * @param access flags of method
+ * @param chopit flag that determines whether chopping is executed or not
* @return Human readable signature
*/
public static String methodSignatureToString(final String signature, final String name, final String access, final boolean chopit) {
@@ -927,15 +834,15 @@ public abstract class Utility {
* 'ClassFormatException' when the parsed type is invalid.
*
* @param signature Method signature
- * @param name Method name
- * @param access Method access rights
- * @param chopit flag that determines whether chopping is executed or not
- * @param vars the LocalVariableTable for the method
+ * @param name Method name
+ * @param access Method access rights
+ * @param chopit flag that determines whether chopping is executed or not
+ * @param vars the LocalVariableTable for the method
* @return Java type declaration
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
public static String methodSignatureToString(final String signature, final String name, final String access, final boolean chopit,
- final LocalVariableTable vars) throws ClassFormatException {
+ final LocalVariableTable vars) throws ClassFormatException {
final StringBuilder buf = new StringBuilder("(");
String type;
int index;
@@ -978,16 +885,15 @@ public abstract class Utility {
}
buf.append(")");
return access + (!access.isEmpty() ? " " : "") + // May be an empty string
- type + " " + name + buf.toString();
+ type + " " + name + buf.toString();
}
/**
* Converts string containing the method return and argument types to a byte code method signature.
*
- * @param ret Return type of method
+ * @param ret Return type of method
* @param argv Types of method arguments
* @return Byte code representation of method signature
- *
* @throws ClassFormatException if the signature is for Void
*/
public static String methodTypeToSignature(final String ret, final String[] argv) throws ClassFormatException {
@@ -1076,8 +982,8 @@ public abstract class Utility {
/**
* Replace all occurrences of old in str with new .
*
- * @param str String to permute
- * @param old String to be replaced
+ * @param str String to permute
+ * @param old String to be replaced
* @param new_ Replacement string
* @return new String object
*/
@@ -1139,7 +1045,7 @@ public abstract class Utility {
* not supported.
*
* @param signature signature to convert
- * @param chopit flag that determines whether chopping is executed or not
+ * @param chopit flag that determines whether chopping is executed or not
* @return String containg human readable signature
*/
public static String signatureToString(final String signature, final boolean chopit) {
@@ -1190,7 +1096,6 @@ public abstract class Utility {
* Convert bytes into hexadecimal string
*
* @param bytes an array of bytes to convert to hexadecimal
- *
* @return bytes as hexadecimal string, e.g. 00 fa 12 ...
*/
public static String toHexString(final byte[] bytes) {
@@ -1214,9 +1119,8 @@ public abstract class Utility {
*
* @param signature in format described above
* @return type of method signature
- * @see Const
- *
* @throws ClassFormatException if signature is not a method signature
+ * @see Const
*/
public static byte typeOfMethodSignature(final String signature) throws ClassFormatException {
int index;
@@ -1236,42 +1140,41 @@ public abstract class Utility {
*
* @param signature in format described above
* @return type of signature
- * @see Const
- *
* @throws ClassFormatException if signature isn't a known type
+ * @see Const
*/
public static byte typeOfSignature(final String signature) throws ClassFormatException {
try {
switch (signature.charAt(0)) {
- case 'B':
- return Const.T_BYTE;
- case 'C':
- return Const.T_CHAR;
- case 'D':
- return Const.T_DOUBLE;
- case 'F':
- return Const.T_FLOAT;
- case 'I':
- return Const.T_INT;
- case 'J':
- return Const.T_LONG;
- case 'L':
- case 'T':
- return Const.T_REFERENCE;
- case '[':
- return Const.T_ARRAY;
- case 'V':
- return Const.T_VOID;
- case 'Z':
- return Const.T_BOOLEAN;
- case 'S':
- return Const.T_SHORT;
- case '!':
- case '+':
- case '*':
- return typeOfSignature(signature.substring(1));
- default:
- throw new ClassFormatException("Invalid method signature: " + signature);
+ case 'B':
+ return Const.T_BYTE;
+ case 'C':
+ return Const.T_CHAR;
+ case 'D':
+ return Const.T_DOUBLE;
+ case 'F':
+ return Const.T_FLOAT;
+ case 'I':
+ return Const.T_INT;
+ case 'J':
+ return Const.T_LONG;
+ case 'L':
+ case 'T':
+ return Const.T_REFERENCE;
+ case '[':
+ return Const.T_ARRAY;
+ case 'V':
+ return Const.T_VOID;
+ case 'Z':
+ return Const.T_BOOLEAN;
+ case 'S':
+ return Const.T_SHORT;
+ case '!':
+ case '+':
+ case '*':
+ return typeOfSignature(signature.substring(1));
+ default:
+ throw new ClassFormatException("Invalid method signature: " + signature);
}
} catch (final StringIndexOutOfBoundsException e) {
throw new ClassFormatException("Invalid method signature: " + signature, e);
@@ -1282,7 +1185,7 @@ public abstract class Utility {
* Converts a type parameter list signature to a string.
*
* @param signature signature to convert
- * @param chopit flag that determines whether chopping is executed or not
+ * @param chopit flag that determines whether chopping is executed or not
* @return String containg human readable signature
*/
private static String typeParamTypesToString(final String signature, final boolean chopit) {
@@ -1306,7 +1209,7 @@ public abstract class Utility {
* Converts a type parameter signature to a string.
*
* @param signature signature to convert
- * @param chopit flag that determines whether chopping is executed or not
+ * @param chopit flag that determines whether chopping is executed or not
* @return String containg human readable signature
*/
private static String typeParamTypeToString(final String signature, final boolean chopit) {
@@ -1338,8 +1241,8 @@ public abstract class Utility {
* Converts a list of type signatures to a string.
*
* @param signature signature to convert
- * @param chopit flag that determines whether chopping is executed or not
- * @param term character indicating the end of the list
+ * @param chopit flag that determines whether chopping is executed or not
+ * @param term character indicating the end of the list
* @return String containg human readable signature
*/
private static String typeSignaturesToString(final String signature, final boolean chopit, final char term) {
@@ -1362,12 +1265,11 @@ public abstract class Utility {
}
/**
- *
* This method converts a type signature string into a Java type declaration such as 'String[]' and throws a
* 'ClassFormatException' when the parsed type is invalid.
*
* @param signature type signature
- * @param chopit flag that determines whether chopping is executed or not
+ * @param chopit flag that determines whether chopping is executed or not
* @return string containing human readable type signature
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
* @since 6.4.0
@@ -1377,90 +1279,67 @@ public abstract class Utility {
wrap(CONSUMER_CHARS, 1); // This is the default, read just one char like 'B'
try {
switch (signature.charAt(0)) {
- case 'B':
- return "byte";
- case 'C':
- return "char";
- case 'D':
- return "double";
- case 'F':
- return "float";
- case 'I':
- return "int";
- case 'J':
- return "long";
- case 'T': { // TypeVariableSignature
- final int index = signature.indexOf(';'); // Look for closing ';'
- if (index < 0) {
- throw new ClassFormatException("Invalid type variable signature: " + signature);
+ case 'B':
+ return "byte";
+ case 'C':
+ return "char";
+ case 'D':
+ return "double";
+ case 'F':
+ return "float";
+ case 'I':
+ return "int";
+ case 'J':
+ return "long";
+ case 'T': { // TypeVariableSignature
+ final int index = signature.indexOf(';'); // Look for closing ';'
+ if (index < 0) {
+ throw new ClassFormatException("Invalid type variable signature: " + signature);
+ }
+ // corrected concurrent private static field acess
+ wrap(CONSUMER_CHARS, index + 1); // "Tblabla;" 'T' and ';' are removed
+ return compactClassName(signature.substring(1, index), chopit);
}
- // corrected concurrent private static field acess
- wrap(CONSUMER_CHARS, index + 1); // "Tblabla;" 'T' and ';' are removed
- return compactClassName(signature.substring(1, index), chopit);
- }
- case 'L': { // Full class name
- // should this be a while loop? can there be more than
- // one generic clause? (markro)
- int fromIndex = signature.indexOf('<'); // generic type?
- if (fromIndex < 0) {
- fromIndex = 0;
- } else {
- fromIndex = signature.indexOf('>', fromIndex);
+ case 'L': { // Full class name
+ // should this be a while loop? can there be more than
+ // one generic clause? (markro)
+ int fromIndex = signature.indexOf('<'); // generic type?
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ } else {
+ fromIndex = signature.indexOf('>', fromIndex);
+ if (fromIndex < 0) {
+ throw new ClassFormatException("Invalid signature: " + signature);
+ }
+ }
+ final int index = signature.indexOf(';', fromIndex); // Look for closing ';'
+ if (index < 0) {
+ throw new ClassFormatException("Invalid signature: " + signature);
+ }
+
+ // check to see if there are any TypeArguments
+ final int bracketIndex = signature.substring(0, index).indexOf('<');
+ if (bracketIndex < 0) {
+ // just a class identifier
+ wrap(CONSUMER_CHARS, index + 1); // "Lblabla;" 'L' and ';' are removed
+ return compactClassName(signature.substring(1, index), chopit);
+ }
+ // but make sure we are not looking past the end of the current item
+ fromIndex = signature.indexOf(';');
if (fromIndex < 0) {
throw new ClassFormatException("Invalid signature: " + signature);
}
- }
- final int index = signature.indexOf(';', fromIndex); // Look for closing ';'
- if (index < 0) {
- throw new ClassFormatException("Invalid signature: " + signature);
- }
+ if (fromIndex < bracketIndex) {
+ // just a class identifier
+ wrap(CONSUMER_CHARS, fromIndex + 1); // "Lblabla;" 'L' and ';' are removed
+ return compactClassName(signature.substring(1, fromIndex), chopit);
+ }
- // check to see if there are any TypeArguments
- final int bracketIndex = signature.substring(0, index).indexOf('<');
- if (bracketIndex < 0) {
- // just a class identifier
- wrap(CONSUMER_CHARS, index + 1); // "Lblabla;" 'L' and ';' are removed
- return compactClassName(signature.substring(1, index), chopit);
- }
- // but make sure we are not looking past the end of the current item
- fromIndex = signature.indexOf(';');
- if (fromIndex < 0) {
- throw new ClassFormatException("Invalid signature: " + signature);
- }
- if (fromIndex < bracketIndex) {
- // just a class identifier
- wrap(CONSUMER_CHARS, fromIndex + 1); // "Lblabla;" 'L' and ';' are removed
- return compactClassName(signature.substring(1, fromIndex), chopit);
- }
+ // we have TypeArguments; build up partial result
+ // as we recurse for each TypeArgument
+ final StringBuilder type = new StringBuilder(compactClassName(signature.substring(1, bracketIndex), chopit)).append("<");
+ int consumedChars = bracketIndex + 1; // Shadows global var
- // we have TypeArguments; build up partial result
- // as we recurse for each TypeArgument
- final StringBuilder type = new StringBuilder(compactClassName(signature.substring(1, bracketIndex), chopit)).append("<");
- int consumedChars = bracketIndex + 1; // Shadows global var
-
- // check for wildcards
- if (signature.charAt(consumedChars) == '+') {
- type.append("? extends ");
- consumedChars++;
- } else if (signature.charAt(consumedChars) == '-') {
- type.append("? super ");
- consumedChars++;
- }
-
- // get the first TypeArgument
- if (signature.charAt(consumedChars) == '*') {
- type.append("?");
- consumedChars++;
- } else {
- type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
- // update our consumed count by the number of characters the for type argument
- consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
- wrap(Utility.CONSUMER_CHARS, consumedChars);
- }
-
- // are there more TypeArguments?
- while (signature.charAt(consumedChars) != '>') {
- type.append(", ");
// check for wildcards
if (signature.charAt(consumedChars) == '+') {
type.append("? extends ");
@@ -1469,6 +1348,8 @@ public abstract class Utility {
type.append("? super ");
consumedChars++;
}
+
+ // get the first TypeArgument
if (signature.charAt(consumedChars) == '*') {
type.append("?");
consumedChars++;
@@ -1478,58 +1359,79 @@ public abstract class Utility {
consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
wrap(Utility.CONSUMER_CHARS, consumedChars);
}
- }
- // process the closing ">"
- consumedChars++;
- type.append(">");
+ // are there more TypeArguments?
+ while (signature.charAt(consumedChars) != '>') {
+ type.append(", ");
+ // check for wildcards
+ if (signature.charAt(consumedChars) == '+') {
+ type.append("? extends ");
+ consumedChars++;
+ } else if (signature.charAt(consumedChars) == '-') {
+ type.append("? super ");
+ consumedChars++;
+ }
+ if (signature.charAt(consumedChars) == '*') {
+ type.append("?");
+ consumedChars++;
+ } else {
+ type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
+ // update our consumed count by the number of characters the for type argument
+ consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
+ wrap(Utility.CONSUMER_CHARS, consumedChars);
+ }
+ }
- if (signature.charAt(consumedChars) == '.') {
- // we have a ClassTypeSignatureSuffix
- type.append(".");
- // convert SimpleClassTypeSignature to fake ClassTypeSignature
- // and then recurse to parse it
- type.append(typeSignatureToString("L" + signature.substring(consumedChars + 1), chopit));
- // update our consumed count by the number of characters the for type argument
- // note that this count includes the "L" we added, but that is ok
- // as it accounts for the "." we didn't consume
- consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
- wrap(Utility.CONSUMER_CHARS, consumedChars);
+ // process the closing ">"
+ consumedChars++;
+ type.append(">");
+
+ if (signature.charAt(consumedChars) == '.') {
+ // we have a ClassTypeSignatureSuffix
+ type.append(".");
+ // convert SimpleClassTypeSignature to fake ClassTypeSignature
+ // and then recurse to parse it
+ type.append(typeSignatureToString("L" + signature.substring(consumedChars + 1), chopit));
+ // update our consumed count by the number of characters the for type argument
+ // note that this count includes the "L" we added, but that is ok
+ // as it accounts for the "." we didn't consume
+ consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
+ wrap(Utility.CONSUMER_CHARS, consumedChars);
+ return type.toString();
+ }
+ if (signature.charAt(consumedChars) != ';') {
+ throw new ClassFormatException("Invalid signature: " + signature);
+ }
+ wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";"
return type.toString();
}
- if (signature.charAt(consumedChars) != ';') {
- throw new ClassFormatException("Invalid signature: " + signature);
+ case 'S':
+ return "short";
+ case 'Z':
+ return "boolean";
+ case '[': { // Array declaration
+ int n;
+ StringBuilder brackets;
+ String type;
+ int consumedChars; // Shadows global var
+ brackets = new StringBuilder(); // Accumulate []'s
+ // Count opening brackets and look for optional size argument
+ for (n = 0; signature.charAt(n) == '['; n++) {
+ brackets.append("[]");
+ }
+ consumedChars = n; // Remember value
+ // The rest of the string denotes a ''
+ type = typeSignatureToString(signature.substring(n), chopit);
+ // corrected concurrent private static field acess
+ // Utility.consumed_chars += consumed_chars; is replaced by:
+ final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
+ wrap(Utility.CONSUMER_CHARS, temp);
+ return type + brackets.toString();
}
- wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";"
- return type.toString();
- }
- case 'S':
- return "short";
- case 'Z':
- return "boolean";
- case '[': { // Array declaration
- int n;
- StringBuilder brackets;
- String type;
- int consumedChars; // Shadows global var
- brackets = new StringBuilder(); // Accumulate []'s
- // Count opening brackets and look for optional size argument
- for (n = 0; signature.charAt(n) == '['; n++) {
- brackets.append("[]");
- }
- consumedChars = n; // Remember value
- // The rest of the string denotes a ''
- type = typeSignatureToString(signature.substring(n), chopit);
- // corrected concurrent private static field acess
- // Utility.consumed_chars += consumed_chars; is replaced by:
- final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
- wrap(Utility.CONSUMER_CHARS, temp);
- return type + brackets.toString();
- }
- case 'V':
- return "void";
- default:
- throw new ClassFormatException("Invalid signature: '" + signature + "'");
+ case 'V':
+ return "void";
+ default:
+ throw new ClassFormatException("Invalid signature: '" + signature + "'");
}
} catch (final StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid signature: " + signature, e);
@@ -1544,4 +1446,88 @@ public abstract class Utility {
tl.set(Integer.valueOf(value));
}
+ /**
+ * Decode characters into bytes. Used by decode()
+ */
+ private static class JavaReader extends FilterReader {
+
+ public JavaReader(final Reader in) {
+ super(in);
+ }
+
+ @Override
+ public int read() throws IOException {
+ final int b = in.read();
+ if (b != ESCAPE_CHAR) {
+ return b;
+ }
+ final int i = in.read();
+ if (i < 0) {
+ return -1;
+ }
+ if (i >= '0' && i <= '9' || i >= 'a' && i <= 'f') { // Normal escape
+ final int j = in.read();
+ if (j < 0) {
+ return -1;
+ }
+ final char[] tmp = {(char) i, (char) j};
+ return Integer.parseInt(new String(tmp), 16);
+ }
+ return MAP_CHAR[i];
+ }
+
+ @Override
+ public int read(final char[] cbuf, final int off, final int len) throws IOException {
+ for (int i = 0; i < len; i++) {
+ cbuf[off + i] = (char) read();
+ }
+ return len;
+ }
+ }
+
+ /**
+ * Encode bytes into valid java identifier characters. Used by
+ * encode()
+ */
+ private static class JavaWriter extends FilterWriter {
+
+ public JavaWriter(final Writer out) {
+ super(out);
+ }
+
+ @Override
+ public void write(final char[] cbuf, final int off, final int len) throws IOException {
+ for (int i = 0; i < len; i++) {
+ write(cbuf[off + i]);
+ }
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ if (isJavaIdentifierPart((char) b) && b != ESCAPE_CHAR) {
+ out.write(b);
+ } else {
+ out.write(ESCAPE_CHAR); // Escape character
+ // Special escape
+ if (b >= 0 && b < FREE_CHARS) {
+ out.write(CHAR_MAP[b]);
+ } else { // Normal escape
+ final char[] tmp = Integer.toHexString(b).toCharArray();
+ if (tmp.length == 1) {
+ out.write('0');
+ out.write(tmp[0]);
+ } else {
+ out.write(tmp[0]);
+ out.write(tmp[1]);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void write(final String str, final int off, final int len) throws IOException {
+ write(str.toCharArray(), off, len);
+ }
+ }
+
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java b/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java
index 6852dc9..5e486b4 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ARRAYLENGTH.java
@@ -53,6 +53,6 @@ public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackP
*/
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION};
+ return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java b/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java
index 053123e..3652c89 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ATHROW.java
@@ -53,6 +53,6 @@ public class ATHROW extends Instruction implements UnconditionalBranch, Exceptio
*/
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.THROWABLE};
+ return new Class[]{ExceptionConst.THROWABLE};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java b/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java
index efeafb6..9bd080b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/AnnotationEntryGen.java
@@ -28,11 +28,43 @@ import java.util.List;
public class AnnotationEntryGen {
static final AnnotationEntryGen[] EMPTY_ARRAY = {};
+ private final ConstantPoolGen cpool;
+ private int typeIndex;
+ private List evs;
+ private boolean isRuntimeVisible;
+
+ /**
+ * Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool
+ * passed in is for a different class file, then copyPoolEntries should have been passed as true as that will force us
+ * to do a deep copy of the annotation and move the cpool entries across. We need to copy the type and the element name
+ * value pairs and the visibility.
+ */
+ public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
+ this.cpool = cpool;
+ if (copyPoolEntries) {
+ typeIndex = cpool.addUtf8(a.getAnnotationType());
+ } else {
+ typeIndex = a.getAnnotationTypeIndex();
+ }
+ isRuntimeVisible = a.isRuntimeVisible();
+ evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries);
+ }
+
+ private AnnotationEntryGen(final ConstantPoolGen cpool) {
+ this.cpool = cpool;
+ }
+
+ public AnnotationEntryGen(final ObjectType type, final List elements, final boolean vis, final ConstantPoolGen cpool) {
+ this.cpool = cpool;
+ this.typeIndex = cpool.addUtf8(type.getSignature());
+ evs = elements;
+ isRuntimeVisible = vis;
+ }
/**
* Converts a list of AnnotationGen objects into a set of attributes that can be attached to the class file.
*
- * @param cp The constant pool gen where we can create the necessary name refs
+ * @param cp The constant pool gen where we can create the necessary name refs
* @param annotationEntryGens An array of AnnotationGen objects
*/
static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) {
@@ -86,11 +118,11 @@ public class AnnotationEntryGen {
final List newAttributes = new ArrayList<>();
if (rvaData.length > 2) {
newAttributes
- .add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool()));
+ .add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool()));
}
if (riaData.length > 2) {
newAttributes.add(
- new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool()));
+ new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool()));
}
return newAttributes.toArray(Attribute.EMPTY_ARRAY);
@@ -106,7 +138,7 @@ public class AnnotationEntryGen {
* RuntimeInvisibleParameterAnnotations
*/
static Attribute[] getParameterAnnotationAttributes(final ConstantPoolGen cp,
- final List[] /* Array of lists, array size depends on #params */ vec) {
+ final List[] /* Array of lists, array size depends on #params */ vec) {
final int[] visCount = new int[vec.length];
int totalVisCount = 0;
final int[] invisCount = new int[vec.length];
@@ -168,11 +200,11 @@ public class AnnotationEntryGen {
final List newAttributes = new ArrayList<>();
if (totalVisCount > 0) {
newAttributes.add(new RuntimeVisibleParameterAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)),
- cp.getConstantPool()));
+ cp.getConstantPool()));
}
if (totalInvisCount > 0) {
newAttributes.add(new RuntimeInvisibleParameterAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)),
- cp.getConstantPool()));
+ cp.getConstantPool()));
}
return newAttributes.toArray(Attribute.EMPTY_ARRAY);
} catch (final IOException e) {
@@ -194,42 +226,6 @@ public class AnnotationEntryGen {
return a;
}
- private int typeIndex;
-
- private List evs;
-
- private final ConstantPoolGen cpool;
-
- private boolean isRuntimeVisible;
-
- /**
- * Here we are taking a fixed annotation of type Annotation and building a modifiable AnnotationGen object. If the pool
- * passed in is for a different class file, then copyPoolEntries should have been passed as true as that will force us
- * to do a deep copy of the annotation and move the cpool entries across. We need to copy the type and the element name
- * value pairs and the visibility.
- */
- public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
- this.cpool = cpool;
- if (copyPoolEntries) {
- typeIndex = cpool.addUtf8(a.getAnnotationType());
- } else {
- typeIndex = a.getAnnotationTypeIndex();
- }
- isRuntimeVisible = a.isRuntimeVisible();
- evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries);
- }
-
- private AnnotationEntryGen(final ConstantPoolGen cpool) {
- this.cpool = cpool;
- }
-
- public AnnotationEntryGen(final ObjectType type, final List elements, final boolean vis, final ConstantPoolGen cpool) {
- this.cpool = cpool;
- this.typeIndex = cpool.addUtf8(type.getSignature());
- evs = elements;
- isRuntimeVisible = vis;
- }
-
public void addElementNameValuePair(final ElementValuePairGen evp) {
if (evs == null) {
evs = new ArrayList<>();
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java
index 4743eb4..5c39975 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ArithmeticInstruction.java
@@ -43,48 +43,48 @@ public abstract class ArithmeticInstruction extends Instruction implements Typed
public Type getType(final ConstantPoolGen cp) {
final short opcode = super.getOpcode();
switch (opcode) {
- case Const.DADD:
- case Const.DDIV:
- case Const.DMUL:
- case Const.DNEG:
- case Const.DREM:
- case Const.DSUB:
- return Type.DOUBLE;
- case Const.FADD:
- case Const.FDIV:
- case Const.FMUL:
- case Const.FNEG:
- case Const.FREM:
- case Const.FSUB:
- return Type.FLOAT;
- case Const.IADD:
- case Const.IAND:
- case Const.IDIV:
- case Const.IMUL:
- case Const.INEG:
- case Const.IOR:
- case Const.IREM:
- case Const.ISHL:
- case Const.ISHR:
- case Const.ISUB:
- case Const.IUSHR:
- case Const.IXOR:
- return Type.INT;
- case Const.LADD:
- case Const.LAND:
- case Const.LDIV:
- case Const.LMUL:
- case Const.LNEG:
- case Const.LOR:
- case Const.LREM:
- case Const.LSHL:
- case Const.LSHR:
- case Const.LSUB:
- case Const.LUSHR:
- case Const.LXOR:
- return Type.LONG;
- default: // Never reached
- throw new ClassGenException("Unknown type " + opcode);
+ case Const.DADD:
+ case Const.DDIV:
+ case Const.DMUL:
+ case Const.DNEG:
+ case Const.DREM:
+ case Const.DSUB:
+ return Type.DOUBLE;
+ case Const.FADD:
+ case Const.FDIV:
+ case Const.FMUL:
+ case Const.FNEG:
+ case Const.FREM:
+ case Const.FSUB:
+ return Type.FLOAT;
+ case Const.IADD:
+ case Const.IAND:
+ case Const.IDIV:
+ case Const.IMUL:
+ case Const.INEG:
+ case Const.IOR:
+ case Const.IREM:
+ case Const.ISHL:
+ case Const.ISHR:
+ case Const.ISUB:
+ case Const.IUSHR:
+ case Const.IXOR:
+ return Type.INT;
+ case Const.LADD:
+ case Const.LAND:
+ case Const.LDIV:
+ case Const.LMUL:
+ case Const.LNEG:
+ case Const.LOR:
+ case Const.LREM:
+ case Const.LSHL:
+ case Const.LSHR:
+ case Const.LSUB:
+ case Const.LUSHR:
+ case Const.LXOR:
+ return Type.LONG;
+ default: // Never reached
+ throw new ClassGenException("Unknown type " + opcode);
}
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java
index fdb7803..307e1ba 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ArrayInstruction.java
@@ -49,32 +49,32 @@ public abstract class ArrayInstruction extends Instruction implements ExceptionT
public Type getType(final ConstantPoolGen cp) {
final short opcode = super.getOpcode();
switch (opcode) {
- case Const.IALOAD:
- case Const.IASTORE:
- return Type.INT;
- case Const.CALOAD:
- case Const.CASTORE:
- return Type.CHAR;
- case Const.BALOAD:
- case Const.BASTORE:
- return Type.BYTE;
- case Const.SALOAD:
- case Const.SASTORE:
- return Type.SHORT;
- case Const.LALOAD:
- case Const.LASTORE:
- return Type.LONG;
- case Const.DALOAD:
- case Const.DASTORE:
- return Type.DOUBLE;
- case Const.FALOAD:
- case Const.FASTORE:
- return Type.FLOAT;
- case Const.AALOAD:
- case Const.AASTORE:
- return Type.OBJECT;
- default:
- throw new ClassGenException("Unknown case in switch" + opcode);
+ case Const.IALOAD:
+ case Const.IASTORE:
+ return Type.INT;
+ case Const.CALOAD:
+ case Const.CASTORE:
+ return Type.CHAR;
+ case Const.BALOAD:
+ case Const.BASTORE:
+ return Type.BYTE;
+ case Const.SALOAD:
+ case Const.SASTORE:
+ return Type.SHORT;
+ case Const.LALOAD:
+ case Const.LASTORE:
+ return Type.LONG;
+ case Const.DALOAD:
+ case Const.DASTORE:
+ return Type.DOUBLE;
+ case Const.FALOAD:
+ case Const.FASTORE:
+ return Type.FLOAT;
+ case Const.AALOAD:
+ case Const.AASTORE:
+ return Type.OBJECT;
+ default:
+ throw new ClassGenException("Unknown case in switch" + opcode);
}
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java b/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java
index 5f8f746..19caf4d 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ArrayType.java
@@ -29,7 +29,7 @@ public final class ArrayType extends ReferenceType {
/**
* Convenience constructor for array type, e.g. int[]
*
- * @param type array type, e.g. T_INT
+ * @param type array type, e.g. T_INT
* @param dimensions array dimensions
*/
public ArrayType(final byte type, final int dimensions) {
@@ -39,7 +39,7 @@ public final class ArrayType extends ReferenceType {
/**
* Convenience constructor for reference array type, e.g. Object[]
*
- * @param className complete name of class (java.lang.String, e.g.)
+ * @param className complete name of class (java.lang.String, e.g.)
* @param dimensions array dimensions
*/
public ArrayType(final String className, final int dimensions) {
@@ -49,7 +49,7 @@ public final class ArrayType extends ReferenceType {
/**
* Constructor for array of given type
*
- * @param type type of array (may be an array itself)
+ * @param type type of array (may be an array itself)
* @param dimensions array dimensions
*/
public ArrayType(final Type type, final int dimensions) {
@@ -58,17 +58,17 @@ public final class ArrayType extends ReferenceType {
throw new ClassGenException("Invalid number of dimensions: " + dimensions);
}
switch (type.getType()) {
- case Const.T_ARRAY:
- final ArrayType array = (ArrayType) type;
- this.dimensions = dimensions + array.dimensions;
- basicType = array.basicType;
- break;
- case Const.T_VOID:
- throw new ClassGenException("Invalid type: void[]");
- default: // Basic type or reference
- this.dimensions = dimensions;
- basicType = type;
- break;
+ case Const.T_ARRAY:
+ final ArrayType array = (ArrayType) type;
+ this.dimensions = dimensions + array.dimensions;
+ basicType = array.basicType;
+ break;
+ case Const.T_VOID:
+ throw new ClassGenException("Invalid type: void[]");
+ default: // Basic type or reference
+ this.dimensions = dimensions;
+ basicType = type;
+ break;
}
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < this.dimensions; i++) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/BasicType.java b/src/main/java/haidnor/jvm/bcel/generic/BasicType.java
index 5af9a28..1a3e8a5 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/BasicType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/BasicType.java
@@ -23,32 +23,6 @@ import haidnor.jvm.bcel.Const;
*/
public final class BasicType extends Type {
- // @since 6.0 no longer final
- public static BasicType getType(final byte type) {
- switch (type) {
- case Const.T_VOID:
- return VOID;
- case Const.T_BOOLEAN:
- return BOOLEAN;
- case Const.T_BYTE:
- return BYTE;
- case Const.T_SHORT:
- return SHORT;
- case Const.T_CHAR:
- return CHAR;
- case Const.T_INT:
- return INT;
- case Const.T_LONG:
- return LONG;
- case Const.T_DOUBLE:
- return DOUBLE;
- case Const.T_FLOAT:
- return FLOAT;
- default:
- throw new ClassGenException("Invalid type: " + type);
- }
- }
-
/**
* Constructor for basic types such as int, long, 'void'
*
@@ -62,6 +36,32 @@ public final class BasicType extends Type {
}
}
+ // @since 6.0 no longer final
+ public static BasicType getType(final byte type) {
+ switch (type) {
+ case Const.T_VOID:
+ return VOID;
+ case Const.T_BOOLEAN:
+ return BOOLEAN;
+ case Const.T_BYTE:
+ return BYTE;
+ case Const.T_SHORT:
+ return SHORT;
+ case Const.T_CHAR:
+ return CHAR;
+ case Const.T_INT:
+ return INT;
+ case Const.T_LONG:
+ return LONG;
+ case Const.T_DOUBLE:
+ return DOUBLE;
+ case Const.T_FLOAT:
+ return FLOAT;
+ default:
+ throw new ClassGenException("Invalid type: " + type);
+ }
+ }
+
/**
* @return true if both type objects refer to the same type
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java b/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java
index deb8a97..61a24aa 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/BranchHandle.java
@@ -26,13 +26,6 @@ package haidnor.jvm.bcel.generic;
*/
public final class BranchHandle extends InstructionHandle {
- /**
- * Factory method.
- */
- static BranchHandle getBranchHandle(final BranchInstruction i) {
- return new BranchHandle(i);
- }
-
// This is also a cache in case the InstructionHandle#swapInstruction() method is used
// See BCEL-273
private BranchInstruction bi; // An alias in fact, but saves lots of casts
@@ -42,6 +35,13 @@ public final class BranchHandle extends InstructionHandle {
bi = i;
}
+ /**
+ * Factory method.
+ */
+ static BranchHandle getBranchHandle(final BranchInstruction i) {
+ return new BranchHandle(i);
+ }
+
/*
* Override InstructionHandle methods: delegate to branch instruction. Through this overriding all access to the private
* i_position field should be prevented.
@@ -51,6 +51,13 @@ public final class BranchHandle extends InstructionHandle {
return bi.getPosition();
}
+ @Override
+ void setPosition(final int pos) {
+ // Original code: i_position = bi.position = pos;
+ bi.setPosition(pos);
+ super.setPosition(pos);
+ }
+
/**
* @return target of instruction.
*/
@@ -58,6 +65,13 @@ public final class BranchHandle extends InstructionHandle {
return bi.getTarget();
}
+ /**
+ * Pass new target to instruction.
+ */
+ public void setTarget(final InstructionHandle ih) {
+ bi.setTarget(ih);
+ }
+
/**
* Set new contents. Old instruction is disposed and may not be used anymore.
*/
@@ -70,20 +84,6 @@ public final class BranchHandle extends InstructionHandle {
bi = (BranchInstruction) i;
}
- @Override
- void setPosition(final int pos) {
- // Original code: i_position = bi.position = pos;
- bi.setPosition(pos);
- super.setPosition(pos);
- }
-
- /**
- * Pass new target to instruction.
- */
- public void setTarget(final InstructionHandle ih) {
- bi.setTarget(ih);
- }
-
@Override
protected int updatePosition(final int offset, final int maxOffset) {
final int x = bi.updatePosition(offset, maxOffset);
diff --git a/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java
index e27d21a..3babe3b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/BranchInstruction.java
@@ -29,30 +29,16 @@ import java.io.IOException;
*/
public abstract class BranchInstruction extends Instruction implements InstructionTargeter {
- /**
- * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen, LineNumberGen
- */
- static void notifyTarget(final InstructionHandle oldIh, final InstructionHandle newIh, final InstructionTargeter t) {
- if (oldIh != null) {
- oldIh.removeTargeter(t);
- }
- if (newIh != null) {
- newIh.addTargeter(t);
- }
- }
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected int index; // Branch target relative to this instruction
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected InstructionHandle target; // Target object in instruction list
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@@ -76,6 +62,18 @@ public abstract class BranchInstruction extends Instruction implements Instructi
setTarget(target);
}
+ /**
+ * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen, LineNumberGen
+ */
+ static void notifyTarget(final InstructionHandle oldIh, final InstructionHandle newIh, final InstructionTargeter t) {
+ if (oldIh != null) {
+ oldIh.removeTargeter(t);
+ }
+ if (newIh != null) {
+ newIh.addTargeter(t);
+ }
+ }
+
/**
* @return true, if ih is target of this instruction
*/
@@ -116,6 +114,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return index;
}
+ /**
+ * @param index the index to set
+ * @since 6.0
+ */
+ protected void setIndex(final int index) {
+ this.index = index;
+ }
+
/**
* @return the position
* @since 6.0
@@ -124,6 +130,14 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return position;
}
+ /**
+ * @param position the position to set
+ * @since 6.0
+ */
+ protected void setPosition(final int position) {
+ this.position = position;
+ }
+
/**
* @return target of branch instruction
*/
@@ -131,6 +145,16 @@ public abstract class BranchInstruction extends Instruction implements Instructi
return target;
}
+ /**
+ * Set branch target
+ *
+ * @param target branch target
+ */
+ public void setTarget(final InstructionHandle target) {
+ notifyTarget(this.target, target, this);
+ this.target = target;
+ }
+
/**
* @return the offset to this instruction's target
*/
@@ -157,7 +181,7 @@ public abstract class BranchInstruction extends Instruction implements Instructi
* Read needed data (e.g. index) from file. Conversion to a InstructionHandle is done in InstructionList(byte[]).
*
* @param bytes input stream
- * @param wide wide prefix?
+ * @param wide wide prefix?
* @see InstructionList
*/
@Override
@@ -166,35 +190,9 @@ public abstract class BranchInstruction extends Instruction implements Instructi
index = bytes.readShort();
}
- /**
- * @param index the index to set
- * @since 6.0
- */
- protected void setIndex(final int index) {
- this.index = index;
- }
-
- /**
- * @param position the position to set
- * @since 6.0
- */
- protected void setPosition(final int position) {
- this.position = position;
- }
-
- /**
- * Set branch target
- *
- * @param target branch target
- */
- public void setTarget(final InstructionHandle target) {
- notifyTarget(this.target, target, this);
- this.target = target;
- }
-
/**
* Long output format:
- *
+ *
* <position in byte code> <name of opcode> "["<opcode number>"]" "("<length of instruction>")"
* "<"<target instruction>">" "@"<branch target offset>
*
@@ -232,7 +230,7 @@ public abstract class BranchInstruction extends Instruction implements Instructi
* length instructions 'setPositions' performs multiple passes over the instruction list to calculate the correct (byte)
* positions and offsets by calling this function.
*
- * @param offset additional offset caused by preceding (variable length) instructions
+ * @param offset additional offset caused by preceding (variable length) instructions
* @param maxOffset the maximum offset that may be caused by these instructions
* @return additional offset caused by possible change of this instruction's length
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java
index 44ad35d..ffac216 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/CPInstruction.java
@@ -74,6 +74,19 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
return index;
}
+ /**
+ * Set the index to constant pool.
+ *
+ * @param index in constant pool.
+ */
+ @Override
+ public void setIndex(final int index) { // TODO could be package-protected?
+ if (index < 0) {
+ throw new ClassGenException("Negative index value: " + index);
+ }
+ this.index = index;
+ }
+
/**
* @return type related with this instruction.
*/
@@ -91,7 +104,7 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
* Read needed data (i.e., index) from file.
*
* @param bytes input stream
- * @param wide wide prefix?
+ * @param wide wide prefix?
*/
@Override
protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException {
@@ -99,22 +112,9 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
super.setLength(3);
}
- /**
- * Set the index to constant pool.
- *
- * @param index in constant pool.
- */
- @Override
- public void setIndex(final int index) { // TODO could be package-protected?
- if (index < 0) {
- throw new ClassGenException("Negative index value: " + index);
- }
- this.index = index;
- }
-
/**
* Long output format:
- *
+ *
* <name of opcode> "["<opcode number>"]" "("<length of instruction>")" "<"< constant pool
* index>">"
*
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java b/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java
index 1a5e1ad..10fcb78 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ClassGen.java
@@ -45,42 +45,23 @@ public class ClassGen extends AccessFlags implements Cloneable {
return THIS.getClassName().hashCode();
}
};
-
- /**
- * @return Comparison strategy object
- */
- public static BCELComparator getComparator() {
- return bcelComparator;
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
-
+ private final String fileName;
+ // ArrayLists instead of arrays to gather fields, methods, etc.
+ private final List fieldList = new ArrayList<>();
+ private final List methodList = new ArrayList<>();
+ private final List attributeList = new ArrayList<>();
+ private final List interfaceList = new ArrayList<>();
+ private final List annotationList = new ArrayList<>();
/*
* Corresponds to the fields found in a JavaClass object.
*/
private String className;
private String superClassName;
- private final String fileName;
private int classNameIndex = -1;
private int superclassNameIndex = -1;
private int major = Const.MAJOR_1_1;
private int minor = Const.MINOR_1_1;
private ConstantPoolGen cp; // Template for building up constant pool
- // ArrayLists instead of arrays to gather fields, methods, etc.
- private final List fieldList = new ArrayList<>();
- private final List methodList = new ArrayList<>();
-
- private final List attributeList = new ArrayList<>();
-
- private final List interfaceList = new ArrayList<>();
-
- private final List annotationList = new ArrayList<>();
-
private List observers;
/**
@@ -115,11 +96,11 @@ public class ClassGen extends AccessFlags implements Cloneable {
/**
* Convenience constructor to set up some important values initially.
*
- * @param className fully qualified class name
+ * @param className fully qualified class name
* @param superClassName fully qualified superclass name
- * @param fileName source file name
- * @param accessFlags access qualifiers
- * @param interfaces implemented interfaces
+ * @param fileName source file name
+ * @param accessFlags access qualifiers
+ * @param interfaces implemented interfaces
*/
public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces) {
this(className, superClassName, fileName, accessFlags, interfaces, new ConstantPoolGen());
@@ -128,15 +109,15 @@ public class ClassGen extends AccessFlags implements Cloneable {
/**
* Convenience constructor to set up some important values initially.
*
- * @param className fully qualified class name
+ * @param className fully qualified class name
* @param superClassName fully qualified superclass name
- * @param fileName source file name
- * @param accessFlags access qualifiers
- * @param interfaces implemented interfaces
- * @param cp constant pool to use
+ * @param fileName source file name
+ * @param accessFlags access qualifiers
+ * @param interfaces implemented interfaces
+ * @param cp constant pool to use
*/
public ClassGen(final String className, final String superClassName, final String fileName, final int accessFlags, final String[] interfaces,
- final ConstantPoolGen cp) {
+ final ConstantPoolGen cp) {
super(accessFlags);
this.className = className;
this.superClassName = superClassName;
@@ -153,6 +134,20 @@ public class ClassGen extends AccessFlags implements Cloneable {
}
}
+ /**
+ * @return Comparison strategy object
+ */
+ public static BCELComparator getComparator() {
+ return bcelComparator;
+ }
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
public void addAnnotationEntry(final AnnotationEntryGen a) {
annotationList.add(a);
}
@@ -168,7 +163,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
/**
* Convenience method.
- *
+ *
* Add an empty constructor to this class that does nothing but calling super().
*
* @param accessFlags rights for constructor
@@ -281,14 +276,28 @@ public class ClassGen extends AccessFlags implements Cloneable {
return className;
}
+ public void setClassName(final String name) {
+ className = Utility.pathToPackage(name);
+ classNameIndex = cp.addClass(name);
+ }
+
public int getClassNameIndex() {
return classNameIndex;
}
+ public void setClassNameIndex(final int classNameIndex) {
+ this.classNameIndex = classNameIndex;
+ this.className = Utility.pathToPackage(cp.getConstantPool().getConstantString(classNameIndex, Const.CONSTANT_Class));
+ }
+
public ConstantPoolGen getConstantPool() {
return cp;
}
+ public void setConstantPool(final ConstantPoolGen constantPool) {
+ cp = constantPool;
+ }
+
public JavaField[] getFields() {
return fieldList.toArray(JavaField.EMPTY_ARRAY);
}
@@ -328,7 +337,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
// Must be last since the above calls may still add something to it
final ConstantPool cp = this.cp.getFinalConstantPool();
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, super.getAccessFlags(), cp, interfaces, fields, methods,
- attributes);
+ attributes);
}
/**
@@ -338,6 +347,15 @@ public class ClassGen extends AccessFlags implements Cloneable {
return major;
}
+ /**
+ * Set major version number of class file, default value is 45 (JDK 1.1)
+ *
+ * @param major major version number
+ */
+ public void setMajor(final int major) { // TODO could be package-protected - only called by test code
+ this.major = major;
+ }
+
public JavaMethod getMethodAt(final int pos) {
return methodList.get(pos);
}
@@ -346,6 +364,11 @@ public class ClassGen extends AccessFlags implements Cloneable {
return methodList.toArray(JavaMethod.EMPTY_ARRAY);
}
+ public void setMethods(final JavaMethod[] methods) {
+ methodList.clear();
+ Collections.addAll(methodList, methods);
+ }
+
/**
* @return minor version number of class file
*/
@@ -353,14 +376,33 @@ public class ClassGen extends AccessFlags implements Cloneable {
return minor;
}
+ /**
+ * Set minor version number of class file, default value is 3 (JDK 1.1)
+ *
+ * @param minor minor version number
+ */
+ public void setMinor(final int minor) { // TODO could be package-protected - only called by test code
+ this.minor = minor;
+ }
+
public String getSuperclassName() {
return superClassName;
}
+ public void setSuperclassName(final String name) {
+ superClassName = Utility.pathToPackage(name);
+ superclassNameIndex = cp.addClass(name);
+ }
+
public int getSuperclassNameIndex() {
return superclassNameIndex;
}
+ public void setSuperclassNameIndex(final int superclassNameIndex) {
+ this.superclassNameIndex = superclassNameIndex;
+ superClassName = Utility.pathToPackage(cp.getConstantPool().getConstantString(superclassNameIndex, Const.CONSTANT_Class));
+ }
+
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name.
*
@@ -446,57 +488,10 @@ public class ClassGen extends AccessFlags implements Cloneable {
}
}
- public void setClassName(final String name) {
- className = Utility.pathToPackage(name);
- classNameIndex = cp.addClass(name);
- }
-
- public void setClassNameIndex(final int classNameIndex) {
- this.classNameIndex = classNameIndex;
- this.className = Utility.pathToPackage(cp.getConstantPool().getConstantString(classNameIndex, Const.CONSTANT_Class));
- }
-
- public void setConstantPool(final ConstantPoolGen constantPool) {
- cp = constantPool;
- }
-
- /**
- * Set major version number of class file, default value is 45 (JDK 1.1)
- *
- * @param major major version number
- */
- public void setMajor(final int major) { // TODO could be package-protected - only called by test code
- this.major = major;
- }
-
public void setMethodAt(final JavaMethod method, final int pos) {
methodList.set(pos, method);
}
- public void setMethods(final JavaMethod[] methods) {
- methodList.clear();
- Collections.addAll(methodList, methods);
- }
-
- /**
- * Set minor version number of class file, default value is 3 (JDK 1.1)
- *
- * @param minor minor version number
- */
- public void setMinor(final int minor) { // TODO could be package-protected - only called by test code
- this.minor = minor;
- }
-
- public void setSuperclassName(final String name) {
- superClassName = Utility.pathToPackage(name);
- superclassNameIndex = cp.addClass(name);
- }
-
- public void setSuperclassNameIndex(final int superclassNameIndex) {
- this.superclassNameIndex = superclassNameIndex;
- superClassName = Utility.pathToPackage(cp.getConstantPool().getConstantString(superclassNameIndex, Const.CONSTANT_Class));
- }
-
/**
* Look for attributes representing annotations and unpack them.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java b/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java
index f9a65f9..e55dba0 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/CodeExceptionGen.java
@@ -42,8 +42,8 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
* Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling
* is done.
*
- * @param startPc Start of handled region (inclusive)
- * @param endPc End of handled region (inclusive)
+ * @param startPc Start of handled region (inclusive)
+ * @param endPc End of handled region (inclusive)
* @param handlerPc Where handling is done
* @param catchType which exception is handled, null for ANY
*/
@@ -71,14 +71,23 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
return startPc == ih || endPc == ih || handlerPc == ih;
}
- /** Gets the type of the Exception to catch, 'null' for ANY. */
+ /**
+ * Gets the type of the Exception to catch, 'null' for ANY.
+ */
public ObjectType getCatchType() {
return catchType;
}
+ /**
+ * Sets the type of the Exception to catch. Set 'null' for ANY.
+ */
+ public void setCatchType(final ObjectType catchType) {
+ this.catchType = catchType;
+ }
+
/**
* Get CodeException object.
- *
+ *
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
* has been called for the instruction list.
*
@@ -86,7 +95,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
*/
public CodeException getCodeException(final ConstantPoolGen cp) {
return new CodeException(startPc.getPosition(), endPc.getPosition() + endPc.getInstruction().getLength(), handlerPc.getPosition(),
- catchType == null ? 0 : cp.addClass(catchType));
+ catchType == null ? 0 : cp.addClass(catchType));
}
/**
@@ -96,25 +105,6 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
return endPc;
}
- /**
- * @return start of handler
- */
- public InstructionHandle getHandlerPC() {
- return handlerPc;
- }
-
- /**
- * @return start of handled region (inclusive)
- */
- public InstructionHandle getStartPC() {
- return startPc;
- }
-
- /** Sets the type of the Exception to catch. Set 'null' for ANY. */
- public void setCatchType(final ObjectType catchType) {
- this.catchType = catchType;
- }
-
/*
* Set end of handler
*
@@ -125,6 +115,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
this.endPc = endPc;
}
+ /**
+ * @return start of handler
+ */
+ public InstructionHandle getHandlerPC() {
+ return handlerPc;
+ }
+
/*
* Set handler code
*
@@ -135,6 +132,13 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
this.handlerPc = handlerPc;
}
+ /**
+ * @return start of handled region (inclusive)
+ */
+ public InstructionHandle getStartPC() {
+ return startPc;
+ }
+
/*
* Set start of handler
*
diff --git a/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java
index 104d96e..bc6a910 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/CompoundInstruction.java
@@ -21,7 +21,7 @@ package haidnor.jvm.bcel.generic;
* meaning. For example, the (virtual) PUSH instruction takes an arbitrary argument and produces the appropriate code at
* dump time (ICONST, LDC, BIPUSH, ...). Also you can use the SWITCH instruction as a useful template for either
* LOOKUPSWITCH or TABLESWITCH.
- *
+ *
* The interface provides the possibility for the user to write 'templates' or 'macros' for such reusable code patterns.
*
* @see PUSH
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java b/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java
index cf7cdd2..8c7b40f 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ConstantPoolGen.java
@@ -44,35 +44,27 @@ public class ConstantPoolGen {
private static final String FIELDREF_DELIM = "&";
private static final String NAT_DELIM = "%"; // Name and Type
-
+ private final Map stringTable = new HashMap<>();
+ private final Map classTable = new HashMap<>();
+ private final Map utf8Table = new HashMap<>();
+ private final Map natTable = new HashMap<>();
+ private final Map cpTable = new HashMap<>();
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected int size;
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected Constant[] constants;
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getSize()
*/
@Deprecated
protected int index = 1; // First entry (0) used by JVM
- private final Map stringTable = new HashMap<>();
-
- private final Map classTable = new HashMap<>();
-
- private final Map utf8Table = new HashMap<>();
-
- private final Map natTable = new HashMap<>();
-
- private final Map cpTable = new HashMap<>();
-
/**
* Constructs a new empty constant pool.
*/
@@ -255,63 +247,63 @@ public class ConstantPoolGen {
* Adds a constant from another ConstantPool and returns the new index.
*
* @param constant The constant to add.
- * @param cpGen Source pool.
+ * @param cpGen Source pool.
* @return index of entry
*/
public int addConstant(final Constant constant, final ConstantPoolGen cpGen) {
final Constant[] constants = cpGen.getConstantPool().getConstantPool();
switch (constant.getTag()) {
- case Const.CONSTANT_String: {
- final ConstantString s = (ConstantString) constant;
- final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
- return addString(u8.getBytes());
- }
- case Const.CONSTANT_Class: {
- final ConstantClass s = (ConstantClass) constant;
- final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
- return addClass(u8.getBytes());
- }
- case Const.CONSTANT_NameAndType: {
- final ConstantNameAndType n = (ConstantNameAndType) constant;
- final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
- final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
- return addNameAndType(u8.getBytes(), u8_2.getBytes());
- }
- case Const.CONSTANT_Utf8:
- return addUtf8(((ConstantUtf8) constant).getBytes());
- case Const.CONSTANT_Double:
- return addDouble(((ConstantDouble) constant).getBytes());
- case Const.CONSTANT_Float:
- return addFloat(((ConstantFloat) constant).getBytes());
- case Const.CONSTANT_Long:
- return addLong(((ConstantLong) constant).getBytes());
- case Const.CONSTANT_Integer:
- return addInteger(((ConstantInteger) constant).getBytes());
- case Const.CONSTANT_InterfaceMethodref:
- case Const.CONSTANT_Methodref:
- case Const.CONSTANT_Fieldref: {
- final ConstantCP m = (ConstantCP) constant;
- final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
- final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
- ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
- final String className = Utility.pathToPackage(u8.getBytes());
- u8 = (ConstantUtf8) constants[n.getNameIndex()];
- final String name = u8.getBytes();
- u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
- final String signature = u8.getBytes();
- switch (constant.getTag()) {
+ case Const.CONSTANT_String: {
+ final ConstantString s = (ConstantString) constant;
+ final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
+ return addString(u8.getBytes());
+ }
+ case Const.CONSTANT_Class: {
+ final ConstantClass s = (ConstantClass) constant;
+ final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
+ return addClass(u8.getBytes());
+ }
+ case Const.CONSTANT_NameAndType: {
+ final ConstantNameAndType n = (ConstantNameAndType) constant;
+ final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
+ final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
+ return addNameAndType(u8.getBytes(), u8_2.getBytes());
+ }
+ case Const.CONSTANT_Utf8:
+ return addUtf8(((ConstantUtf8) constant).getBytes());
+ case Const.CONSTANT_Double:
+ return addDouble(((ConstantDouble) constant).getBytes());
+ case Const.CONSTANT_Float:
+ return addFloat(((ConstantFloat) constant).getBytes());
+ case Const.CONSTANT_Long:
+ return addLong(((ConstantLong) constant).getBytes());
+ case Const.CONSTANT_Integer:
+ return addInteger(((ConstantInteger) constant).getBytes());
case Const.CONSTANT_InterfaceMethodref:
- return addInterfaceMethodref(className, name, signature);
case Const.CONSTANT_Methodref:
- return addMethodref(className, name, signature);
- case Const.CONSTANT_Fieldref:
- return addFieldref(className, name, signature);
+ case Const.CONSTANT_Fieldref: {
+ final ConstantCP m = (ConstantCP) constant;
+ final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
+ final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
+ ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
+ final String className = Utility.pathToPackage(u8.getBytes());
+ u8 = (ConstantUtf8) constants[n.getNameIndex()];
+ final String name = u8.getBytes();
+ u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
+ final String signature = u8.getBytes();
+ switch (constant.getTag()) {
+ case Const.CONSTANT_InterfaceMethodref:
+ return addInterfaceMethodref(className, name, signature);
+ case Const.CONSTANT_Methodref:
+ return addMethodref(className, name, signature);
+ case Const.CONSTANT_Fieldref:
+ return addFieldref(className, name, signature);
+ default: // Never reached
+ throw new IllegalArgumentException("Unknown constant type " + constant);
+ }
+ }
default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + constant);
- }
- }
- default: // Never reached
- throw new IllegalArgumentException("Unknown constant type " + constant);
}
}
@@ -395,9 +387,9 @@ public class ConstantPoolGen {
/**
* Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there.
*
- * @param className class name string to add
+ * @param className class name string to add
* @param methodName method name string to add
- * @param signature signature string to add
+ * @param signature signature string to add
* @return index of entry
*/
public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
@@ -430,6 +422,7 @@ public class ConstantPoolGen {
index += 2; // Wastes one entry according to spec
return ret;
}
+
public int addMethodref(final MethodGen method) {
return addMethodref(method.getClassName(), method.getName(), method.getSignature());
}
@@ -437,9 +430,9 @@ public class ConstantPoolGen {
/**
* Add a new Methodref constant to the ConstantPool, if it is not already in there.
*
- * @param className class name string to add
+ * @param className class name string to add
* @param methodName method name string to add
- * @param signature method signature string to add
+ * @param signature method signature string to add
* @return index of entry
*/
public int addMethodref(final String className, final String methodName, final String signature) {
@@ -458,7 +451,7 @@ public class ConstantPoolGen {
/**
* Add a new NameAndType constant to the ConstantPool if it is not already in there.
*
- * @param name Name string to add
+ * @param name Name string to add
* @param signature signature string to add
* @return index of entry
*/
@@ -654,9 +647,9 @@ public class ConstantPoolGen {
/**
* Look for ConstantInterfaceMethodref in ConstantPool.
*
- * @param className Where to find method
+ * @param className Where to find method
* @param methodName Guess what
- * @param signature return and argument types
+ * @param signature return and argument types
* @return index on success, -1 otherwise
*/
public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
@@ -688,9 +681,9 @@ public class ConstantPoolGen {
/**
* Look for ConstantMethodref in ConstantPool.
*
- * @param className Where to find method
+ * @param className Where to find method
* @param methodName Guess what
- * @param signature return and argument types
+ * @param signature return and argument types
* @return index on success, -1 otherwise
*/
public int lookupMethodref(final String className, final String methodName, final String signature) {
@@ -700,7 +693,7 @@ public class ConstantPoolGen {
/**
* Look for ConstantNameAndType in ConstantPool.
*
- * @param name of variable/method
+ * @param name of variable/method
* @param signature of variable/method
* @return index on success, -1 otherwise
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java
index 9112c60..bdf8d2b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ConstantPushInstruction.java
@@ -19,7 +19,6 @@ package haidnor.jvm.bcel.generic;
/**
* Denotes a push instruction that produces a literal on the stack such as SIPUSH, BIPUSH, ICONST, etc.
*
- *
* @see ICONST
* @see SIPUSH
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java
index abfbd19..d6f00d8 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ConversionInstruction.java
@@ -43,30 +43,30 @@ public abstract class ConversionInstruction extends Instruction implements Typed
public Type getType(final ConstantPoolGen cp) {
final short opcode = super.getOpcode();
switch (opcode) {
- case Const.D2I:
- case Const.F2I:
- case Const.L2I:
- return Type.INT;
- case Const.D2F:
- case Const.I2F:
- case Const.L2F:
- return Type.FLOAT;
- case Const.D2L:
- case Const.F2L:
- case Const.I2L:
- return Type.LONG;
- case Const.F2D:
- case Const.I2D:
- case Const.L2D:
- return Type.DOUBLE;
- case Const.I2B:
- return Type.BYTE;
- case Const.I2C:
- return Type.CHAR;
- case Const.I2S:
- return Type.SHORT;
- default: // Never reached
- throw new ClassGenException("Unknown type " + opcode);
+ case Const.D2I:
+ case Const.F2I:
+ case Const.L2I:
+ return Type.INT;
+ case Const.D2F:
+ case Const.I2F:
+ case Const.L2F:
+ return Type.FLOAT;
+ case Const.D2L:
+ case Const.F2L:
+ case Const.I2L:
+ return Type.LONG;
+ case Const.F2D:
+ case Const.I2D:
+ case Const.L2D:
+ return Type.DOUBLE;
+ case Const.I2B:
+ return Type.BYTE;
+ case Const.I2C:
+ return Type.CHAR;
+ case Const.I2S:
+ return Type.SHORT;
+ default: // Never reached
+ throw new ClassGenException("Unknown type " + opcode);
}
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/DADD.java b/src/main/java/haidnor/jvm/bcel/generic/DADD.java
index eb51578..0ed4336 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/DADD.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/DADD.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result1.word2
*/
public class DADD extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/DDIV.java b/src/main/java/haidnor/jvm/bcel/generic/DDIV.java
index fedb009..e419b58 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/DDIV.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/DDIV.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class DDIV extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/DMUL.java b/src/main/java/haidnor/jvm/bcel/generic/DMUL.java
index cc0b95f..d33ef96 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/DMUL.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/DMUL.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class DMUL extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/DREM.java b/src/main/java/haidnor/jvm/bcel/generic/DREM.java
index 78c87a3..f1531de 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/DREM.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/DREM.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class DREM extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/DSUB.java b/src/main/java/haidnor/jvm/bcel/generic/DSUB.java
index 9742bb9..9f47378 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/DSUB.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/DSUB.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class DSUB extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java b/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java
index 489730b..29fe1b8 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ElementValueGen.java
@@ -52,83 +52,11 @@ public abstract class ElementValueGen {
public static final int PRIMITIVE_SHORT = 'S';
public static final int PRIMITIVE_BOOLEAN = 'Z';
-
- /**
- * Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct.
- */
- public static ElementValueGen copy(final ElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
- switch (value.getElementValueType()) {
- case 'B': // byte
- case 'C': // char
- case 'D': // double
- case 'F': // float
- case 'I': // int
- case 'J': // long
- case 'S': // short
- case 'Z': // boolean
- case 's': // String
- return new SimpleElementValueGen((SimpleElementValue) value, cpool, copyPoolEntries);
- case 'e': // Enum constant
- return new EnumElementValueGen((EnumElementValue) value, cpool, copyPoolEntries);
- case '@': // Annotation
- return new AnnotationElementValueGen((AnnotationElementValue) value, cpool, copyPoolEntries);
- case '[': // Array
- return new ArrayElementValueGen((ArrayElementValue) value, cpool, copyPoolEntries);
- case 'c': // Class
- return new ClassElementValueGen((ClassElementValue) value, cpool, copyPoolEntries);
- default:
- throw new UnsupportedOperationException("Not implemented yet! (" + value.getElementValueType() + ")");
- }
- }
-
- public static ElementValueGen readElementValue(final DataInput dis, final ConstantPoolGen cpGen) throws IOException {
- final int type = dis.readUnsignedByte();
- switch (type) {
- case 'B': // byte
- return new SimpleElementValueGen(PRIMITIVE_BYTE, dis.readUnsignedShort(), cpGen);
- case 'C': // char
- return new SimpleElementValueGen(PRIMITIVE_CHAR, dis.readUnsignedShort(), cpGen);
- case 'D': // double
- return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis.readUnsignedShort(), cpGen);
- case 'F': // float
- return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis.readUnsignedShort(), cpGen);
- case 'I': // int
- return new SimpleElementValueGen(PRIMITIVE_INT, dis.readUnsignedShort(), cpGen);
- case 'J': // long
- return new SimpleElementValueGen(PRIMITIVE_LONG, dis.readUnsignedShort(), cpGen);
- case 'S': // short
- return new SimpleElementValueGen(PRIMITIVE_SHORT, dis.readUnsignedShort(), cpGen);
- case 'Z': // boolean
- return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis.readUnsignedShort(), cpGen);
- case 's': // String
- return new SimpleElementValueGen(STRING, dis.readUnsignedShort(), cpGen);
- case 'e': // Enum constant
- return new EnumElementValueGen(dis.readUnsignedShort(), dis.readUnsignedShort(), cpGen);
- case 'c': // Class
- return new ClassElementValueGen(dis.readUnsignedShort(), cpGen);
- case '@': // Annotation
- // TODO: isRuntimeVisible ??????????
- // FIXME
- return new AnnotationElementValueGen(ANNOTATION, new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen.getConstantPool(), true), cpGen, false),
- cpGen);
- case '[': // Array
- final int numArrayVals = dis.readUnsignedShort();
- final ElementValue[] evalues = new ElementValue[numArrayVals];
- for (int j = 0; j < numArrayVals; j++) {
- evalues[j] = ElementValue.readElementValue(dis, cpGen.getConstantPool());
- }
- return new ArrayElementValueGen(ARRAY, evalues, cpGen);
- default:
- throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type);
- }
- }
-
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@Deprecated
protected int type;
-
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@@ -140,6 +68,76 @@ public abstract class ElementValueGen {
this.cpGen = cpGen;
}
+ /**
+ * Creates an (modifiable) ElementValueGen copy of an (immutable) ElementValue - constant pool is assumed correct.
+ */
+ public static ElementValueGen copy(final ElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
+ switch (value.getElementValueType()) {
+ case 'B': // byte
+ case 'C': // char
+ case 'D': // double
+ case 'F': // float
+ case 'I': // int
+ case 'J': // long
+ case 'S': // short
+ case 'Z': // boolean
+ case 's': // String
+ return new SimpleElementValueGen((SimpleElementValue) value, cpool, copyPoolEntries);
+ case 'e': // Enum constant
+ return new EnumElementValueGen((EnumElementValue) value, cpool, copyPoolEntries);
+ case '@': // Annotation
+ return new AnnotationElementValueGen((AnnotationElementValue) value, cpool, copyPoolEntries);
+ case '[': // Array
+ return new ArrayElementValueGen((ArrayElementValue) value, cpool, copyPoolEntries);
+ case 'c': // Class
+ return new ClassElementValueGen((ClassElementValue) value, cpool, copyPoolEntries);
+ default:
+ throw new UnsupportedOperationException("Not implemented yet! (" + value.getElementValueType() + ")");
+ }
+ }
+
+ public static ElementValueGen readElementValue(final DataInput dis, final ConstantPoolGen cpGen) throws IOException {
+ final int type = dis.readUnsignedByte();
+ switch (type) {
+ case 'B': // byte
+ return new SimpleElementValueGen(PRIMITIVE_BYTE, dis.readUnsignedShort(), cpGen);
+ case 'C': // char
+ return new SimpleElementValueGen(PRIMITIVE_CHAR, dis.readUnsignedShort(), cpGen);
+ case 'D': // double
+ return new SimpleElementValueGen(PRIMITIVE_DOUBLE, dis.readUnsignedShort(), cpGen);
+ case 'F': // float
+ return new SimpleElementValueGen(PRIMITIVE_FLOAT, dis.readUnsignedShort(), cpGen);
+ case 'I': // int
+ return new SimpleElementValueGen(PRIMITIVE_INT, dis.readUnsignedShort(), cpGen);
+ case 'J': // long
+ return new SimpleElementValueGen(PRIMITIVE_LONG, dis.readUnsignedShort(), cpGen);
+ case 'S': // short
+ return new SimpleElementValueGen(PRIMITIVE_SHORT, dis.readUnsignedShort(), cpGen);
+ case 'Z': // boolean
+ return new SimpleElementValueGen(PRIMITIVE_BOOLEAN, dis.readUnsignedShort(), cpGen);
+ case 's': // String
+ return new SimpleElementValueGen(STRING, dis.readUnsignedShort(), cpGen);
+ case 'e': // Enum constant
+ return new EnumElementValueGen(dis.readUnsignedShort(), dis.readUnsignedShort(), cpGen);
+ case 'c': // Class
+ return new ClassElementValueGen(dis.readUnsignedShort(), cpGen);
+ case '@': // Annotation
+ // TODO: isRuntimeVisible ??????????
+ // FIXME
+ return new AnnotationElementValueGen(ANNOTATION, new AnnotationEntryGen(AnnotationEntry.read(dis, cpGen.getConstantPool(), true), cpGen, false),
+ cpGen);
+ case '[': // Array
+ final int numArrayVals = dis.readUnsignedShort();
+ final ElementValue[] evalues = new ElementValue[numArrayVals];
+ for (int j = 0; j < numArrayVals; j++) {
+ evalues[j] = ElementValue.readElementValue(dis, cpGen.getConstantPool());
+ }
+ return new ArrayElementValueGen(ARRAY, evalues, cpGen);
+ default:
+ throw new IllegalArgumentException("Unexpected element value kind in annotation: " + type);
+ }
+ }
+
public abstract void dump(DataOutputStream dos) throws IOException;
protected ConstantPoolGen getConstantPool() {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java b/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java
index 87c6c67..d4e2e08 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/EnumElementValueGen.java
@@ -36,9 +36,9 @@ public class EnumElementValueGen extends ElementValueGen {
super(ENUM_CONSTANT, cpool);
if (copyPoolEntries) {
typeIdx = cpool.addUtf8(value.getEnumTypeString());// was
- // addClass(value.getEnumTypeString());
+ // addClass(value.getEnumTypeString());
valueIdx = cpool.addUtf8(value.getEnumValueString()); // was
- // addString(value.getEnumValueString());
+ // addString(value.getEnumValueString());
} else {
typeIdx = value.getTypeIndex();
valueIdx = value.getValueIndex();
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java b/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java
index 923064e..7b7a249 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ExceptionThrower.java
@@ -19,11 +19,11 @@ package haidnor.jvm.bcel.generic;
/**
* Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite
* the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted.
- *
+ *
* The Lava Language Specification specifies exactly which RUN-TIME and which LINKING exceptions each
* instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may
* be possible that an Instruction implementing this interface returns a Class[] of size 0.
- *
+ *
* Please note that we speak of an "exception" here when we mean any "Throwable" object; so this term is equally used
* for "Exception" and "Error" objects.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java b/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java
index 1e26b51..cbffaf6 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/FieldGen.java
@@ -48,30 +48,14 @@ public class FieldGen extends FieldGenOrMethodGen {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
}
};
-
- /**
- * @return Comparison strategy object
- */
- public static BCELComparator getComparator() {
- return bcelComparator;
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
-
private Object value;
-
private List observers;
/**
* Instantiate from existing field.
*
* @param field Field object
- * @param cp constant pool (must contain the same entries as the field's constant pool)
+ * @param cp constant pool (must contain the same entries as the field's constant pool)
*/
public FieldGen(final JavaField field, final ConstantPoolGen cp) {
this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp);
@@ -93,9 +77,9 @@ public class FieldGen extends FieldGenOrMethodGen {
* value associated with it as defined by setInitValue().
*
* @param accessFlags access qualifiers
- * @param type field type
- * @param name field name
- * @param cp constant pool
+ * @param type field type
+ * @param name field name
+ * @param cp constant pool
*/
public FieldGen(final int accessFlags, final Type type, final String name, final ConstantPoolGen cp) {
super(accessFlags);
@@ -104,28 +88,42 @@ public class FieldGen extends FieldGenOrMethodGen {
setConstantPool(cp);
}
+ /**
+ * @return Comparison strategy object
+ */
+ public static BCELComparator getComparator() {
+ return bcelComparator;
+ }
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
private void addAnnotationsAsAttribute(final ConstantPoolGen cp) {
Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute);
}
private int addConstant() {
switch (super.getType().getType()) { // sic
- case Const.T_INT:
- case Const.T_CHAR:
- case Const.T_BYTE:
- case Const.T_BOOLEAN:
- case Const.T_SHORT:
- return super.getConstantPool().addInteger(((Integer) value).intValue());
- case Const.T_FLOAT:
- return super.getConstantPool().addFloat(((Float) value).floatValue());
- case Const.T_DOUBLE:
- return super.getConstantPool().addDouble(((Double) value).doubleValue());
- case Const.T_LONG:
- return super.getConstantPool().addLong(((Long) value).longValue());
- case Const.T_REFERENCE:
- return super.getConstantPool().addString((String) value);
- default:
- throw new IllegalStateException("Unhandled : " + super.getType().getType()); // sic
+ case Const.T_INT:
+ case Const.T_CHAR:
+ case Const.T_BYTE:
+ case Const.T_BOOLEAN:
+ case Const.T_SHORT:
+ return super.getConstantPool().addInteger(((Integer) value).intValue());
+ case Const.T_FLOAT:
+ return super.getConstantPool().addFloat(((Float) value).floatValue());
+ case Const.T_DOUBLE:
+ return super.getConstantPool().addDouble(((Double) value).doubleValue());
+ case Const.T_LONG:
+ return super.getConstantPool().addLong(((Long) value).longValue());
+ case Const.T_REFERENCE:
+ return super.getConstantPool().addString((String) value);
+ default:
+ throw new IllegalStateException("Unhandled : " + super.getType().getType()); // sic
}
}
@@ -202,31 +200,6 @@ public class FieldGen extends FieldGenOrMethodGen {
return null;
}
- @Override
- public String getSignature() {
- return super.getType().getSignature();
- }
-
- /**
- * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
- * signature.
- *
- * @see Object#hashCode()
- */
- @Override
- public int hashCode() {
- return bcelComparator.hashCode(this);
- }
-
- /**
- * Remove observer for this object.
- */
- public void removeObserver(final FieldObserver o) {
- if (observers != null) {
- observers.remove(o);
- }
- }
-
public void setInitValue(final boolean b) {
checkType(Type.BOOLEAN);
if (b) {
@@ -293,6 +266,31 @@ public class FieldGen extends FieldGenOrMethodGen {
}
}
+ @Override
+ public String getSignature() {
+ return super.getType().getSignature();
+ }
+
+ /**
+ * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
+ * signature.
+ *
+ * @see Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return bcelComparator.hashCode(this);
+ }
+
+ /**
+ * Remove observer for this object.
+ */
+ public void removeObserver(final FieldObserver o) {
+ if (observers != null) {
+ observers.remove(o);
+ }
+ }
+
private void setValue(final int index) {
final ConstantPool cp = super.getConstantPool().getConstantPool();
final Constant c = cp.getConstant(index);
diff --git a/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java b/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java
index 4f2ba9d..8a23e84 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/FieldGenOrMethodGen.java
@@ -29,29 +29,25 @@ import java.util.List;
*/
public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable {
+ private final List attributeList = new ArrayList<>();
+ // @since 6.0
+ private final List annotationList = new ArrayList<>();
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected String name;
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected Type type;
-
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@Deprecated
protected ConstantPoolGen cp;
- private final List attributeList = new ArrayList<>();
-
- // @since 6.0
- private final List annotationList = new ArrayList<>();
-
protected FieldGenOrMethodGen() {
}
@@ -107,6 +103,10 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
return cp;
}
+ public void setConstantPool(final ConstantPoolGen cp) { // TODO could be package-protected?
+ this.cp = cp;
+ }
+
/**
* @return name of method/field.
*/
@@ -115,6 +115,11 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
return name;
}
+ @Override
+ public void setName(final String name) { // TODO could be package-protected?
+ this.name = name;
+ }
+
/**
* @return signature of method/field.
*/
@@ -125,6 +130,14 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
return type;
}
+ @Override
+ public void setType(final Type type) { // TODO could be package-protected?
+ if (type.getType() == Const.T_ADDRESS) {
+ throw new IllegalArgumentException("Type can not be " + type);
+ }
+ this.type = type;
+ }
+
/**
* @since 6.0
*/
@@ -152,21 +165,4 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
public void removeAttributes() {
attributeList.clear();
}
-
- public void setConstantPool(final ConstantPoolGen cp) { // TODO could be package-protected?
- this.cp = cp;
- }
-
- @Override
- public void setName(final String name) { // TODO could be package-protected?
- this.name = name;
- }
-
- @Override
- public void setType(final Type type) { // TODO could be package-protected?
- if (type.getType() == Const.T_ADDRESS) {
- throw new IllegalArgumentException("Type can not be " + type);
- }
- this.type = type;
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java b/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java
index b0fc8ac..dc26e42 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/FieldOrMethod.java
@@ -43,10 +43,9 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
/**
* @return name of the referenced class/interface
* @deprecated If the instruction references an array class, this method will return "java.lang.Object". For code
- * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an
- * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly
- * distinguishes between class types and array types.
- *
+ * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an
+ * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly
+ * distinguishes between class types and array types.
*/
@Deprecated
public String getClassName(final ConstantPoolGen cpg) {
@@ -63,7 +62,7 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
/**
* @return type of the referenced class/interface
* @deprecated If the instruction references an array class, the ObjectType returned will be invalid. Use
- * getReferenceType() instead.
+ * getReferenceType() instead.
*/
@Deprecated
public ObjectType getClassType(final ConstantPoolGen cpg) {
@@ -100,7 +99,7 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
*
* @param cpg the ConstantPoolGen used to create the instruction
* @return an ObjectType (if the referenced class type is a class or interface), or an ArrayType (if the referenced
- * class type is an array class)
+ * class type is an array class)
*/
public ReferenceType getReferenceType(final ConstantPoolGen cpg) {
final ConstantPool cp = cpg.getConstantPool();
diff --git a/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java b/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java
index 0df16c2..baa1a96 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/GETFIELD.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
*
* Stack: ..., objectref -> ..., value
*
- *
+ *
* OR
*
*
@@ -66,7 +66,7 @@ public class GETFIELD extends FieldInstruction implements ExceptionThrower, Stac
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
- ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+ ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
}
@Override
diff --git a/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java b/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java
index 699b656..b097020 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/GETSTATIC.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
*
* Stack: ..., -> ..., value
*
- *
+ *
* OR
*
*
diff --git a/src/main/java/haidnor/jvm/bcel/generic/GOTO.java b/src/main/java/haidnor/jvm/bcel/generic/GOTO.java
index 76b117b..a599e3f 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/GOTO.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/GOTO.java
@@ -73,7 +73,7 @@ public class GOTO extends GotoInstruction implements VariableLengthInstruction {
* Called in pass 2 of InstructionList.setPositions() in order to update the branch target, that may shift due to
* variable length instructions.
*
- * @param offset additional offset caused by preceding (variable length) instructions
+ * @param offset additional offset caused by preceding (variable length) instructions
* @param maxOffset the maximum offset that may be caused by these instructions
* @return additional offset caused by possible change of this instruction's length
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/IDIV.java b/src/main/java/haidnor/jvm/bcel/generic/IDIV.java
index a3806b7..2831efe 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/IDIV.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/IDIV.java
@@ -56,6 +56,6 @@ public class IDIV extends ArithmeticInstruction implements ExceptionThrower {
*/
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION};
+ return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/IINC.java b/src/main/java/haidnor/jvm/bcel/generic/IINC.java
index 8ea16d4..a114dda 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/IINC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/IINC.java
@@ -87,6 +87,14 @@ public class IINC extends LocalVariableInstruction {
return c;
}
+ /**
+ * Sets increment factor.
+ */
+ public final void setIncrement(final int c) {
+ this.c = c;
+ setWide();
+ }
+
/**
* @return int type
*/
@@ -112,14 +120,6 @@ public class IINC extends LocalVariableInstruction {
}
}
- /**
- * Sets increment factor.
- */
- public final void setIncrement(final int c) {
- this.c = c;
- setWide();
- }
-
/**
* Sets index of local variable.
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java
index 133657e..ee5fcf7 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKEDYNAMIC.java
@@ -31,7 +31,7 @@ import java.io.IOException;
* of the method. Ignores the bootstrap mechanism entirely.
*
* @see The
- * invokedynamic instruction in The Java Virtual Machine Specification
+ * invokedynamic instruction in The Java Virtual Machine Specification
* @since 6.0
*/
public class INVOKEDYNAMIC extends InvokeInstruction {
@@ -80,7 +80,7 @@ public class INVOKEDYNAMIC extends InvokeInstruction {
/**
* Override the parent method because our class name is held elsewhere.
- *
+ *
* Note: Contrary to this method's name it does not return the class name of the invoke target; rather it returns the
* name of the method that will be used to invoke the Lambda method generated by this invoke dynamic instruction.
*/
@@ -94,7 +94,7 @@ public class INVOKEDYNAMIC extends InvokeInstruction {
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR,
- ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+ ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
}
/**
diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java
index 8cf9d47..d888c94 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKEINTERFACE.java
@@ -32,7 +32,7 @@ import java.io.IOException;
*
*
* @see The
- * invokeinterface instruction in The Java Virtual Machine Specification
+ * invokeinterface instruction in The Java Virtual Machine Specification
*/
public final class INVOKEINTERFACE extends InvokeInstruction {
@@ -100,7 +100,7 @@ public final class INVOKEINTERFACE extends InvokeInstruction {
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_INTERFACE_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR,
- ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+ ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.ILLEGAL_ACCESS_ERROR, ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
}
/**
diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java
index 1ab8998..ff029d4 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKESPECIAL.java
@@ -31,7 +31,7 @@ import java.io.IOException;
*
*
* @see The
- * invokespecial instruction in The Java Virtual Machine Specification
+ * invokespecial instruction in The Java Virtual Machine Specification
*/
public class INVOKESPECIAL extends InvokeInstruction {
@@ -78,6 +78,6 @@ public class INVOKESPECIAL extends InvokeInstruction {
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
- ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR);
+ ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java
index 1890895..b24faf4 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKESTATIC.java
@@ -30,7 +30,7 @@ import java.io.IOException;
*
*
* @see The invokestatic
- * instruction in The Java Virtual Machine Specification
+ * instruction in The Java Virtual Machine Specification
*/
public class INVOKESTATIC extends InvokeInstruction {
@@ -77,6 +77,6 @@ public class INVOKESTATIC extends InvokeInstruction {
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.UNSATISFIED_LINK_ERROR,
- ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+ ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java b/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java
index ddbd29d..8774156 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/INVOKEVIRTUAL.java
@@ -30,7 +30,7 @@ import java.io.IOException;
*
*
* @see The
- * invokevirtual instruction in The Java Virtual Machine Specification
+ * invokevirtual instruction in The Java Virtual Machine Specification
*/
public class INVOKEVIRTUAL extends InvokeInstruction {
@@ -77,6 +77,6 @@ public class INVOKEVIRTUAL extends InvokeInstruction {
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
- ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR);
+ ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR, ExceptionConst.ABSTRACT_METHOD_ERROR, ExceptionConst.UNSATISFIED_LINK_ERROR);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/IREM.java b/src/main/java/haidnor/jvm/bcel/generic/IREM.java
index c1262bc..2556efe 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/IREM.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/IREM.java
@@ -56,6 +56,6 @@ public class IREM extends ArithmeticInstruction implements ExceptionThrower {
*/
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION};
+ return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/Instruction.java b/src/main/java/haidnor/jvm/bcel/generic/Instruction.java
index 92cc653..4b25748 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/Instruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/Instruction.java
@@ -31,6 +31,27 @@ public abstract class Instruction implements Cloneable {
static final Instruction[] EMPTY_ARRAY = {};
private static InstructionComparator cmp = InstructionComparator.DEFAULT;
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected short length = 1; // Length of instruction in bytes
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected short opcode = -1; // Opcode number
+
+ /**
+ * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
+ */
+ Instruction() {
+ }
+
+ public Instruction(final short opcode, final short length) {
+ this.length = length;
+ this.opcode = opcode;
+ }
/**
* Gets Comparator object used in the equals() method to determine equality of instructions.
@@ -43,6 +64,16 @@ public abstract class Instruction implements Cloneable {
return cmp;
}
+ /**
+ * Sets comparator to be used for equals().
+ *
+ * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods
+ */
+ @Deprecated
+ public static void setComparator(final InstructionComparator c) {
+ cmp = c;
+ }
+
/**
* Tests if the value can fit in a byte (signed)
*
@@ -70,6 +101,7 @@ public abstract class Instruction implements Cloneable {
*
* If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned.
*
+ *
* @param bytes input stream bytes
* @return instruction object being read
* @throws IOException Thrown when an I/O exception of some sort has occurred.
@@ -90,299 +122,299 @@ public abstract class Instruction implements Cloneable {
}
switch (opcode) {
- case Const.BIPUSH:
- obj = new BIPUSH();
- break;
- case Const.SIPUSH:
- obj = new SIPUSH();
- break;
- case Const.LDC:
- obj = new LDC();
- break;
- case Const.LDC_W:
- obj = new LDC_W();
- break;
- case Const.LDC2_W:
- obj = new LDC2_W();
- break;
- case Const.ILOAD:
- obj = new ILOAD();
- break;
- case Const.LLOAD:
- obj = new LLOAD();
- break;
- case Const.FLOAD:
- obj = new FLOAD();
- break;
- case Const.DLOAD:
- obj = new DLOAD();
- break;
- case Const.ALOAD:
- obj = new ALOAD();
- break;
- case Const.ILOAD_0:
- obj = new ILOAD(0);
- break;
- case Const.ILOAD_1:
- obj = new ILOAD(1);
- break;
- case Const.ILOAD_2:
- obj = new ILOAD(2);
- break;
- case Const.ILOAD_3:
- obj = new ILOAD(3);
- break;
- case Const.LLOAD_0:
- obj = new LLOAD(0);
- break;
- case Const.LLOAD_1:
- obj = new LLOAD(1);
- break;
- case Const.LLOAD_2:
- obj = new LLOAD(2);
- break;
- case Const.LLOAD_3:
- obj = new LLOAD(3);
- break;
- case Const.FLOAD_0:
- obj = new FLOAD(0);
- break;
- case Const.FLOAD_1:
- obj = new FLOAD(1);
- break;
- case Const.FLOAD_2:
- obj = new FLOAD(2);
- break;
- case Const.FLOAD_3:
- obj = new FLOAD(3);
- break;
- case Const.DLOAD_0:
- obj = new DLOAD(0);
- break;
- case Const.DLOAD_1:
- obj = new DLOAD(1);
- break;
- case Const.DLOAD_2:
- obj = new DLOAD(2);
- break;
- case Const.DLOAD_3:
- obj = new DLOAD(3);
- break;
- case Const.ALOAD_0:
- obj = new ALOAD(0);
- break;
- case Const.ALOAD_1:
- obj = new ALOAD(1);
- break;
- case Const.ALOAD_2:
- obj = new ALOAD(2);
- break;
- case Const.ALOAD_3:
- obj = new ALOAD(3);
- break;
- case Const.ISTORE:
- obj = new ISTORE();
- break;
- case Const.LSTORE:
- obj = new LSTORE();
- break;
- case Const.FSTORE:
- obj = new FSTORE();
- break;
- case Const.DSTORE:
- obj = new DSTORE();
- break;
- case Const.ASTORE:
- obj = new ASTORE();
- break;
- case Const.ISTORE_0:
- obj = new ISTORE(0);
- break;
- case Const.ISTORE_1:
- obj = new ISTORE(1);
- break;
- case Const.ISTORE_2:
- obj = new ISTORE(2);
- break;
- case Const.ISTORE_3:
- obj = new ISTORE(3);
- break;
- case Const.LSTORE_0:
- obj = new LSTORE(0);
- break;
- case Const.LSTORE_1:
- obj = new LSTORE(1);
- break;
- case Const.LSTORE_2:
- obj = new LSTORE(2);
- break;
- case Const.LSTORE_3:
- obj = new LSTORE(3);
- break;
- case Const.FSTORE_0:
- obj = new FSTORE(0);
- break;
- case Const.FSTORE_1:
- obj = new FSTORE(1);
- break;
- case Const.FSTORE_2:
- obj = new FSTORE(2);
- break;
- case Const.FSTORE_3:
- obj = new FSTORE(3);
- break;
- case Const.DSTORE_0:
- obj = new DSTORE(0);
- break;
- case Const.DSTORE_1:
- obj = new DSTORE(1);
- break;
- case Const.DSTORE_2:
- obj = new DSTORE(2);
- break;
- case Const.DSTORE_3:
- obj = new DSTORE(3);
- break;
- case Const.ASTORE_0:
- obj = new ASTORE(0);
- break;
- case Const.ASTORE_1:
- obj = new ASTORE(1);
- break;
- case Const.ASTORE_2:
- obj = new ASTORE(2);
- break;
- case Const.ASTORE_3:
- obj = new ASTORE(3);
- break;
- case Const.IINC:
- obj = new IINC();
- break;
- case Const.IFEQ:
- obj = new IFEQ();
- break;
- case Const.IFNE:
- obj = new IFNE();
- break;
- case Const.IFLT:
- obj = new IFLT();
- break;
- case Const.IFGE:
- obj = new IFGE();
- break;
- case Const.IFGT:
- obj = new IFGT();
- break;
- case Const.IFLE:
- obj = new IFLE();
- break;
- case Const.IF_ICMPEQ:
- obj = new IF_ICMPEQ();
- break;
- case Const.IF_ICMPNE:
- obj = new IF_ICMPNE();
- break;
- case Const.IF_ICMPLT:
- obj = new IF_ICMPLT();
- break;
- case Const.IF_ICMPGE:
- obj = new IF_ICMPGE();
- break;
- case Const.IF_ICMPGT:
- obj = new IF_ICMPGT();
- break;
- case Const.IF_ICMPLE:
- obj = new IF_ICMPLE();
- break;
- case Const.IF_ACMPEQ:
- obj = new IF_ACMPEQ();
- break;
- case Const.IF_ACMPNE:
- obj = new IF_ACMPNE();
- break;
- case Const.GOTO:
- obj = new GOTO();
- break;
- case Const.JSR:
- obj = new JSR();
- break;
- case Const.RET:
- obj = new RET();
- break;
- case Const.TABLESWITCH:
- obj = new TABLESWITCH();
- break;
- case Const.LOOKUPSWITCH:
- obj = new LOOKUPSWITCH();
- break;
- case Const.GETSTATIC:
- obj = new GETSTATIC();
- break;
- case Const.PUTSTATIC:
- obj = new PUTSTATIC();
- break;
- case Const.GETFIELD:
- obj = new GETFIELD();
- break;
- case Const.PUTFIELD:
- obj = new PUTFIELD();
- break;
- case Const.INVOKEVIRTUAL:
- obj = new INVOKEVIRTUAL();
- break;
- case Const.INVOKESPECIAL:
- obj = new INVOKESPECIAL();
- break;
- case Const.INVOKESTATIC:
- obj = new INVOKESTATIC();
- break;
- case Const.INVOKEINTERFACE:
- obj = new INVOKEINTERFACE();
- break;
- case Const.INVOKEDYNAMIC:
- obj = new INVOKEDYNAMIC();
- break;
- case Const.NEW:
- obj = new NEW();
- break;
- case Const.NEWARRAY:
- obj = new NEWARRAY();
- break;
- case Const.ANEWARRAY:
- obj = new ANEWARRAY();
- break;
- case Const.CHECKCAST:
- obj = new CHECKCAST();
- break;
- case Const.INSTANCEOF:
- obj = new INSTANCEOF();
- break;
- case Const.MULTIANEWARRAY:
- obj = new MULTIANEWARRAY();
- break;
- case Const.IFNULL:
- obj = new IFNULL();
- break;
- case Const.IFNONNULL:
- obj = new IFNONNULL();
- break;
- case Const.GOTO_W:
- obj = new GOTO_W();
- break;
- case Const.JSR_W:
- obj = new JSR_W();
- break;
- case Const.BREAKPOINT:
- obj = new BREAKPOINT();
- break;
- case Const.IMPDEP1:
- obj = new IMPDEP1();
- break;
- case Const.IMPDEP2:
- obj = new IMPDEP2();
- break;
- default:
- throw new ClassGenException("Illegal opcode detected: " + opcode);
+ case Const.BIPUSH:
+ obj = new BIPUSH();
+ break;
+ case Const.SIPUSH:
+ obj = new SIPUSH();
+ break;
+ case Const.LDC:
+ obj = new LDC();
+ break;
+ case Const.LDC_W:
+ obj = new LDC_W();
+ break;
+ case Const.LDC2_W:
+ obj = new LDC2_W();
+ break;
+ case Const.ILOAD:
+ obj = new ILOAD();
+ break;
+ case Const.LLOAD:
+ obj = new LLOAD();
+ break;
+ case Const.FLOAD:
+ obj = new FLOAD();
+ break;
+ case Const.DLOAD:
+ obj = new DLOAD();
+ break;
+ case Const.ALOAD:
+ obj = new ALOAD();
+ break;
+ case Const.ILOAD_0:
+ obj = new ILOAD(0);
+ break;
+ case Const.ILOAD_1:
+ obj = new ILOAD(1);
+ break;
+ case Const.ILOAD_2:
+ obj = new ILOAD(2);
+ break;
+ case Const.ILOAD_3:
+ obj = new ILOAD(3);
+ break;
+ case Const.LLOAD_0:
+ obj = new LLOAD(0);
+ break;
+ case Const.LLOAD_1:
+ obj = new LLOAD(1);
+ break;
+ case Const.LLOAD_2:
+ obj = new LLOAD(2);
+ break;
+ case Const.LLOAD_3:
+ obj = new LLOAD(3);
+ break;
+ case Const.FLOAD_0:
+ obj = new FLOAD(0);
+ break;
+ case Const.FLOAD_1:
+ obj = new FLOAD(1);
+ break;
+ case Const.FLOAD_2:
+ obj = new FLOAD(2);
+ break;
+ case Const.FLOAD_3:
+ obj = new FLOAD(3);
+ break;
+ case Const.DLOAD_0:
+ obj = new DLOAD(0);
+ break;
+ case Const.DLOAD_1:
+ obj = new DLOAD(1);
+ break;
+ case Const.DLOAD_2:
+ obj = new DLOAD(2);
+ break;
+ case Const.DLOAD_3:
+ obj = new DLOAD(3);
+ break;
+ case Const.ALOAD_0:
+ obj = new ALOAD(0);
+ break;
+ case Const.ALOAD_1:
+ obj = new ALOAD(1);
+ break;
+ case Const.ALOAD_2:
+ obj = new ALOAD(2);
+ break;
+ case Const.ALOAD_3:
+ obj = new ALOAD(3);
+ break;
+ case Const.ISTORE:
+ obj = new ISTORE();
+ break;
+ case Const.LSTORE:
+ obj = new LSTORE();
+ break;
+ case Const.FSTORE:
+ obj = new FSTORE();
+ break;
+ case Const.DSTORE:
+ obj = new DSTORE();
+ break;
+ case Const.ASTORE:
+ obj = new ASTORE();
+ break;
+ case Const.ISTORE_0:
+ obj = new ISTORE(0);
+ break;
+ case Const.ISTORE_1:
+ obj = new ISTORE(1);
+ break;
+ case Const.ISTORE_2:
+ obj = new ISTORE(2);
+ break;
+ case Const.ISTORE_3:
+ obj = new ISTORE(3);
+ break;
+ case Const.LSTORE_0:
+ obj = new LSTORE(0);
+ break;
+ case Const.LSTORE_1:
+ obj = new LSTORE(1);
+ break;
+ case Const.LSTORE_2:
+ obj = new LSTORE(2);
+ break;
+ case Const.LSTORE_3:
+ obj = new LSTORE(3);
+ break;
+ case Const.FSTORE_0:
+ obj = new FSTORE(0);
+ break;
+ case Const.FSTORE_1:
+ obj = new FSTORE(1);
+ break;
+ case Const.FSTORE_2:
+ obj = new FSTORE(2);
+ break;
+ case Const.FSTORE_3:
+ obj = new FSTORE(3);
+ break;
+ case Const.DSTORE_0:
+ obj = new DSTORE(0);
+ break;
+ case Const.DSTORE_1:
+ obj = new DSTORE(1);
+ break;
+ case Const.DSTORE_2:
+ obj = new DSTORE(2);
+ break;
+ case Const.DSTORE_3:
+ obj = new DSTORE(3);
+ break;
+ case Const.ASTORE_0:
+ obj = new ASTORE(0);
+ break;
+ case Const.ASTORE_1:
+ obj = new ASTORE(1);
+ break;
+ case Const.ASTORE_2:
+ obj = new ASTORE(2);
+ break;
+ case Const.ASTORE_3:
+ obj = new ASTORE(3);
+ break;
+ case Const.IINC:
+ obj = new IINC();
+ break;
+ case Const.IFEQ:
+ obj = new IFEQ();
+ break;
+ case Const.IFNE:
+ obj = new IFNE();
+ break;
+ case Const.IFLT:
+ obj = new IFLT();
+ break;
+ case Const.IFGE:
+ obj = new IFGE();
+ break;
+ case Const.IFGT:
+ obj = new IFGT();
+ break;
+ case Const.IFLE:
+ obj = new IFLE();
+ break;
+ case Const.IF_ICMPEQ:
+ obj = new IF_ICMPEQ();
+ break;
+ case Const.IF_ICMPNE:
+ obj = new IF_ICMPNE();
+ break;
+ case Const.IF_ICMPLT:
+ obj = new IF_ICMPLT();
+ break;
+ case Const.IF_ICMPGE:
+ obj = new IF_ICMPGE();
+ break;
+ case Const.IF_ICMPGT:
+ obj = new IF_ICMPGT();
+ break;
+ case Const.IF_ICMPLE:
+ obj = new IF_ICMPLE();
+ break;
+ case Const.IF_ACMPEQ:
+ obj = new IF_ACMPEQ();
+ break;
+ case Const.IF_ACMPNE:
+ obj = new IF_ACMPNE();
+ break;
+ case Const.GOTO:
+ obj = new GOTO();
+ break;
+ case Const.JSR:
+ obj = new JSR();
+ break;
+ case Const.RET:
+ obj = new RET();
+ break;
+ case Const.TABLESWITCH:
+ obj = new TABLESWITCH();
+ break;
+ case Const.LOOKUPSWITCH:
+ obj = new LOOKUPSWITCH();
+ break;
+ case Const.GETSTATIC:
+ obj = new GETSTATIC();
+ break;
+ case Const.PUTSTATIC:
+ obj = new PUTSTATIC();
+ break;
+ case Const.GETFIELD:
+ obj = new GETFIELD();
+ break;
+ case Const.PUTFIELD:
+ obj = new PUTFIELD();
+ break;
+ case Const.INVOKEVIRTUAL:
+ obj = new INVOKEVIRTUAL();
+ break;
+ case Const.INVOKESPECIAL:
+ obj = new INVOKESPECIAL();
+ break;
+ case Const.INVOKESTATIC:
+ obj = new INVOKESTATIC();
+ break;
+ case Const.INVOKEINTERFACE:
+ obj = new INVOKEINTERFACE();
+ break;
+ case Const.INVOKEDYNAMIC:
+ obj = new INVOKEDYNAMIC();
+ break;
+ case Const.NEW:
+ obj = new NEW();
+ break;
+ case Const.NEWARRAY:
+ obj = new NEWARRAY();
+ break;
+ case Const.ANEWARRAY:
+ obj = new ANEWARRAY();
+ break;
+ case Const.CHECKCAST:
+ obj = new CHECKCAST();
+ break;
+ case Const.INSTANCEOF:
+ obj = new INSTANCEOF();
+ break;
+ case Const.MULTIANEWARRAY:
+ obj = new MULTIANEWARRAY();
+ break;
+ case Const.IFNULL:
+ obj = new IFNULL();
+ break;
+ case Const.IFNONNULL:
+ obj = new IFNONNULL();
+ break;
+ case Const.GOTO_W:
+ obj = new GOTO_W();
+ break;
+ case Const.JSR_W:
+ obj = new JSR_W();
+ break;
+ case Const.BREAKPOINT:
+ obj = new BREAKPOINT();
+ break;
+ case Const.IMPDEP1:
+ obj = new IMPDEP1();
+ break;
+ case Const.IMPDEP2:
+ obj = new IMPDEP2();
+ break;
+ default:
+ throw new ClassGenException("Illegal opcode detected: " + opcode);
}
@@ -394,39 +426,6 @@ public abstract class Instruction implements Cloneable {
return obj;
}
- /**
- * Sets comparator to be used for equals().
- *
- * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods
- */
- @Deprecated
- public static void setComparator(final InstructionComparator c) {
- cmp = c;
- }
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected short length = 1; // Length of instruction in bytes
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected short opcode = -1; // Opcode number
-
- /**
- * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
- */
- Instruction() {
- }
-
- public Instruction(final short opcode, final short length) {
- this.length = length;
- this.opcode = opcode;
- }
-
/**
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
@@ -440,7 +439,7 @@ public abstract class Instruction implements Cloneable {
* they reference.
*
* @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this can not be
- * computed statically
+ * computed statically
*/
public int consumeStack(final ConstantPoolGen cpg) {
return Const.getConsumeStack(opcode);
@@ -450,8 +449,8 @@ public abstract class Instruction implements Cloneable {
* Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic
* types are). This also applies for 'Select' instructions with their multiple branch targets.
*
- * @see BranchInstruction
* @return (shallow) copy of an instruction
+ * @see BranchInstruction
*/
public Instruction copy() {
Instruction i = null;
@@ -501,6 +500,15 @@ public abstract class Instruction implements Cloneable {
return length;
}
+ /**
+ * Needed in readInstruction and subclasses in this package
+ *
+ * @since 6.0
+ */
+ final void setLength(final int length) {
+ this.length = (short) length; // TODO check range?
+ }
+
/**
* @return name of instruction, i.e., opcode name
*/
@@ -515,6 +523,13 @@ public abstract class Instruction implements Cloneable {
return opcode;
}
+ /**
+ * Needed in readInstruction and subclasses in this package
+ */
+ final void setOpcode(final short opcode) {
+ this.opcode = opcode;
+ }
+
/**
* Gets the hashCode of this object.
*
@@ -530,7 +545,7 @@ public abstract class Instruction implements Cloneable {
* Reads needed data (e.g. index) from file.
*
* @param bytes byte sequence to read from
- * @param wide "wide" instruction flag
+ * @param wide "wide" instruction flag
* @throws IOException may be thrown if the implementation needs to read data from the file
*/
@SuppressWarnings("unused") // thrown by subclasses
@@ -542,28 +557,12 @@ public abstract class Instruction implements Cloneable {
* they reference.
*
* @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this can not be
- * computed statically
+ * computed statically
*/
public int produceStack(final ConstantPoolGen cpg) {
return Const.getProduceStack(opcode);
}
- /**
- * Needed in readInstruction and subclasses in this package
- *
- * @since 6.0
- */
- final void setLength(final int length) {
- this.length = (short) length; // TODO check range?
- }
-
- /**
- * Needed in readInstruction and subclasses in this package
- */
- final void setOpcode(final short opcode) {
- this.opcode = opcode;
- }
-
/**
* @return mnemonic for instruction in verbose format
*/
@@ -574,7 +573,7 @@ public abstract class Instruction implements Cloneable {
/**
* Long output format:
- *
+ *
* <name of opcode> "["<opcode number>"]" "("<length of instruction>")"
*
* @param verbose long/short format switch
diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java
index 3e3834a..d90ba86 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionConst.java
@@ -35,7 +35,7 @@ public final class InstructionConst {
/**
* Predefined instruction objects.
- *
+ *
* NOTE these are not currently immutable, because Instruction has mutable protected fields opcode and length.
*/
public static final Instruction NOP = new NOP();
@@ -279,6 +279,9 @@ public final class InstructionConst {
INSTRUCTIONS[Const.MONITOREXIT] = MONITOREXIT;
}
+ private InstructionConst() {
+ } // non-instantiable
+
/**
* Gets the Instruction.
*
@@ -288,7 +291,4 @@ public final class InstructionConst {
public static Instruction getInstruction(final int index) {
return INSTRUCTIONS[index];
}
-
- private InstructionConst() {
- } // non-instantiable
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java
index bd1e4b6..ab279ac 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionFactory.java
@@ -30,28 +30,10 @@ import haidnor.jvm.bcel.Const;
*/
public class InstructionFactory {
- private static class MethodObject {
-
- final Type[] argTypes;
- final Type resultType;
- final String className;
- final String name;
-
- MethodObject(final String c, final String n, final Type r, final Type[] a) {
- this.className = c;
- this.name = n;
- this.resultType = r;
- this.argTypes = a;
- }
- }
-
private static final String APPEND = "append";
-
private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer";
-
// N.N. These must agree with the order of Constants.T_CHAR through T_LONG
private static final String[] shortNames = {"C", "F", "D", "B", "S", "I", "L"};
-
private static final MethodObject[] appendMethodObjects = {
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.STRING}),
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.OBJECT}), null, null, // indices 2, 3
@@ -63,6 +45,35 @@ public class InstructionFactory {
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.INT}), // No append(byte)
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.INT}), // No append(short)
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[]{Type.LONG})};
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected ClassGen cg;
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected ConstantPoolGen cp;
+
+ /**
+ * Initialize with ClassGen object
+ */
+ public InstructionFactory(final ClassGen cg) {
+ this(cg, cg.getConstantPool());
+ }
+
+ public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
+ this.cg = cg;
+ this.cp = cp;
+ }
+
+ /**
+ * Initialize just with ConstantPoolGen object
+ */
+ public InstructionFactory(final ConstantPoolGen cp) {
+ this(null, cp);
+ }
/**
* @param type type of elements of array, i.e., array.getElementType()
@@ -445,37 +456,6 @@ public class InstructionFactory {
return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String");
}
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected ClassGen cg;
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected ConstantPoolGen cp;
-
- /**
- * Initialize with ClassGen object
- */
- public InstructionFactory(final ClassGen cg) {
- this(cg, cg.getConstantPool());
- }
-
- public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
- this.cg = cg;
- this.cp = cp;
- }
-
- /**
- * Initialize just with ConstantPoolGen object
- */
- public InstructionFactory(final ConstantPoolGen cp) {
- this(null, cp);
- }
-
public Instruction createAppend(final Type type) {
final byte t = type.getType();
if (isString(type)) {
@@ -720,15 +700,30 @@ public class InstructionFactory {
return cg;
}
- public ConstantPoolGen getConstantPool() {
- return cp;
- }
-
public void setClassGen(final ClassGen c) {
cg = c;
}
+ public ConstantPoolGen getConstantPool() {
+ return cp;
+ }
+
public void setConstantPool(final ConstantPoolGen c) {
cp = c;
}
+
+ private static class MethodObject {
+
+ final Type[] argTypes;
+ final Type resultType;
+ final String className;
+ final String name;
+
+ MethodObject(final String c, final String n, final Type r, final Type[] a) {
+ this.className = c;
+ this.name = n;
+ this.resultType = r;
+ this.argTypes = a;
+ }
+ }
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java
index 1602de7..8c19c87 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionHandle.java
@@ -23,7 +23,7 @@ import java.util.*;
/**
* Instances of this class give users a handle to the instructions contained in an InstructionList. Instruction objects
* may be used more than once within a list, this is useful because it saves memory and may be much faster.
- *
+ *
* Within an InstructionList an InstructionHandle object is wrapped around all instructions, i.e., it implements a cell
* in a doubly-linked list. From the outside only the next and the previous instruction (handle) are accessible. One can
* traverse the list via an Enumeration returned by InstructionList.elements().
@@ -45,6 +45,21 @@ public class InstructionHandle {
* Empty array.
*/
static final InstructionTargeter[] EMPTY_INSTRUCTION_TARGETER_ARRAY = {};
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected int i_position = -1; // byte code offset of instruction
+ private InstructionHandle next;
+ private InstructionHandle prev;
+
+ private Instruction instruction;
+ private Set targeters;
+ private Map attributes;
+
+ protected InstructionHandle(final Instruction i) {
+ setInstruction(i);
+ }
/**
* Factory method.
@@ -53,24 +68,6 @@ public class InstructionHandle {
return new InstructionHandle(i);
}
- private InstructionHandle next;
- private InstructionHandle prev;
-
- private Instruction instruction;
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected int i_position = -1; // byte code offset of instruction
- private Set targeters;
-
- private Map attributes;
-
- protected InstructionHandle(final Instruction i) {
- setInstruction(i);
- }
-
/**
* Convenience method, simply calls accept() on the contained instruction.
*
@@ -83,7 +80,7 @@ public class InstructionHandle {
/**
* Add an attribute to an instruction handle.
*
- * @param key the key object to store/retrieve the attribute
+ * @param key the key object to store/retrieve the attribute
* @param attr the attribute to associate with this handle
*/
public void addAttribute(final Object key, final Object attr) {
@@ -152,22 +149,63 @@ public class InstructionHandle {
return instruction;
}
+ /**
+ * Replace current instruction contained in this handle. Old instruction is disposed using Instruction.dispose().
+ */
+ public void setInstruction(final Instruction i) { // Overridden in BranchHandle TODO could be package-protected?
+ if (i == null) {
+ throw new ClassGenException("Assigning null to handle");
+ }
+ if (this.getClass() != BranchHandle.class && i instanceof BranchInstruction) {
+ throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
+ }
+ if (instruction != null) {
+ instruction.dispose();
+ }
+ instruction = i;
+ }
+
public final InstructionHandle getNext() {
return next;
}
+ /**
+ * @param next the next to set
+ * @since 6.0
+ */
+ final InstructionHandle setNext(final InstructionHandle next) {
+ this.next = next;
+ return next;
+ }
+
/**
* @return the position, i.e., the byte code offset of the contained instruction. This is accurate only after
- * InstructionList.setPositions() has been called.
+ * InstructionList.setPositions() has been called.
*/
public int getPosition() {
return i_position;
}
+ /**
+ * Set the position, i.e., the byte code offset of the contained instruction.
+ */
+ void setPosition(final int pos) {
+ i_position = pos;
+ }
+
public final InstructionHandle getPrev() {
return prev;
}
+ /**
+ * @param prev the prev to set
+ * @since 6.0
+ */
+ final InstructionHandle setPrev(final InstructionHandle prev) {
+ this.prev = prev;
+ return prev;
+ }
+
/**
* @return null, if there are no targeters
*/
@@ -213,47 +251,6 @@ public class InstructionHandle {
}
}
- /**
- * Replace current instruction contained in this handle. Old instruction is disposed using Instruction.dispose().
- */
- public void setInstruction(final Instruction i) { // Overridden in BranchHandle TODO could be package-protected?
- if (i == null) {
- throw new ClassGenException("Assigning null to handle");
- }
- if (this.getClass() != BranchHandle.class && i instanceof BranchInstruction) {
- throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
- }
- if (instruction != null) {
- instruction.dispose();
- }
- instruction = i;
- }
-
- /**
- * @param next the next to set
- * @since 6.0
- */
- final InstructionHandle setNext(final InstructionHandle next) {
- this.next = next;
- return next;
- }
-
- /**
- * Set the position, i.e., the byte code offset of the contained instruction.
- */
- void setPosition(final int pos) {
- i_position = pos;
- }
-
- /**
- * @param prev the prev to set
- * @since 6.0
- */
- final InstructionHandle setPrev(final InstructionHandle prev) {
- this.prev = prev;
- return prev;
- }
-
/**
* Temporarily swap the current instruction, without disturbing anything. Meant to be used by a debugger, implementing
* breakpoints. Current instruction is returned.
@@ -289,7 +286,7 @@ public class InstructionHandle {
* length instructions 'setPositions()' performs multiple passes over the instruction list to calculate the correct
* (byte) positions and offsets by calling this function.
*
- * @param offset additional offset caused by preceding (variable length) instructions
+ * @param offset additional offset caused by preceding (variable length) instructions
* @param maxOffset the maximum offset that may be caused by these instructions
* @return additional offset caused by possible change of this instruction's length
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java b/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java
index 92a14d3..2642714 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/InstructionList.java
@@ -32,7 +32,7 @@ import java.util.*;
* InstructionHandles objects that are returned upon append/insert operations. They
* give the user (read only) access to the list structure, such that it can be traversed and manipulated in a controlled
* way.
- *
+ *
* A list is finally dumped to a byte code array with getByteCode .
*
* @see Instruction
@@ -41,42 +41,10 @@ import java.util.*;
*/
public class InstructionList implements Iterable {
- /**
- * Find the target instruction (handle) that corresponds to the given target position (byte code offset).
- *
- * @param ihs array of instruction handles, i.e. il.getInstructionHandles()
- * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions()
- * @param count length of arrays
- * @param target target position to search for
- * @return target position's instruction handle if available
- */
- public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) {
- int l = 0;
- int r = count - 1;
- /*
- * Do a binary search since the pos array is orderd.
- */
- do {
- final int i = l + r >>> 1;
- final int j = pos[i];
- if (j == target) {
- return ihs[i];
- }
- if (target < j) {
- r = i - 1;
- } else {
- l = i + 1;
- }
- } while (l <= r);
- return null;
- }
-
private InstructionHandle start;
private InstructionHandle end;
private int length; // number of elements in list
-
private int[] bytePositions; // byte code offsets corresponding to instructions
-
private List observers;
/**
@@ -138,8 +106,8 @@ public class InstructionList implements Iterable {
if (ihs[i] instanceof BranchHandle) {
final BranchInstruction bi = (BranchInstruction) ihs[i].getInstruction();
int target = bi.getPosition() + bi.getIndex(); /*
- * Byte code position: relative -> absolute.
- */
+ * Byte code position: relative -> absolute.
+ */
// Search for target position
InstructionHandle ih = findHandle(ihs, pos, count, target);
if (ih == null) {
@@ -181,6 +149,36 @@ public class InstructionList implements Iterable {
append(i);
}
+ /**
+ * Find the target instruction (handle) that corresponds to the given target position (byte code offset).
+ *
+ * @param ihs array of instruction handles, i.e. il.getInstructionHandles()
+ * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions()
+ * @param count length of arrays
+ * @param target target position to search for
+ * @return target position's instruction handle if available
+ */
+ public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) {
+ int l = 0;
+ int r = count - 1;
+ /*
+ * Do a binary search since the pos array is orderd.
+ */
+ do {
+ final int i = l + r >>> 1;
+ final int j = pos[i];
+ if (j == target) {
+ return ihs[i];
+ }
+ if (target < j) {
+ r = i - 1;
+ } else {
+ l = i + 1;
+ }
+ } while (l <= r);
+ return null;
+ }
+
/**
* Add observer for this object.
*/
@@ -250,7 +248,7 @@ public class InstructionList implements Iterable {
/**
* Append another list after instruction i contained in this list. Consumes argument list, i.e., it becomes empty.
*
- * @param i where to append the instruction list
+ * @param i where to append the instruction list
* @param il Instruction list to append to this one
* @return instruction handle pointing to the first appended instruction
*/
@@ -284,7 +282,7 @@ public class InstructionList implements Iterable {
* Append an instruction after instruction (handle) ih contained in this list.
*
* @param ih where to append the instruction list
- * @param i Instruction to append
+ * @param i Instruction to append
* @return instruction handle pointing to the first appended instruction
*/
public BranchHandle append(final InstructionHandle ih, final BranchInstruction i) {
@@ -299,7 +297,7 @@ public class InstructionList implements Iterable {
* Append a compound instruction.
*
* @param ih where to append the instruction list
- * @param c The composite instruction (containing an InstructionList)
+ * @param c The composite instruction (containing an InstructionList)
* @return instruction handle of the first appended instruction
*/
public InstructionHandle append(final InstructionHandle ih, final CompoundInstruction c) {
@@ -310,7 +308,7 @@ public class InstructionList implements Iterable {
* Append an instruction after instruction (handle) ih contained in this list.
*
* @param ih where to append the instruction list
- * @param i Instruction to append
+ * @param i Instruction to append
* @return instruction handle pointing to the first appended instruction
*/
public InstructionHandle append(final InstructionHandle ih, final Instruction i) {
@@ -456,7 +454,7 @@ public class InstructionList implements Iterable {
* 'from' is an instruction before 'to', or risk havoc. The corresponding Instruction handles must not be reused!
*
* @param from where to start deleting (inclusive)
- * @param to where to end deleting (inclusive)
+ * @param to where to end deleting (inclusive)
*/
public void delete(final Instruction from, final Instruction to) throws TargetLostException {
InstructionHandle fromIh;
@@ -484,7 +482,7 @@ public class InstructionList implements Iterable {
* 'from' is an instruction before 'to', or risk havoc. The corresponding Instruction handles must not be reused!
*
* @param from where to start deleting (inclusive)
- * @param to where to end deleting (inclusive)
+ * @param to where to end deleting (inclusive)
*/
public void delete(final InstructionHandle from, final InstructionHandle to) throws TargetLostException {
remove(from.getPrev(), to.getNext());
@@ -693,7 +691,7 @@ public class InstructionList implements Iterable {
/**
* Insert another list before Instruction i contained in this list. Consumes argument list, i.e., it becomes empty.
*
- * @param i where to append the instruction list
+ * @param i where to append the instruction list
* @param il Instruction list to insert
* @return instruction handle pointing to the first inserted instruction, i.e., il.getStart()
*/
@@ -727,7 +725,7 @@ public class InstructionList implements Iterable {
* Insert an instruction before instruction (handle) ih contained in this list.
*
* @param ih where to insert to the instruction list
- * @param i Instruction to insert
+ * @param i Instruction to insert
* @return instruction handle of the first inserted instruction
*/
public BranchHandle insert(final InstructionHandle ih, final BranchInstruction i) {
@@ -742,7 +740,7 @@ public class InstructionList implements Iterable {
* Insert a compound instruction.
*
* @param ih where to insert the instruction list
- * @param c The composite instruction (containing an InstructionList)
+ * @param c The composite instruction (containing an InstructionList)
* @return instruction handle of the first inserted instruction
*/
public InstructionHandle insert(final InstructionHandle ih, final CompoundInstruction c) {
@@ -753,7 +751,7 @@ public class InstructionList implements Iterable {
* Insert an instruction before instruction (handle) ih contained in this list.
*
* @param ih where to insert to the instruction list
- * @param i Instruction to insert
+ * @param i Instruction to insert
* @return instruction handle of the first inserted instruction
*/
public InstructionHandle insert(final InstructionHandle ih, final Instruction i) {
@@ -845,7 +843,7 @@ public class InstructionList implements Iterable {
/**
* Move a single instruction (handle) to a new location.
*
- * @param ih moved instruction
+ * @param ih moved instruction
* @param target new location of moved instruction
*/
public void move(final InstructionHandle ih, final InstructionHandle target) {
@@ -860,8 +858,8 @@ public class InstructionList implements Iterable {
* Any instruction targeters pointing to handles within the block, keep their targets.
*
*
- * @param start of moved block
- * @param end of moved block
+ * @param start of moved block
+ * @param end of moved block
* @param target of moved block
*/
public void move(final InstructionHandle start, final InstructionHandle end, final InstructionHandle target) {
@@ -945,8 +943,8 @@ public class InstructionList implements Iterable {
* Redirect all references of exception handlers from oldTarget to newTarget.
*
* @param exceptions array of exception handlers
- * @param oldTarget the old target instruction handle
- * @param newTarget the new target instruction handle
+ * @param oldTarget the old target instruction handle
+ * @param newTarget the new target instruction handle
* @see MethodGen
*/
public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final InstructionHandle oldTarget, final InstructionHandle newTarget) {
@@ -966,7 +964,7 @@ public class InstructionList implements Iterable {
/**
* Redirect all references of local variables from oldTarget to newTarget.
*
- * @param lg array of local variables
+ * @param lg array of local variables
* @param oldTarget the old target instruction handle
* @param newTarget the new target instruction handle
* @see MethodGen
@@ -1098,7 +1096,7 @@ public class InstructionList implements Iterable {
}
if (!(ih instanceof BranchHandle)) {
throw new ClassGenException(
- "Branch instruction " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not contained in BranchHandle.");
+ "Branch instruction " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not contained in BranchHandle.");
}
}
}
@@ -1115,14 +1113,14 @@ public class InstructionList implements Iterable {
* depending on the target offset (short vs. int) or alignment issues (TABLESWITCH and LOOKUPSWITCH).
*/
switch (i.getOpcode()) {
- case Const.JSR:
- case Const.GOTO:
- maxAdditionalBytes += 2;
- break;
- case Const.TABLESWITCH:
- case Const.LOOKUPSWITCH:
- maxAdditionalBytes += 3;
- break;
+ case Const.JSR:
+ case Const.GOTO:
+ maxAdditionalBytes += 2;
+ break;
+ case Const.TABLESWITCH:
+ case Const.LOOKUPSWITCH:
+ maxAdditionalBytes += 3;
+ break;
}
index += i.getLength();
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LADD.java b/src/main/java/haidnor/jvm/bcel/generic/LADD.java
index a633bfb..6d8e809 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LADD.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LADD.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class LADD extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LAND.java b/src/main/java/haidnor/jvm/bcel/generic/LAND.java
index 8c11081..7676850 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LAND.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LAND.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class LAND extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LCMP.java b/src/main/java/haidnor/jvm/bcel/generic/LCMP.java
index 487bf67..ac233a2 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LCMP.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LCMP.java
@@ -24,7 +24,6 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -> ..., result <= -1, 0, 1>
*
- *
*/
public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LDC.java b/src/main/java/haidnor/jvm/bcel/generic/LDC.java
index 1b1fa6d..eb772e2 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LDC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LDC.java
@@ -83,36 +83,36 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro
@Override
public Type getType(final ConstantPoolGen cpg) {
switch (cpg.getConstantPool().getConstant(super.getIndex()).getTag()) {
- case Const.CONSTANT_String:
- return Type.STRING;
- case Const.CONSTANT_Float:
- return Type.FLOAT;
- case Const.CONSTANT_Integer:
- return Type.INT;
- case Const.CONSTANT_Class:
- return Type.CLASS;
- default: // Never reached
- throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
+ case Const.CONSTANT_String:
+ return Type.STRING;
+ case Const.CONSTANT_Float:
+ return Type.FLOAT;
+ case Const.CONSTANT_Integer:
+ return Type.INT;
+ case Const.CONSTANT_Class:
+ return Type.CLASS;
+ default: // Never reached
+ throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
}
}
public Object getValue(final ConstantPoolGen cpg) {
Constant c = cpg.getConstantPool().getConstant(super.getIndex());
switch (c.getTag()) {
- case Const.CONSTANT_String:
- final int i = ((ConstantString) c).getStringIndex();
- c = cpg.getConstantPool().getConstant(i);
- return ((ConstantUtf8) c).getBytes();
- case Const.CONSTANT_Float:
- return Float.valueOf(((ConstantFloat) c).getBytes());
- case Const.CONSTANT_Integer:
- return Integer.valueOf(((ConstantInteger) c).getBytes());
- case Const.CONSTANT_Class:
- final int nameIndex = ((ConstantClass) c).getNameIndex();
- c = cpg.getConstantPool().getConstant(nameIndex);
- return Type.getType(((ConstantUtf8) c).getBytes());
- default: // Never reached
- throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
+ case Const.CONSTANT_String:
+ final int i = ((ConstantString) c).getStringIndex();
+ c = cpg.getConstantPool().getConstant(i);
+ return ((ConstantUtf8) c).getBytes();
+ case Const.CONSTANT_Float:
+ return Float.valueOf(((ConstantFloat) c).getBytes());
+ case Const.CONSTANT_Integer:
+ return Integer.valueOf(((ConstantInteger) c).getBytes());
+ case Const.CONSTANT_Class:
+ final int nameIndex = ((ConstantClass) c).getNameIndex();
+ c = cpg.getConstantPool().getConstant(nameIndex);
+ return Type.getType(((ConstantUtf8) c).getBytes());
+ default: // Never reached
+ throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java b/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java
index 579b0ab..2450be0 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LDC2_W.java
@@ -58,24 +58,24 @@ public class LDC2_W extends CPInstruction implements PushInstruction {
@Override
public Type getType(final ConstantPoolGen cpg) {
switch (cpg.getConstantPool().getConstant(super.getIndex()).getTag()) {
- case Const.CONSTANT_Long:
- return Type.LONG;
- case Const.CONSTANT_Double:
- return Type.DOUBLE;
- default: // Never reached
- throw new IllegalArgumentException("Unknown constant type " + super.getOpcode());
+ case Const.CONSTANT_Long:
+ return Type.LONG;
+ case Const.CONSTANT_Double:
+ return Type.DOUBLE;
+ default: // Never reached
+ throw new IllegalArgumentException("Unknown constant type " + super.getOpcode());
}
}
public Number getValue(final ConstantPoolGen cpg) {
final Constant c = cpg.getConstantPool().getConstant(super.getIndex());
switch (c.getTag()) {
- case Const.CONSTANT_Long:
- return Long.valueOf(((ConstantLong) c).getBytes());
- case Const.CONSTANT_Double:
- return Double.valueOf(((ConstantDouble) c).getBytes());
- default: // Never reached
- throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
+ case Const.CONSTANT_Long:
+ return Long.valueOf(((ConstantLong) c).getBytes());
+ case Const.CONSTANT_Double:
+ return Double.valueOf(((ConstantDouble) c).getBytes());
+ default: // Never reached
+ throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
}
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LDIV.java b/src/main/java/haidnor/jvm/bcel/generic/LDIV.java
index be20296..4781b00 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LDIV.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LDIV.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class LDIV extends ArithmeticInstruction implements ExceptionThrower {
@@ -52,6 +52,6 @@ public class LDIV extends ArithmeticInstruction implements ExceptionThrower {
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION};
+ return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LMUL.java b/src/main/java/haidnor/jvm/bcel/generic/LMUL.java
index 4b60c17..a2f9a1a 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LMUL.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LMUL.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class LMUL extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LREM.java b/src/main/java/haidnor/jvm/bcel/generic/LREM.java
index 22f164e..cfba075 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LREM.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LREM.java
@@ -50,6 +50,6 @@ public class LREM extends ArithmeticInstruction implements ExceptionThrower {
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.ARITHMETIC_EXCEPTION};
+ return new Class[]{ExceptionConst.ARITHMETIC_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LSUB.java b/src/main/java/haidnor/jvm/bcel/generic/LSUB.java
index e81bcdd..9e947cc 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LSUB.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LSUB.java
@@ -24,7 +24,7 @@ import haidnor.jvm.bcel.Const;
*
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 ->
*
- *
+ *
* ..., result.word1, result.word2
*/
public class LSUB extends ArithmeticInstruction {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java b/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java
index 4376c5d..e7d2c88 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LineNumberGen.java
@@ -65,9 +65,15 @@ public class LineNumberGen implements InstructionTargeter, Cloneable {
return ih;
}
+ public void setInstruction(final InstructionHandle instructionHandle) { // TODO could be package-protected?
+ Objects.requireNonNull(instructionHandle, "instructionHandle");
+ BranchInstruction.notifyTarget(this.ih, instructionHandle, this);
+ this.ih = instructionHandle;
+ }
+
/**
* Get LineNumber attribute.
- *
+ *
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
* has been called for the instruction list.
*/
@@ -79,12 +85,6 @@ public class LineNumberGen implements InstructionTargeter, Cloneable {
return srcLine;
}
- public void setInstruction(final InstructionHandle instructionHandle) { // TODO could be package-protected?
- Objects.requireNonNull(instructionHandle, "instructionHandle");
- BranchInstruction.notifyTarget(this.ih, instructionHandle, this);
- this.ih = instructionHandle;
- }
-
public void setSourceLine(final int srcLine) { // TODO could be package-protected?
this.srcLine = srcLine;
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java
index f79c968..9c97372 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LoadInstruction.java
@@ -31,8 +31,8 @@ public abstract class LoadInstruction extends LocalVariableInstruction implement
/**
* @param opcode Instruction opcode
- * @param cTag Instruction number for compact version, ALOAD_0, e.g.
- * @param n local variable index (unsigned short)
+ * @param cTag Instruction number for compact version, ALOAD_0, e.g.
+ * @param n local variable index (unsigned short)
*/
protected LoadInstruction(final short opcode, final short cTag, final int n) {
super(opcode, cTag, n);
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java
index 0c6bcb1..a5c2a37 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableGen.java
@@ -41,10 +41,10 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
* have to be provided by the user.
*
* @param index index of local variable
- * @param name its name
- * @param type its type
+ * @param name its name
+ * @param type its type
* @param start from where the instruction is valid (null means from the start)
- * @param end until where the instruction is valid (null means to the end)
+ * @param end until where the instruction is valid (null means to the end)
*/
public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end) {
if (index < 0 || index > Const.MAX_SHORT) {
@@ -63,15 +63,15 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
* Generates a local variable that with index 'index'. Note that double and long variables need two indexs. Index
* indices have to be provided by the user.
*
- * @param index index of local variable
- * @param name its name
- * @param type its type
- * @param start from where the instruction is valid (null means from the start)
- * @param end until where the instruction is valid (null means to the end)
+ * @param index index of local variable
+ * @param name its name
+ * @param type its type
+ * @param start from where the instruction is valid (null means from the start)
+ * @param end until where the instruction is valid (null means to the end)
* @param origIndex index of local variable prior to any changes to index
*/
public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end,
- final int origIndex) {
+ final int origIndex) {
this(index, name, type, start, end);
this.origIndex = origIndex;
}
@@ -117,20 +117,33 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
return end;
}
+ public void setEnd(final InstructionHandle end) { // TODO could be package-protected?
+ BranchInstruction.notifyTarget(this.end, end, this);
+ this.end = end;
+ }
+
public int getIndex() {
return index;
}
+ public void setIndex(final int index) {
+ this.index = index;
+ }
+
public boolean getLiveToEnd() {
return liveToEnd;
}
+ public void setLiveToEnd(final boolean liveToEnd) {
+ this.liveToEnd = liveToEnd;
+ }
+
/**
* Gets LocalVariable object.
- *
+ *
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
* has been called for the instruction list.
- *
+ *
* Note that due to the conversion from byte code offset to InstructionHandle, it is impossible to tell the difference
* between a live range that ends BEFORE the last insturction of the method or a live range that ends AFTER the last
* instruction of the method. Hence the liveToEnd flag to differentiate between these two cases.
@@ -157,6 +170,11 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
return name;
}
+ @Override
+ public void setName(final String name) {
+ this.name = name;
+ }
+
public int getOrigIndex() {
return origIndex;
}
@@ -165,11 +183,21 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
return start;
}
+ public void setStart(final InstructionHandle start) { // TODO could be package-protected?
+ BranchInstruction.notifyTarget(this.start, start, this);
+ this.start = start;
+ }
+
@Override
public Type getType() {
return type;
}
+ @Override
+ public void setType(final Type type) {
+ this.type = type;
+ }
+
@Override
public int hashCode() {
// If the user changes the name or type, problems with the targeter hashmap will occur.
@@ -177,34 +205,6 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
return name.hashCode() ^ type.hashCode();
}
- public void setEnd(final InstructionHandle end) { // TODO could be package-protected?
- BranchInstruction.notifyTarget(this.end, end, this);
- this.end = end;
- }
-
- public void setIndex(final int index) {
- this.index = index;
- }
-
- public void setLiveToEnd(final boolean liveToEnd) {
- this.liveToEnd = liveToEnd;
- }
-
- @Override
- public void setName(final String name) {
- this.name = name;
- }
-
- public void setStart(final InstructionHandle start) { // TODO could be package-protected?
- BranchInstruction.notifyTarget(this.start, start, this);
- this.start = start;
- }
-
- @Override
- public void setType(final Type type) {
- this.type = type;
- }
-
@Override
public String toString() {
return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")";
diff --git a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java
index cde6f91..6f29232 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/LocalVariableInstruction.java
@@ -53,8 +53,8 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty
/**
* @param opcode Instruction opcode
- * @param cTag Instruction number for compact version, ALOAD_0, e.g.
- * @param n local variable index (unsigned short)
+ * @param cTag Instruction number for compact version, ALOAD_0, e.g.
+ * @param n local variable index (unsigned short)
*/
protected LocalVariableInstruction(final short opcode, final short cTag, final int n) {
super(opcode, (short) 2);
@@ -98,6 +98,31 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty
return n;
}
+ /**
+ * Set the local variable index. also updates opcode and length TODO Why?
+ *
+ * @see #setIndexOnly(int)
+ */
+ @Override
+ public void setIndex(final int n) { // TODO could be package-protected?
+ if (n < 0 || n > Const.MAX_SHORT) {
+ throw new ClassGenException("Illegal value: " + n);
+ }
+ this.n = n;
+ // Cannot be < 0 as this is checked above
+ if (n <= 3) { // Use more compact instruction xLOAD_n
+ super.setOpcode((short) (cTag + n));
+ super.setLength(1);
+ } else {
+ super.setOpcode(canonTag);
+ if (wide()) {
+ super.setLength(4);
+ } else {
+ super.setLength(2);
+ }
+ }
+ }
+
/**
* Returns the type associated with the instruction - in case of ALOAD or ASTORE Type.OBJECT is returned. This is just a
* bit incorrect, because ALOAD and ASTORE may work on every ReferenceType (including Type.NULL) and ASTORE may even
@@ -108,23 +133,23 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty
@Override
public Type getType(final ConstantPoolGen cp) {
switch (canonTag) {
- case Const.ILOAD:
- case Const.ISTORE:
- return Type.INT;
- case Const.LLOAD:
- case Const.LSTORE:
- return Type.LONG;
- case Const.DLOAD:
- case Const.DSTORE:
- return Type.DOUBLE;
- case Const.FLOAD:
- case Const.FSTORE:
- return Type.FLOAT;
- case Const.ALOAD:
- case Const.ASTORE:
- return Type.OBJECT;
- default:
- throw new ClassGenException("Unknown case in switch" + canonTag);
+ case Const.ILOAD:
+ case Const.ISTORE:
+ return Type.INT;
+ case Const.LLOAD:
+ case Const.LSTORE:
+ return Type.LONG;
+ case Const.DLOAD:
+ case Const.DSTORE:
+ return Type.DOUBLE;
+ case Const.FLOAD:
+ case Const.FSTORE:
+ return Type.FLOAT;
+ case Const.ALOAD:
+ case Const.ASTORE:
+ return Type.OBJECT;
+ default:
+ throw new ClassGenException("Unknown case in switch" + canonTag);
}
}
@@ -156,36 +181,11 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty
}
}
- /**
- * Set the local variable index. also updates opcode and length TODO Why?
- *
- * @see #setIndexOnly(int)
- */
- @Override
- public void setIndex(final int n) { // TODO could be package-protected?
- if (n < 0 || n > Const.MAX_SHORT) {
- throw new ClassGenException("Illegal value: " + n);
- }
- this.n = n;
- // Cannot be < 0 as this is checked above
- if (n <= 3) { // Use more compact instruction xLOAD_n
- super.setOpcode((short) (cTag + n));
- super.setLength(1);
- } else {
- super.setOpcode(canonTag);
- if (wide()) {
- super.setLength(4);
- } else {
- super.setLength(2);
- }
- }
- }
-
/**
* Sets the index of the referenced variable (n) only
*
- * @since 6.0
* @see #setIndex(int)
+ * @since 6.0
*/
final void setIndexOnly(final int n) {
this.n = n;
@@ -193,7 +193,7 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty
/**
* Long output format:
- *
+ *
* <name of opcode> "["<opcode number>"]" "("<length of instruction>")" "<"< local variable
* index>">"
*
diff --git a/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java b/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java
index 6c801f0..a8527ef 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/MONITORENTER.java
@@ -47,6 +47,6 @@ public class MONITORENTER extends Instruction implements ExceptionThrower, Stack
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION};
+ return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java b/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java
index 543ca18..437e72a 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/MONITOREXIT.java
@@ -47,6 +47,6 @@ public class MONITOREXIT extends Instruction implements ExceptionThrower, StackC
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.NULL_POINTER_EXCEPTION};
+ return new Class[]{ExceptionConst.NULL_POINTER_EXCEPTION};
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java b/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java
index 9cb0658..c535d2c 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/MULTIANEWARRAY.java
@@ -98,7 +98,7 @@ public class MULTIANEWARRAY extends CPInstruction implements LoadClass, Allocati
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_CLASS_AND_INTERFACE_RESOLUTION, ExceptionConst.ILLEGAL_ACCESS_ERROR,
- ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION);
+ ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION);
}
@Override
diff --git a/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java b/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java
index 20a278a..79180e5 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/MethodGen.java
@@ -27,7 +27,7 @@ import java.util.*;
* Template class for building up a method. This is done by defining exception handlers, adding thrown exceptions, local
* variables and attributes, whereas the 'LocalVariableTable' and 'LineNumberTable' attributes will be set automatically
* for the code. Use stripAttributes() if you don't like this.
- *
+ *
* While generating code it may be necessary to insert NOP operations. You can use the 'removeNOPs' method to get rid
* off them. The resulting method object can be obtained via the 'getMethod()' method.
*
@@ -36,47 +36,6 @@ import java.util.*;
*/
public class MethodGen extends FieldGenOrMethodGen {
- static final class BranchStack {
-
- private final Stack branchTargets = new Stack<>();
- private final Hashtable visitedTargets = new Hashtable<>();
-
- public BranchTarget pop() {
- if (!branchTargets.empty()) {
- return branchTargets.pop();
- }
- return null;
- }
-
- public void push(final InstructionHandle target, final int stackDepth) {
- if (visited(target)) {
- return;
- }
- branchTargets.push(visit(target, stackDepth));
- }
-
- private BranchTarget visit(final InstructionHandle target, final int stackDepth) {
- final BranchTarget bt = new BranchTarget(target, stackDepth);
- visitedTargets.put(target, bt);
- return bt;
- }
-
- private boolean visited(final InstructionHandle target) {
- return visitedTargets.get(target) != null;
- }
- }
-
- static final class BranchTarget {
-
- final InstructionHandle target;
- final int stackDepth;
-
- BranchTarget(final InstructionHandle target, final int stackDepth) {
- this.target = target;
- this.stackDepth = stackDepth;
- }
- }
-
private static BCELComparator bcelComparator = new BCELComparator() {
@Override
@@ -92,147 +51,43 @@ public class MethodGen extends FieldGenOrMethodGen {
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
}
};
-
- private static byte[] getByteCodes(final JavaMethod method) {
- final Code code = method.getCode();
- if (code == null) {
- throw new IllegalStateException(String.format("The method '%s' has no code.", method));
- }
- return code.getCode();
- }
-
- /**
- * @return Comparison strategy object
- */
- public static BCELComparator getComparator() {
- return bcelComparator;
- }
-
- /**
- * Computes stack usage of an instruction list by performing control flow analysis.
- *
- * @return maximum stack depth used by method
- */
- public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et) {
- final BranchStack branchTargets = new BranchStack();
- /*
- * Initially, populate the branch stack with the exception handlers, because these aren't (necessarily) branched to
- * explicitly. in each case, the stack will have depth 1, containing the exception object.
- */
- for (final CodeExceptionGen element : et) {
- final InstructionHandle handlerPc = element.getHandlerPC();
- if (handlerPc != null) {
- branchTargets.push(handlerPc, 1);
- }
- }
- int stackDepth = 0;
- int maxStackDepth = 0;
- InstructionHandle ih = il.getStart();
- while (ih != null) {
- final Instruction instruction = ih.getInstruction();
- final short opcode = instruction.getOpcode();
- final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
- stackDepth += delta;
- if (stackDepth > maxStackDepth) {
- maxStackDepth = stackDepth;
- }
- // choose the next instruction based on whether current is a branch.
- if (instruction instanceof BranchInstruction) {
- final BranchInstruction branch = (BranchInstruction) instruction;
- if (instruction instanceof Select) {
- // explore all of the select's targets. the default target is handled below.
- final Select select = (Select) branch;
- final InstructionHandle[] targets = select.getTargets();
- for (final InstructionHandle target : targets) {
- branchTargets.push(target, stackDepth);
- }
- // nothing to fall through to.
- ih = null;
- } else if (!(branch instanceof IfInstruction)) {
- // if an instruction that comes back to following PC,
- // push next instruction, with stack depth reduced by 1.
- if (opcode == Const.JSR || opcode == Const.JSR_W) {
- branchTargets.push(ih.getNext(), stackDepth - 1);
- }
- ih = null;
- }
- // for all branches, the target of the branch is pushed on the branch stack.
- // conditional branches have a fall through case, selects don't, and
- // jsr/jsr_w return to the next instruction.
- branchTargets.push(branch.getTarget(), stackDepth);
- } else // check for instructions that terminate the method.
- if (opcode == Const.ATHROW || opcode == Const.RET || opcode >= Const.IRETURN && opcode <= Const.RETURN) {
- ih = null;
- }
- // normal case, go to the next instruction.
- if (ih != null) {
- ih = ih.getNext();
- }
- // if we have no more instructions, see if there are any deferred branches to explore.
- if (ih == null) {
- final BranchTarget bt = branchTargets.pop();
- if (bt != null) {
- ih = bt.target;
- stackDepth = bt.stackDepth;
- }
- }
- }
- return maxStackDepth;
- }
-
- /**
- * @param comparator Comparison strategy object
- */
- public static void setComparator(final BCELComparator comparator) {
- bcelComparator = comparator;
- }
-
+ private final List variableList = new ArrayList<>();
+ private final List lineNumberList = new ArrayList<>();
+ private final List exceptionList = new ArrayList<>();
+ private final List throwsList = new ArrayList<>();
+ private final List codeAttrsList = new ArrayList<>();
private String className;
private Type[] argTypes;
private String[] argNames;
private int maxLocals;
private int maxStack;
private InstructionList il;
-
private boolean stripAttributes;
private LocalVariableTypeTable localVariableTypeTable;
- private final List variableList = new ArrayList<>();
-
- private final List lineNumberList = new ArrayList<>();
-
- private final List exceptionList = new ArrayList<>();
-
- private final List throwsList = new ArrayList<>();
-
- private final List codeAttrsList = new ArrayList<>();
-
private List[] paramAnnotations; // Array of lists containing AnnotationGen objects
-
private boolean hasParameterAnnotations;
-
private boolean haveUnpackedParameterAnnotations;
-
private List observers;
/**
* Declare method. If the method is non-static the constructor automatically declares a local variable '$this' in slot
* 0. The actual code is contained in the 'il' parameter, which may further manipulated by the user. But they must take
* care not to remove any instruction (handles) that are still referenced from this object.
- *
+ *
* For example one may not add a local variable and later remove the instructions it refers to without causing havoc. It
* is safe however if you remove that local variable, too.
*
* @param accessFlags access qualifiers
- * @param returnType method type
- * @param argTypes argument types
- * @param argNames argument names (if this is null, default names will be provided for them)
- * @param methodName name of method
- * @param className class name containing this method (may be null, if you don't care)
- * @param il instruction list associated with this method, may be null only for abstract or native methods
- * @param cp constant pool
+ * @param returnType method type
+ * @param argTypes argument types
+ * @param argNames argument names (if this is null, default names will be provided for them)
+ * @param methodName name of method
+ * @param className class name containing this method (may be null, if you don't care)
+ * @param il instruction list associated with this method, may be null only for abstract or native methods
+ * @param cp constant pool
*/
public MethodGen(final int accessFlags, final Type returnType, final Type[] argTypes, String[] argNames, final String methodName, final String className,
- final InstructionList il, final ConstantPoolGen cp) {
+ final InstructionList il, final ConstantPoolGen cp) {
super(accessFlags);
setType(returnType);
setArgumentTypes(argTypes);
@@ -283,15 +138,15 @@ public class MethodGen extends FieldGenOrMethodGen {
/**
* Instantiate from existing method.
*
- * @param method method
+ * @param method method
* @param className class name containing this method
- * @param cp constant pool
+ * @param cp constant pool
*/
public MethodGen(final JavaMethod method, final String className, final ConstantPoolGen cp) {
this(method.getAccessFlags(), Type.getReturnType(method.getSignature()), Type.getArgumentTypes(method.getSignature()),
- null /* may be overridden anyway */
- , method.getName(), className,
- (method.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0 ? new InstructionList(getByteCodes(method)) : null, cp);
+ null /* may be overridden anyway */
+ , method.getName(), className,
+ (method.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0 ? new InstructionList(getByteCodes(method)) : null, cp);
final Attribute[] attributes = method.getAttributes();
for (final Attribute attribute : attributes) {
Attribute a = attribute;
@@ -349,6 +204,100 @@ public class MethodGen extends FieldGenOrMethodGen {
}
}
+ private static byte[] getByteCodes(final JavaMethod method) {
+ final Code code = method.getCode();
+ if (code == null) {
+ throw new IllegalStateException(String.format("The method '%s' has no code.", method));
+ }
+ return code.getCode();
+ }
+
+ /**
+ * @return Comparison strategy object
+ */
+ public static BCELComparator getComparator() {
+ return bcelComparator;
+ }
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
+ }
+
+ /**
+ * Computes stack usage of an instruction list by performing control flow analysis.
+ *
+ * @return maximum stack depth used by method
+ */
+ public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et) {
+ final BranchStack branchTargets = new BranchStack();
+ /*
+ * Initially, populate the branch stack with the exception handlers, because these aren't (necessarily) branched to
+ * explicitly. in each case, the stack will have depth 1, containing the exception object.
+ */
+ for (final CodeExceptionGen element : et) {
+ final InstructionHandle handlerPc = element.getHandlerPC();
+ if (handlerPc != null) {
+ branchTargets.push(handlerPc, 1);
+ }
+ }
+ int stackDepth = 0;
+ int maxStackDepth = 0;
+ InstructionHandle ih = il.getStart();
+ while (ih != null) {
+ final Instruction instruction = ih.getInstruction();
+ final short opcode = instruction.getOpcode();
+ final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
+ stackDepth += delta;
+ if (stackDepth > maxStackDepth) {
+ maxStackDepth = stackDepth;
+ }
+ // choose the next instruction based on whether current is a branch.
+ if (instruction instanceof BranchInstruction) {
+ final BranchInstruction branch = (BranchInstruction) instruction;
+ if (instruction instanceof Select) {
+ // explore all of the select's targets. the default target is handled below.
+ final Select select = (Select) branch;
+ final InstructionHandle[] targets = select.getTargets();
+ for (final InstructionHandle target : targets) {
+ branchTargets.push(target, stackDepth);
+ }
+ // nothing to fall through to.
+ ih = null;
+ } else if (!(branch instanceof IfInstruction)) {
+ // if an instruction that comes back to following PC,
+ // push next instruction, with stack depth reduced by 1.
+ if (opcode == Const.JSR || opcode == Const.JSR_W) {
+ branchTargets.push(ih.getNext(), stackDepth - 1);
+ }
+ ih = null;
+ }
+ // for all branches, the target of the branch is pushed on the branch stack.
+ // conditional branches have a fall through case, selects don't, and
+ // jsr/jsr_w return to the next instruction.
+ branchTargets.push(branch.getTarget(), stackDepth);
+ } else // check for instructions that terminate the method.
+ if (opcode == Const.ATHROW || opcode == Const.RET || opcode >= Const.IRETURN && opcode <= Const.RETURN) {
+ ih = null;
+ }
+ // normal case, go to the next instruction.
+ if (ih != null) {
+ ih = ih.getNext();
+ }
+ // if we have no more instructions, see if there are any deferred branches to explore.
+ if (ih == null) {
+ final BranchTarget bt = branchTargets.pop();
+ if (bt != null) {
+ ih = bt.target;
+ stackDepth = bt.stackDepth;
+ }
+ }
+ }
+ return maxStackDepth;
+ }
+
/**
* @since 6.0
*/
@@ -380,14 +329,14 @@ public class MethodGen extends FieldGenOrMethodGen {
* Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling
* is done.
*
- * @param startPc Start of region (inclusive)
- * @param endPc End of region (inclusive)
+ * @param startPc Start of region (inclusive)
+ * @param endPc End of region (inclusive)
* @param handlerPc Where handling is done
* @param catchType class type of handled exception or null if any exception is handled
* @return new exception handler object
*/
public CodeExceptionGen addExceptionHandler(final InstructionHandle startPc, final InstructionHandle endPc, final InstructionHandle handlerPc,
- final ObjectType catchType) {
+ final ObjectType catchType) {
if (startPc == null || endPc == null || handlerPc == null) {
throw new ClassGenException("Exception handler target is null instruction");
}
@@ -412,10 +361,10 @@ public class MethodGen extends FieldGenOrMethodGen {
/**
* Adds a local variable to this method and assigns an index automatically.
*
- * @param name variable name
- * @param type variable type
+ * @param name variable name
+ * @param type variable type
* @param start from where the variable is valid, if this is null, it is valid from the start
- * @param end until where the variable is valid, if this is null, it is valid to the end
+ * @param end until where the variable is valid, if this is null, it is valid to the end
* @return new local variable object
* @see LocalVariable
*/
@@ -426,11 +375,11 @@ public class MethodGen extends FieldGenOrMethodGen {
/**
* Adds a local variable to this method.
*
- * @param name variable name
- * @param type variable type
- * @param slot the index of the local variable, if type is long or double, the next available index is slot+2
+ * @param name variable name
+ * @param type variable type
+ * @param slot the index of the local variable, if type is long or double, the next available index is slot+2
* @param start from where the variable is valid
- * @param end until where the variable is valid
+ * @param end until where the variable is valid
* @return new local variable object
* @see LocalVariable
*/
@@ -441,17 +390,17 @@ public class MethodGen extends FieldGenOrMethodGen {
/**
* Adds a local variable to this method.
*
- * @param name variable name
- * @param type variable type
- * @param slot the index of the local variable, if type is long or double, the next available index is slot+2
- * @param start from where the variable is valid
- * @param end until where the variable is valid
+ * @param name variable name
+ * @param type variable type
+ * @param slot the index of the local variable, if type is long or double, the next available index is slot+2
+ * @param start from where the variable is valid
+ * @param end until where the variable is valid
* @param origIndex the index of the local variable prior to any modifications
* @return new local variable object
* @see LocalVariable
*/
public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot, final InstructionHandle start, final InstructionHandle end,
- final int origIndex) {
+ final int origIndex) {
final byte t = type.getType();
if (t != Const.T_ADDRESS) {
final int add = type.getSize();
@@ -614,8 +563,6 @@ public class MethodGen extends FieldGenOrMethodGen {
return bcelComparator.equals(this, obj);
}
- // J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this
- // is more likely to suggest to the caller it is readonly (which a List does not).
/**
* Return a list of AnnotationGen objects representing parameter annotations
*
@@ -633,10 +580,17 @@ public class MethodGen extends FieldGenOrMethodGen {
return argNames[i];
}
+ // J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this
+ // is more likely to suggest to the caller it is readonly (which a List does not).
+
public String[] getArgumentNames() {
return argNames.clone();
}
+ public void setArgumentNames(final String[] argNames) {
+ this.argNames = argNames;
+ }
+
public Type getArgumentType(final int i) {
return argTypes[i];
}
@@ -645,6 +599,10 @@ public class MethodGen extends FieldGenOrMethodGen {
return argTypes.clone();
}
+ public void setArgumentTypes(final Type[] argTypes) {
+ this.argTypes = argTypes;
+ }
+
/**
* @return class that contains this method
*/
@@ -652,6 +610,10 @@ public class MethodGen extends FieldGenOrMethodGen {
return className;
}
+ public void setClassName(final String className) { // TODO could be package-protected?
+ this.className = className;
+ }
+
/**
* @return all attributes of this method.
*/
@@ -697,6 +659,10 @@ public class MethodGen extends FieldGenOrMethodGen {
return il;
}
+ public void setInstructionList(final InstructionList il) { // TODO could be package-protected?
+ this.il = il;
+ }
+
/*
* @return array of line numbers
*/
@@ -760,10 +726,24 @@ public class MethodGen extends FieldGenOrMethodGen {
return maxLocals;
}
+ /**
+ * Set maximum number of local variables.
+ */
+ public void setMaxLocals(final int m) {
+ maxLocals = m;
+ }
+
public int getMaxStack() {
return maxStack;
}
+ /**
+ * Set maximum stack size for this method.
+ */
+ public void setMaxStack(final int m) { // TODO could be package-protected?
+ maxStack = m;
+ }
+
/**
* Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method
* (the same applies for max locals).
@@ -819,9 +799,9 @@ public class MethodGen extends FieldGenOrMethodGen {
}
}
code = new Code(cp.addUtf8("Code"), 8 + byteCode.length + // prologue byte code
- 2 + excLen + // exceptions
- 2 + attrsLen, // attributes
- maxStack, maxLocals, byteCode, cExc, codeAttrs, cp.getConstantPool());
+ 2 + excLen + // exceptions
+ 2 + attrsLen, // attributes
+ maxStack, maxLocals, byteCode, cExc, codeAttrs, cp.getConstantPool());
addAttribute(code);
}
final Attribute[] annotations = addRuntimeAnnotationsAsAttribute(cp);
@@ -857,6 +837,10 @@ public class MethodGen extends FieldGenOrMethodGen {
return getType();
}
+ public void setReturnType(final Type returnType) {
+ setType(returnType);
+ }
+
@Override
public String getSignature() {
return Type.getMethodSignature(super.getType(), argTypes);
@@ -1014,26 +998,10 @@ public class MethodGen extends FieldGenOrMethodGen {
argNames[i] = name;
}
- public void setArgumentNames(final String[] argNames) {
- this.argNames = argNames;
- }
-
public void setArgumentType(final int i, final Type type) {
argTypes[i] = type;
}
- public void setArgumentTypes(final Type[] argTypes) {
- this.argTypes = argTypes;
- }
-
- public void setClassName(final String className) { // TODO could be package-protected?
- this.className = className;
- }
-
- public void setInstructionList(final InstructionList il) { // TODO could be package-protected?
- this.il = il;
- }
-
/**
* Compute maximum number of local variables.
*/
@@ -1060,13 +1028,6 @@ public class MethodGen extends FieldGenOrMethodGen {
}
}
- /**
- * Set maximum number of local variables.
- */
- public void setMaxLocals(final int m) {
- maxLocals = m;
- }
-
/**
* Computes max. stack size by performing control flow analysis.
*/
@@ -1078,17 +1039,6 @@ public class MethodGen extends FieldGenOrMethodGen {
}
}
- /**
- * Set maximum stack size for this method.
- */
- public void setMaxStack(final int m) { // TODO could be package-protected?
- maxStack = m;
- }
-
- public void setReturnType(final Type returnType) {
- setType(returnType);
- }
-
/**
* Do not/Do produce attributes code attributesLineNumberTable and LocalVariableTable, like javac -O
*/
@@ -1149,4 +1099,45 @@ public class MethodGen extends FieldGenOrMethodGen {
addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end, l.getOrigIndex());
}
}
+
+ static final class BranchStack {
+
+ private final Stack branchTargets = new Stack<>();
+ private final Hashtable visitedTargets = new Hashtable<>();
+
+ public BranchTarget pop() {
+ if (!branchTargets.empty()) {
+ return branchTargets.pop();
+ }
+ return null;
+ }
+
+ public void push(final InstructionHandle target, final int stackDepth) {
+ if (visited(target)) {
+ return;
+ }
+ branchTargets.push(visit(target, stackDepth));
+ }
+
+ private BranchTarget visit(final InstructionHandle target, final int stackDepth) {
+ final BranchTarget bt = new BranchTarget(target, stackDepth);
+ visitedTargets.put(target, bt);
+ return bt;
+ }
+
+ private boolean visited(final InstructionHandle target) {
+ return visitedTargets.get(target) != null;
+ }
+ }
+
+ static final class BranchTarget {
+
+ final InstructionHandle target;
+ final int stackDepth;
+
+ BranchTarget(final InstructionHandle target, final int stackDepth) {
+ this.target = target;
+ this.stackDepth = stackDepth;
+ }
+ }
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/NEW.java b/src/main/java/haidnor/jvm/bcel/generic/NEW.java
index 9c7d0e8..6ee2b72 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/NEW.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/NEW.java
@@ -58,7 +58,7 @@ public class NEW extends CPInstruction implements LoadClass, AllocationInstructi
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_CLASS_AND_INTERFACE_RESOLUTION, ExceptionConst.ILLEGAL_ACCESS_ERROR,
- ExceptionConst.INSTANTIATION_ERROR);
+ ExceptionConst.INSTANTIATION_ERROR);
}
@Override
diff --git a/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java b/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java
index 4e8514a..1c520c0 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/NEWARRAY.java
@@ -29,7 +29,7 @@ import java.io.IOException;
*
* Stack: ..., count -> ..., arrayref
*
- *
+ *
* type must be one of T_INT, T_SHORT, ...
*/
public class NEWARRAY extends Instruction implements AllocationInstruction, ExceptionThrower, StackProducer {
@@ -78,7 +78,7 @@ public class NEWARRAY extends Instruction implements AllocationInstruction, Exce
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION};
+ return new Class[]{ExceptionConst.NEGATIVE_ARRAY_SIZE_EXCEPTION};
}
/**
diff --git a/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java b/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java
index dd76de8..b567ab1 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/NamedAndTyped.java
@@ -23,9 +23,9 @@ public interface NamedAndTyped {
String getName();
- Type getType();
-
void setName(String name);
+ Type getType();
+
void setType(Type type);
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java b/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java
index 0ccb1d8..3d535a6 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ObjectType.java
@@ -26,17 +26,6 @@ import haidnor.jvm.bcel.classfile.Utility;
*/
public class ObjectType extends ReferenceType {
- /**
- * Constructs a new instance.
- *
- * @param className fully qualified class name, e.g. java.lang.String
- * @return a new instance.
- * @since 6.0
- */
- public static ObjectType getInstance(final String className) {
- return new ObjectType(className);
- }
-
private final String className; // Class name of type
/**
@@ -49,6 +38,17 @@ public class ObjectType extends ReferenceType {
this.className = Utility.pathToPackage(className);
}
+ /**
+ * Constructs a new instance.
+ *
+ * @param className fully qualified class name, e.g. java.lang.String
+ * @return a new instance.
+ * @since 6.0
+ */
+ public static ObjectType getInstance(final String className) {
+ return new ObjectType(className);
+ }
+
/**
* Java Virtual Machine Specification edition 2, � 5.4.4 Access Control
*
@@ -89,8 +89,9 @@ public class ObjectType extends ReferenceType {
/**
* If "this" doesn't reference a class, it references an interface or a non-existant entity.
+ *
* @deprecated (since 6.0) this method returns an inaccurate result if the class or interface referenced cannot be
- * found: use referencesClassExact() instead
+ * found: use referencesClassExact() instead
*/
@Deprecated
public boolean referencesClass() {
@@ -117,7 +118,7 @@ public class ObjectType extends ReferenceType {
* If "this" doesn't reference an interface, it references a class or a non-existant entity.
*
* @deprecated (since 6.0) this method returns an inaccurate result if the class or interface referenced cannot be
- * found: use referencesInterfaceExact() instead
+ * found: use referencesInterfaceExact() instead
*/
@Deprecated
public boolean referencesInterface() {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/PUSH.java b/src/main/java/haidnor/jvm/bcel/generic/PUSH.java
index 86dcd09..bc86caa 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/PUSH.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/PUSH.java
@@ -30,7 +30,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
/**
* Pushes an array type constant, for example {@code int[].class}, {@code String[].class}, and so on.
*
- * @param cp generated constant pool.
+ * @param cp generated constant pool.
* @param value to be pushed.
* @since 6.7.0
*/
@@ -42,8 +42,8 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
}
- /**
- * @param cp Constant pool
+ /**
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final boolean value) {
@@ -52,7 +52,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final Boolean value) {
@@ -63,7 +63,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
* creates a push object from a Character value. Warning: Make sure not to attempt to allow autoboxing to create this
* value parameter, as an alternative constructor will be called
*
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final Character value) {
@@ -71,7 +71,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final double value) {
@@ -85,7 +85,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final float value) {
@@ -103,7 +103,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
/**
* This constructor also applies for values of type short, char, byte
*
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final int value) {
@@ -119,7 +119,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final long value) {
@@ -133,7 +133,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final Number value) {
@@ -151,7 +151,6 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- *
* @param cp
* @param value
* @since 6.0
@@ -165,7 +164,7 @@ public final class PUSH implements CompoundInstruction, VariableLengthInstructio
}
/**
- * @param cp Constant pool
+ * @param cp Constant pool
* @param value to be pushed
*/
public PUSH(final ConstantPoolGen cp, final String value) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java b/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java
index be1688c..cda8377 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/PUTFIELD.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
*
* Stack: ..., objectref, value -> ...
*
- *
+ *
* OR
*
*
@@ -71,6 +71,6 @@ public class PUTFIELD extends FieldInstruction implements PopInstruction, Except
@Override
public Class>[] getExceptions() {
return ExceptionConst.createExceptions(ExceptionConst.EXCS.EXCS_FIELD_AND_METHOD_RESOLUTION, ExceptionConst.NULL_POINTER_EXCEPTION,
- ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
+ ExceptionConst.INCOMPATIBLE_CLASS_CHANGE_ERROR);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java b/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java
index 800c170..9151f36 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/PUTSTATIC.java
@@ -25,7 +25,7 @@ import haidnor.jvm.bcel.ExceptionConst;
*
* Stack: ..., value -> ...
*
- *
+ *
* OR
*
*
diff --git a/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java
index b3cdb52..d3d8f73 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/PushInstruction.java
@@ -20,7 +20,6 @@ package haidnor.jvm.bcel.generic;
* Denotes an unparameterized instruction to produce a value on top of the stack, such as ILOAD, LDC, SIPUSH, DUP,
* ICONST, etc.
*
- *
* @see ILOAD
* @see ICONST
* @see LDC
diff --git a/src/main/java/haidnor/jvm/bcel/generic/RET.java b/src/main/java/haidnor/jvm/bcel/generic/RET.java
index 665de71..f3de96b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/RET.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/RET.java
@@ -82,6 +82,18 @@ public class RET extends Instruction implements IndexedInstruction, TypedInstruc
return index;
}
+ /**
+ * Set index of local variable containg the return address
+ */
+ @Override
+ public final void setIndex(final int n) {
+ if (n < 0) {
+ throw new ClassGenException("Negative index value: " + n);
+ }
+ index = n;
+ setWide();
+ }
+
/**
* @return return address type
*/
@@ -105,18 +117,6 @@ public class RET extends Instruction implements IndexedInstruction, TypedInstruc
}
}
- /**
- * Set index of local variable containg the return address
- */
- @Override
- public final void setIndex(final int n) {
- if (n < 0) {
- throw new ClassGenException("Negative index value: " + n);
- }
- index = n;
- setWide();
- }
-
private void setWide() {
wide = index > Const.MAX_BYTE;
if (wide) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java b/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java
index a681c7c..72d25be 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ReferenceType.java
@@ -44,8 +44,8 @@ public abstract class ReferenceType extends Type {
* interface, then Type.OBJECT is returned. If not all of the two classes' superclasses cannot be found, "null" is
* returned. See the JVM specification edition 2, "�4.9.2 The Bytecode Verifier".
*
- * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics.
* @throws ClassNotFoundException on failure to find superclasses of this type, or the type passed as a parameter
+ * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics.
*/
@Deprecated
public ReferenceType firstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException {
@@ -96,9 +96,9 @@ public abstract class ReferenceType extends Type {
final ArrayType arrType1 = (ArrayType) this;
final ArrayType arrType2 = (ArrayType) t;
if (arrType1.getDimensions() == arrType2.getDimensions() && arrType1.getBasicType() instanceof ObjectType
- && arrType2.getBasicType() instanceof ObjectType) {
+ && arrType2.getBasicType() instanceof ObjectType) {
return new ArrayType(((ObjectType) arrType1.getBasicType()).getFirstCommonSuperclass((ObjectType) arrType2.getBasicType()),
- arrType1.getDimensions());
+ arrType1.getDimensions());
}
}
if (this instanceof ArrayType || t instanceof ArrayType) {
@@ -110,7 +110,7 @@ public abstract class ReferenceType extends Type {
private ReferenceType getFirstCommonSuperclassInternal(final ReferenceType t) throws ClassNotFoundException {
if (this instanceof ObjectType && ((ObjectType) this).referencesInterfaceExact()
- || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) {
+ || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) {
return Type.OBJECT;
// TODO: The above line is correct comparing to the vmspec2. But one could
// make class file verification a bit stronger here by using the notion of
@@ -147,7 +147,7 @@ public abstract class ReferenceType extends Type {
* AASTORE definition there.
*
* @throws ClassNotFoundException if any classes or interfaces required to determine assignment compatibility can't be
- * found
+ * found
*/
public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundException {
if (!(t instanceof ReferenceType)) {
@@ -165,14 +165,14 @@ public abstract class ReferenceType extends Type {
* If T is a class type, then this must be the same class as T, or this must be a subclass of T;
*/
if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact()
- && (this.equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
+ && (this.equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
return true;
}
/*
* If T is an interface type, this must implement interface T.
*/
if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact()
- && Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName())) {
+ && Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName())) {
return true;
}
}
@@ -190,7 +190,7 @@ public abstract class ReferenceType extends Type {
* If T is an interface type, then T must be the same interface as this or a superinterface of this (�2.13.2).
*/
if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact()
- && (this.equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
+ && (this.equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) {
return true;
}
}
@@ -246,7 +246,7 @@ public abstract class ReferenceType extends Type {
* doesn't throw a ClassCastException when casting a null reference to any Object, true is returned in this case.
*
* @throws ClassNotFoundException if any classes or interfaces required to determine assignment compatibility can't be
- * found
+ * found
*/
public boolean isCastableTo(final Type t) throws ClassNotFoundException {
if (this.equals(Type.NULL)) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java
index c979b61..004be9d 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ReturnInstruction.java
@@ -39,26 +39,26 @@ public abstract class ReturnInstruction extends Instruction implements Exception
@Override
public Class>[] getExceptions() {
- return new Class[] {ExceptionConst.ILLEGAL_MONITOR_STATE};
+ return new Class[]{ExceptionConst.ILLEGAL_MONITOR_STATE};
}
public Type getType() {
final short opcode = super.getOpcode();
switch (opcode) {
- case Const.IRETURN:
- return Type.INT;
- case Const.LRETURN:
- return Type.LONG;
- case Const.FRETURN:
- return Type.FLOAT;
- case Const.DRETURN:
- return Type.DOUBLE;
- case Const.ARETURN:
- return Type.OBJECT;
- case Const.RETURN:
- return Type.VOID;
- default: // Never reached
- throw new ClassGenException("Unknown type " + opcode);
+ case Const.IRETURN:
+ return Type.INT;
+ case Const.LRETURN:
+ return Type.LONG;
+ case Const.FRETURN:
+ return Type.FLOAT;
+ case Const.DRETURN:
+ return Type.DOUBLE;
+ case Const.ARETURN:
+ return Type.OBJECT;
+ case Const.RETURN:
+ return Type.VOID;
+ default: // Never reached
+ throw new ClassGenException("Unknown type " + opcode);
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java b/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java
index 8191907..16deb8b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/ReturnaddressType.java
@@ -20,7 +20,7 @@ import haidnor.jvm.bcel.Const;
/**
* Returnaddress, the type JSR or JSR_W instructions push upon the stack.
- *
+ *
* see vmspec2 �3.3.3
*/
public class ReturnaddressType extends Type {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java b/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java
index 11fce8d..8653986 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/SWITCH.java
@@ -24,6 +24,58 @@ import java.util.Arrays;
*/
public final class SWITCH implements CompoundInstruction {
+ private final Select instruction;
+
+ public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target) {
+ this(match, targets, target, 1);
+ }
+
+ /**
+ * Template for switch() constructs. If the match array can be sorted in ascending order with gaps no larger than
+ * maxGap between the numbers, a TABLESWITCH instruction is generated, and a LOOKUPSWITCH otherwise. The former may be
+ * more efficient, but needs more space.
+ *
+ * Note, that the key array always will be sorted, though we leave the original arrays unaltered.
+ *
+ * @param match array of match values (case 2: ... case 7: ..., etc.)
+ * @param targets the instructions to be branched to for each case
+ * @param target the default target
+ * @param maxGap maximum gap that may between case branches
+ */
+ public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int maxGap) {
+ int[] matchClone = match.clone();
+ final InstructionHandle[] targetsClone = targets.clone();
+ final int matchLength = match.length;
+ if (matchLength < 2) {
+ instruction = new TABLESWITCH(match, targets, target);
+ } else {
+ sort(0, matchLength - 1, matchClone, targetsClone);
+ if (matchIsOrdered(matchClone, matchLength, maxGap)) {
+ final int maxSize = matchLength + matchLength * maxGap;
+ final int[] mVec = new int[maxSize];
+ final InstructionHandle[] tVec = new InstructionHandle[maxSize];
+ int count = 1;
+ mVec[0] = match[0];
+ tVec[0] = targets[0];
+ for (int i = 1; i < matchLength; i++) {
+ final int prev = match[i - 1];
+ final int gap = match[i] - prev;
+ for (int j = 1; j < gap; j++) {
+ mVec[count] = prev + j;
+ tVec[count] = target;
+ count++;
+ }
+ mVec[count] = match[i];
+ tVec[count] = targets[i];
+ count++;
+ }
+ instruction = new TABLESWITCH(Arrays.copyOf(mVec, count), Arrays.copyOf(tVec, count), target);
+ } else {
+ instruction = new LOOKUPSWITCH(matchClone, targetsClone, target);
+ }
+ }
+ }
+
/**
* @return match is sorted in ascending order with no gap bigger than maxGap?
*/
@@ -71,58 +123,6 @@ public final class SWITCH implements CompoundInstruction {
}
}
- private final Select instruction;
-
- public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target) {
- this(match, targets, target, 1);
- }
-
- /**
- * Template for switch() constructs. If the match array can be sorted in ascending order with gaps no larger than
- * maxGap between the numbers, a TABLESWITCH instruction is generated, and a LOOKUPSWITCH otherwise. The former may be
- * more efficient, but needs more space.
- *
- * Note, that the key array always will be sorted, though we leave the original arrays unaltered.
- *
- * @param match array of match values (case 2: ... case 7: ..., etc.)
- * @param targets the instructions to be branched to for each case
- * @param target the default target
- * @param maxGap maximum gap that may between case branches
- */
- public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int maxGap) {
- int[] matchClone = match.clone();
- final InstructionHandle[] targetsClone = targets.clone();
- final int matchLength = match.length;
- if (matchLength < 2) {
- instruction = new TABLESWITCH(match, targets, target);
- } else {
- sort(0, matchLength - 1, matchClone, targetsClone);
- if (matchIsOrdered(matchClone, matchLength, maxGap)) {
- final int maxSize = matchLength + matchLength * maxGap;
- final int[] mVec = new int[maxSize];
- final InstructionHandle[] tVec = new InstructionHandle[maxSize];
- int count = 1;
- mVec[0] = match[0];
- tVec[0] = targets[0];
- for (int i = 1; i < matchLength; i++) {
- final int prev = match[i - 1];
- final int gap = match[i] - prev;
- for (int j = 1; j < gap; j++) {
- mVec[count] = prev + j;
- tVec[count] = target;
- count++;
- }
- mVec[count] = match[i];
- tVec[count] = targets[i];
- count++;
- }
- instruction = new TABLESWITCH(Arrays.copyOf(mVec, count), Arrays.copyOf(tVec, count), target);
- } else {
- instruction = new LOOKUPSWITCH(matchClone, targetsClone, target);
- }
- }
- }
-
public Instruction getInstruction() {
return instruction;
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/Select.java b/src/main/java/haidnor/jvm/bcel/generic/Select.java
index 3f1808a..3db5e6f 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/Select.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/Select.java
@@ -78,8 +78,8 @@ public abstract class Select extends BranchInstruction implements VariableLength
/**
* (Match, target) pairs for switch. 'Match' and 'targets' must have the same length of course.
*
- * @param match array of matching values
- * @param targets instruction targets
+ * @param match array of matching values
+ * @param targets instruction targets
* @param defaultTarget default instruction target
*/
Select(final short opcode, final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) {
@@ -157,6 +157,14 @@ public abstract class Select extends BranchInstruction implements VariableLength
return fixed_length;
}
+ /**
+ * @param fixedLength the fixed_length to set
+ * @since 6.0
+ */
+ final void setFixedLength(final int fixedLength) {
+ this.fixed_length = fixedLength;
+ }
+
/**
* @return array of match target offsets
*/
@@ -164,6 +172,14 @@ public abstract class Select extends BranchInstruction implements VariableLength
return indices;
}
+ /**
+ * @param array
+ * @since 6.0
+ */
+ final void setIndices(final int[] array) {
+ indices = array;
+ }
+
/**
* @return index entry from indices
* @since 6.0
@@ -196,7 +212,6 @@ public abstract class Select extends BranchInstruction implements VariableLength
}
/**
- *
* @return the padding
* @since 6.0
*/
@@ -219,6 +234,14 @@ public abstract class Select extends BranchInstruction implements VariableLength
return targets;
}
+ /**
+ * @param array
+ * @since 6.0
+ */
+ final void setTargets(final InstructionHandle[] array) {
+ targets = array;
+ }
+
/**
* Read needed data (e.g. index) from file.
*/
@@ -233,30 +256,14 @@ public abstract class Select extends BranchInstruction implements VariableLength
}
/**
- * @param fixedLength the fixed_length to set
* @since 6.0
*/
- final void setFixedLength(final int fixedLength) {
- this.fixed_length = fixedLength;
- }
-
- /** @since 6.0 */
final int setIndices(final int i, final int value) {
indices[i] = value;
return value; // Allow use in nested calls
}
/**
- *
- * @param array
- * @since 6.0
- */
- final void setIndices(final int[] array) {
- indices = array;
- }
-
- /**
- *
* @param index
* @param value
* @since 6.0
@@ -266,7 +273,6 @@ public abstract class Select extends BranchInstruction implements VariableLength
}
/**
- *
* @param array
* @since 6.0
*/
@@ -291,15 +297,6 @@ public abstract class Select extends BranchInstruction implements VariableLength
targets[i] = target;
}
- /**
- *
- * @param array
- * @since 6.0
- */
- final void setTargets(final InstructionHandle[] array) {
- targets = array;
- }
-
/**
* @return mnemonic for instruction
*/
@@ -323,12 +320,12 @@ public abstract class Select extends BranchInstruction implements VariableLength
/**
* Since this is a variable length instruction, it may shift the following instructions which then need to update their
* position.
- *
+ *
* Called by InstructionList.setPositions when setting the position for every instruction. In the presence of variable
* length instructions 'setPositions' performs multiple passes over the instruction list to calculate the correct (byte)
* positions and offsets by calling this function.
*
- * @param offset additional offset caused by preceding (variable length) instructions
+ * @param offset additional offset caused by preceding (variable length) instructions
* @param maxOffset the maximum offset that may be caused by these instructions
* @return additional offset caused by possible change of this instruction's length
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java b/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java
index 4b53711..607812b 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/SimpleElementValueGen.java
@@ -81,6 +81,7 @@ public class SimpleElementValueGen extends ElementValueGen {
// ctors for each supported type... type could be inferred but for now lets
// force it to be passed
+
/**
* Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, assumes the one at the supplied
* index is correct.
@@ -102,39 +103,39 @@ public class SimpleElementValueGen extends ElementValueGen {
idx = value.getIndex();
} else {
switch (value.getElementValueType()) {
- case STRING:
- idx = cpool.addUtf8(value.getValueString());
- break;
- case PRIMITIVE_INT:
- idx = cpool.addInteger(value.getValueInt());
- break;
- case PRIMITIVE_BYTE:
- idx = cpool.addInteger(value.getValueByte());
- break;
- case PRIMITIVE_CHAR:
- idx = cpool.addInteger(value.getValueChar());
- break;
- case PRIMITIVE_LONG:
- idx = cpool.addLong(value.getValueLong());
- break;
- case PRIMITIVE_FLOAT:
- idx = cpool.addFloat(value.getValueFloat());
- break;
- case PRIMITIVE_DOUBLE:
- idx = cpool.addDouble(value.getValueDouble());
- break;
- case PRIMITIVE_BOOLEAN:
- if (value.getValueBoolean()) {
- idx = cpool.addInteger(1);
- } else {
- idx = cpool.addInteger(0);
- }
- break;
- case PRIMITIVE_SHORT:
- idx = cpool.addInteger(value.getValueShort());
- break;
- default:
- throw new IllegalArgumentException("SimpleElementValueGen class does not know how to copy this type " + super.getElementValueType());
+ case STRING:
+ idx = cpool.addUtf8(value.getValueString());
+ break;
+ case PRIMITIVE_INT:
+ idx = cpool.addInteger(value.getValueInt());
+ break;
+ case PRIMITIVE_BYTE:
+ idx = cpool.addInteger(value.getValueByte());
+ break;
+ case PRIMITIVE_CHAR:
+ idx = cpool.addInteger(value.getValueChar());
+ break;
+ case PRIMITIVE_LONG:
+ idx = cpool.addLong(value.getValueLong());
+ break;
+ case PRIMITIVE_FLOAT:
+ idx = cpool.addFloat(value.getValueFloat());
+ break;
+ case PRIMITIVE_DOUBLE:
+ idx = cpool.addDouble(value.getValueDouble());
+ break;
+ case PRIMITIVE_BOOLEAN:
+ if (value.getValueBoolean()) {
+ idx = cpool.addInteger(1);
+ } else {
+ idx = cpool.addInteger(0);
+ }
+ break;
+ case PRIMITIVE_SHORT:
+ idx = cpool.addInteger(value.getValueShort());
+ break;
+ default:
+ throw new IllegalArgumentException("SimpleElementValueGen class does not know how to copy this type " + super.getElementValueType());
}
}
}
@@ -143,19 +144,19 @@ public class SimpleElementValueGen extends ElementValueGen {
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getElementValueType()); // u1 kind of value
switch (super.getElementValueType()) {
- case PRIMITIVE_INT:
- case PRIMITIVE_BYTE:
- case PRIMITIVE_CHAR:
- case PRIMITIVE_FLOAT:
- case PRIMITIVE_LONG:
- case PRIMITIVE_BOOLEAN:
- case PRIMITIVE_SHORT:
- case PRIMITIVE_DOUBLE:
- case STRING:
- dos.writeShort(idx);
- break;
- default:
- throw new IllegalStateException("SimpleElementValueGen doesnt know how to write out type " + super.getElementValueType());
+ case PRIMITIVE_INT:
+ case PRIMITIVE_BYTE:
+ case PRIMITIVE_CHAR:
+ case PRIMITIVE_FLOAT:
+ case PRIMITIVE_LONG:
+ case PRIMITIVE_BOOLEAN:
+ case PRIMITIVE_SHORT:
+ case PRIMITIVE_DOUBLE:
+ case STRING:
+ dos.writeShort(idx);
+ break;
+ default:
+ throw new IllegalStateException("SimpleElementValueGen doesnt know how to write out type " + super.getElementValueType());
}
}
@@ -191,38 +192,38 @@ public class SimpleElementValueGen extends ElementValueGen {
@Override
public String stringifyValue() {
switch (super.getElementValueType()) {
- case PRIMITIVE_INT:
- final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx);
- return Integer.toString(c.getBytes());
- case PRIMITIVE_LONG:
- final ConstantLong j = (ConstantLong) getConstantPool().getConstant(idx);
- return Long.toString(j.getBytes());
- case PRIMITIVE_DOUBLE:
- final ConstantDouble d = (ConstantDouble) getConstantPool().getConstant(idx);
- return Double.toString(d.getBytes());
- case PRIMITIVE_FLOAT:
- final ConstantFloat f = (ConstantFloat) getConstantPool().getConstant(idx);
- return Float.toString(f.getBytes());
- case PRIMITIVE_SHORT:
- final ConstantInteger s = (ConstantInteger) getConstantPool().getConstant(idx);
- return Integer.toString(s.getBytes());
- case PRIMITIVE_BYTE:
- final ConstantInteger b = (ConstantInteger) getConstantPool().getConstant(idx);
- return Integer.toString(b.getBytes());
- case PRIMITIVE_CHAR:
- final ConstantInteger ch = (ConstantInteger) getConstantPool().getConstant(idx);
- return Integer.toString(ch.getBytes());
- case PRIMITIVE_BOOLEAN:
- final ConstantInteger bo = (ConstantInteger) getConstantPool().getConstant(idx);
- if (bo.getBytes() == 0) {
- return "false";
- }
- return "true";
- case STRING:
- final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx);
- return cu8.getBytes();
- default:
- throw new IllegalStateException("SimpleElementValueGen class does not know how to stringify type " + super.getElementValueType());
+ case PRIMITIVE_INT:
+ final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx);
+ return Integer.toString(c.getBytes());
+ case PRIMITIVE_LONG:
+ final ConstantLong j = (ConstantLong) getConstantPool().getConstant(idx);
+ return Long.toString(j.getBytes());
+ case PRIMITIVE_DOUBLE:
+ final ConstantDouble d = (ConstantDouble) getConstantPool().getConstant(idx);
+ return Double.toString(d.getBytes());
+ case PRIMITIVE_FLOAT:
+ final ConstantFloat f = (ConstantFloat) getConstantPool().getConstant(idx);
+ return Float.toString(f.getBytes());
+ case PRIMITIVE_SHORT:
+ final ConstantInteger s = (ConstantInteger) getConstantPool().getConstant(idx);
+ return Integer.toString(s.getBytes());
+ case PRIMITIVE_BYTE:
+ final ConstantInteger b = (ConstantInteger) getConstantPool().getConstant(idx);
+ return Integer.toString(b.getBytes());
+ case PRIMITIVE_CHAR:
+ final ConstantInteger ch = (ConstantInteger) getConstantPool().getConstant(idx);
+ return Integer.toString(ch.getBytes());
+ case PRIMITIVE_BOOLEAN:
+ final ConstantInteger bo = (ConstantInteger) getConstantPool().getConstant(idx);
+ if (bo.getBytes() == 0) {
+ return "false";
+ }
+ return "true";
+ case STRING:
+ final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx);
+ return cu8.getBytes();
+ default:
+ throw new IllegalStateException("SimpleElementValueGen class does not know how to stringify type " + super.getElementValueType());
}
}
}
diff --git a/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java
index 77b6bd9..2bd47a2 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/StoreInstruction.java
@@ -31,8 +31,8 @@ public abstract class StoreInstruction extends LocalVariableInstruction implemen
/**
* @param opcode Instruction opcode
- * @param cTag Instruction number for compact version, ASTORE_0, e.g.
- * @param n local variable index (unsigned short)
+ * @param cTag Instruction number for compact version, ASTORE_0, e.g.
+ * @param n local variable index (unsigned short)
*/
protected StoreInstruction(final short opcode, final short cTag, final int n) {
super(opcode, cTag, n);
diff --git a/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java b/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java
index 583fa1c..f154117 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/TABLESWITCH.java
@@ -36,8 +36,8 @@ public class TABLESWITCH extends Select {
}
/**
- * @param match sorted array of match values, match[0] must be low value, match[match_length - 1] high value
- * @param targets where to branch for matched values
+ * @param match sorted array of match values, match[0] must be low value, match[match_length - 1] high value
+ * @param targets where to branch for matched values
* @param defaultTarget default branch
*/
public TABLESWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) {
diff --git a/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java b/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java
index c2ac5fd..8a6427c 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/TargetLostException.java
@@ -27,16 +27,16 @@ package haidnor.jvm.bcel.generic;
*
*
*
- * ...
- * try {
- * il.delete(start_ih, end_ih);
- * } catch(TargetLostException e) {
- * for (InstructionHandle target : e.getTargets()) {
- * for (InstructionTargeter targeter : target.getTargeters()) {
- * targeter.updateTarget(target, new_target);
- * }
- * }
- * }
+ * ...
+ * try {
+ * il.delete(start_ih, end_ih);
+ * } catch(TargetLostException e) {
+ * for (InstructionHandle target : e.getTargets()) {
+ * for (InstructionTargeter targeter : target.getTargeters()) {
+ * targeter.updateTarget(target, new_target);
+ * }
+ * }
+ * }
*
*
* @see InstructionHandle
diff --git a/src/main/java/haidnor/jvm/bcel/generic/Type.java b/src/main/java/haidnor/jvm/bcel/generic/Type.java
index 8851d51..b6198e2 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/Type.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/Type.java
@@ -61,6 +61,21 @@ public abstract class Type {
};
private static final ThreadLocal CONSUMED_CHARS = ThreadLocal.withInitial(() -> Integer.valueOf(0));
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected byte type; // TODO should be final (and private)
+ /**
+ * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
+ */
+ @Deprecated
+ protected String signature; // signature for the type TODO should be private
+
+ protected Type(final byte type, final String signature) {
+ this.type = type;
+ this.signature = signature;
+ }
// int consumed_chars=0; // Remember position in string, see getArgumentTypes
static int consumed(final int coded) {
@@ -123,7 +138,7 @@ public abstract class Type {
* Convert type to Java method signature, e.g. int[] f(java.lang.String x) becomes (Ljava/lang/String;)[I
*
* @param returnType what the method returns
- * @param argTypes what are the argument types
+ * @param argTypes what are the argument types
* @return method signature for given type(s).
*/
public static String getMethodSignature(final Type returnType, final Type[] argTypes) {
@@ -294,23 +309,6 @@ public abstract class Type {
tl.set(Integer.valueOf(value));
}
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected byte type; // TODO should be final (and private)
-
- /**
- * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
- */
- @Deprecated
- protected String signature; // signature for the type TODO should be private
-
- protected Type(final byte type, final String signature) {
- this.type = type;
- this.signature = signature;
- }
-
/**
* @return whether the Types are equal
*/
@@ -334,18 +332,26 @@ public abstract class Type {
return signature;
}
+ /*
+ * Currently only used by the ArrayType constructor. The signature has a complicated dependency on other parameter so
+ * it's tricky to do it in a call to the super ctor.
+ */
+ void setSignature(final String signature) {
+ this.signature = signature;
+ }
+
/**
* @return stack size of this type (2 for long and double, 0 for void, 1 otherwise)
*/
public int getSize() {
switch (type) {
- case Const.T_DOUBLE:
- case Const.T_LONG:
- return 2;
- case Const.T_VOID:
- return 0;
- default:
- return 1;
+ case Const.T_DOUBLE:
+ case Const.T_LONG:
+ return 2;
+ case Const.T_VOID:
+ return 0;
+ default:
+ return 1;
}
}
@@ -377,14 +383,6 @@ public abstract class Type {
return this;
}
- /*
- * Currently only used by the ArrayType constructor. The signature has a complicated dependency on other parameter so
- * it's tricky to do it in a call to the super ctor.
- */
- void setSignature(final String signature) {
- this.signature = signature;
- }
-
/**
* @return Type string, e.g. 'int[]'
*/
diff --git a/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java b/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java
index af4feb4..adba3c9 100644
--- a/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java
+++ b/src/main/java/haidnor/jvm/bcel/generic/VariableLengthInstruction.java
@@ -19,7 +19,6 @@ package haidnor.jvm.bcel.generic;
/**
* Denotes an instruction to be a variable length instruction, such as GOTO, JSR, LOOKUPSWITCH and TABLESWITCH.
*
- *
* @see GOTO
* @see JSR
* @see LOOKUPSWITCH
diff --git a/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java b/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java
index d96ff82..3cd0a80 100644
--- a/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java
+++ b/src/main/java/haidnor/jvm/bcel/util/AbstractClassPathRepository.java
@@ -57,10 +57,10 @@ abstract class AbstractClassPathRepository implements Repository {
* the Repository version is returned. Otherwise, getResourceAsStream() is called on the Class object to find the
* class's representation. If the representation is found, it is added to the Repository.
*
- * @see Class
* @param clazz the runtime Class object
* @return JavaClass object for given runtime class
* @throws ClassNotFoundException if the class is not in the Repository, and its representation could not be found
+ * @see Class
*/
@Override
public JavaClass loadClass(final Class> clazz) throws ClassNotFoundException {
diff --git a/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java b/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java
index 7a9c2c6..7e61488 100644
--- a/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java
+++ b/src/main/java/haidnor/jvm/bcel/util/BCELFactory.java
@@ -63,7 +63,7 @@ class BCELFactory extends EmptyVisitor {
} else {
embed += "f";
}
- } else if (value instanceof Double) {
+ } else if (value instanceof Double) {
final Double d = (Double) value;
if (Double.isNaN(d)) {
embed = "Double.NaN";
@@ -134,7 +134,7 @@ class BCELFactory extends EmptyVisitor {
for (final CodeExceptionGen h : handlers) {
final String type = h.getCatchType() == null ? "null" : BCELifier.printType(h.getCatchType());
printWriter.println(" method.addExceptionHandler(" + "ih_" + h.getStartPC().getPosition() + ", " + "ih_" + h.getEndPC().getPosition() + ", "
- + "ih_" + h.getHandlerPC().getPosition() + ", " + type + ");");
+ + "ih_" + h.getHandlerPC().getPosition() + ", " + type + ");");
}
}
@@ -149,22 +149,22 @@ class BCELFactory extends EmptyVisitor {
final short opcode = ((Instruction) i).getOpcode();
int dim = 1;
switch (opcode) {
- case Const.NEW:
- printWriter.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName() + "\"));");
- break;
- case Const.MULTIANEWARRAY:
- dim = ((MULTIANEWARRAY) i).getDimensions();
- //$FALL-THROUGH$
- case Const.NEWARRAY:
- if (type instanceof ArrayType) {
- type = ((ArrayType) type).getBasicType();
- }
- //$FALL-THROUGH$
- case Const.ANEWARRAY:
- printWriter.println("il.append(_factory.createNewArray(" + BCELifier.printType(type) + ", (short) " + dim + "));");
- break;
- default:
- throw new IllegalArgumentException("Unhandled opcode: " + opcode);
+ case Const.NEW:
+ printWriter.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName() + "\"));");
+ break;
+ case Const.MULTIANEWARRAY:
+ dim = ((MULTIANEWARRAY) i).getDimensions();
+ //$FALL-THROUGH$
+ case Const.NEWARRAY:
+ if (type instanceof ArrayType) {
+ type = ((ArrayType) type).getBasicType();
+ }
+ //$FALL-THROUGH$
+ case Const.ANEWARRAY:
+ printWriter.println("il.append(_factory.createNewArray(" + BCELifier.printType(type) + ", (short) " + dim + "));");
+ break;
+ default:
+ throw new IllegalArgumentException("Unhandled opcode: " + opcode);
}
}
@@ -211,7 +211,7 @@ class BCELFactory extends EmptyVisitor {
target = "null";
}
printWriter.println(" BranchInstruction " + name + " = _factory.createBranchInstruction(" + CONSTANT_PREFIX
- + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target + ");");
+ + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target + ");");
}
if (bh.hasTargeters()) {
printWriter.println(" ih_" + pos + " = il.append(" + name + ");");
@@ -238,7 +238,7 @@ class BCELFactory extends EmptyVisitor {
final String fieldName = i.getFieldName(constantPoolGen);
final Type type = i.getFieldType(constantPoolGen);
printWriter.println("il.append(_factory.createFieldAccess(\"" + className + "\", \"" + fieldName + "\", " + BCELifier.printType(type) + ", "
- + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));");
+ + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));");
}
@Override
@@ -264,7 +264,7 @@ class BCELFactory extends EmptyVisitor {
final Type type = i.getReturnType(constantPoolGen);
final Type[] argTypes = i.getArgumentTypes(constantPoolGen);
printWriter.println("il.append(_factory.createInvoke(\"" + className + "\", \"" + methodName + "\", " + BCELifier.printType(type) + ", "
- + BCELifier.printArgumentTypes(argTypes) + ", " + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));");
+ + BCELifier.printArgumentTypes(argTypes) + ", " + CONSTANT_PREFIX + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));");
}
@Override
diff --git a/src/main/java/haidnor/jvm/bcel/util/BCELifier.java b/src/main/java/haidnor/jvm/bcel/util/BCELifier.java
index 6cf55b5..ab593a3 100644
--- a/src/main/java/haidnor/jvm/bcel/util/BCELifier.java
+++ b/src/main/java/haidnor/jvm/bcel/util/BCELifier.java
@@ -39,17 +39,25 @@ import java.util.Locale;
*/
public class BCELifier extends EmptyVisitor {
- /**
- * Enum corresponding to flag source.
- */
- public enum FLAGS {
- UNKNOWN, CLASS, METHOD,
- }
-
// The base package name for imports; assumes Const is at the top level
// N.B we use the class so renames will be detected by the compiler/IDE
private static final String BASE_PACKAGE = Const.class.getPackage().getName();
private static final String CONSTANT_PREFIX = Const.class.getSimpleName() + ".";
+ private final JavaClass clazz;
+ private final PrintWriter printWriter;
+ private final ConstantPoolGen constantPoolGen;
+
+ /**
+ * Constructs a new instance.
+ *
+ * @param clazz Java class to "decompile".
+ * @param out where to print the Java program in UTF-8.
+ */
+ public BCELifier(final JavaClass clazz, final OutputStream out) {
+ this.clazz = clazz;
+ this.printWriter = new PrintWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8), false);
+ this.constantPoolGen = new ConstantPoolGen(this.clazz.getConstantPool());
+ }
// Needs to be accessible from unit test code
static JavaClass getJavaClass(final String name) throws ClassNotFoundException, IOException {
@@ -94,7 +102,7 @@ public class BCELifier extends EmptyVisitor {
/**
* Return a string with the flag settings
*
- * @param flags the flags field to interpret
+ * @param flags the flags field to interpret
* @param location the item type
* @return the formatted string
* @since 6.0 made public
@@ -150,24 +158,6 @@ public class BCELifier extends EmptyVisitor {
return printType(type.getSignature());
}
- private final JavaClass clazz;
-
- private final PrintWriter printWriter;
-
- private final ConstantPoolGen constantPoolGen;
-
- /**
- * Constructs a new instance.
- *
- * @param clazz Java class to "decompile".
- * @param out where to print the Java program in UTF-8.
- */
- public BCELifier(final JavaClass clazz, final OutputStream out) {
- this.clazz = clazz;
- this.printWriter = new PrintWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8), false);
- this.constantPoolGen = new ConstantPoolGen(this.clazz.getConstantPool());
- }
-
private void printCreate() {
printWriter.println(" public void create(OutputStream out) throws IOException {");
final JavaField[] fields = clazz.getFields();
@@ -203,7 +193,7 @@ public class BCELifier extends EmptyVisitor {
public void visitField(final JavaField field) {
printWriter.println();
printWriter.println(
- " field = new FieldGen(" + printFlags(field.getAccessFlags()) + ", " + printType(field.getSignature()) + ", \"" + field.getName() + "\", _cp);");
+ " field = new FieldGen(" + printFlags(field.getAccessFlags()) + ", " + printType(field.getSignature()) + ", \"" + field.getName() + "\", _cp);");
final ConstantValue cv = field.getConstantValue();
if (cv != null) {
printWriter.print(" field.setInitValue(");
@@ -254,7 +244,7 @@ public class BCELifier extends EmptyVisitor {
printWriter.println();
printWriter.println(" public " + className + "Creator() {");
printWriter.println(" _cg = new ClassGen(\"" + (packageName.isEmpty() ? className : packageName + "." + className) + "\", \"" + superName
- + "\", " + "\"" + clazz.getSourceFileName() + "\", " + printFlags(clazz.getAccessFlags(), FLAGS.CLASS) + ", " + "new String[] { " + inter + " });");
+ + "\", " + "\"" + clazz.getSourceFileName() + "\", " + printFlags(clazz.getAccessFlags(), FLAGS.CLASS) + ", " + "new String[] { " + inter + " });");
printWriter.println(" _cg.setMajor(" + clazz.getMajor() + ");");
printWriter.println(" _cg.setMinor(" + clazz.getMinor() + ");");
printWriter.println();
@@ -289,8 +279,8 @@ public class BCELifier extends EmptyVisitor {
final MethodGen mg = new MethodGen(method, clazz.getClassName(), constantPoolGen);
printWriter.println(" InstructionList il = new InstructionList();");
printWriter.println(" MethodGen method = new MethodGen(" + printFlags(method.getAccessFlags(), FLAGS.METHOD) + ", " + printType(mg.getReturnType())
- + ", " + printArgumentTypes(mg.getArgumentTypes()) + ", " + "new String[] { " + Utility.printArray(mg.getArgumentNames(), false, true) + " }, \""
- + method.getName() + "\", \"" + clazz.getClassName() + "\", il, _cp);");
+ + ", " + printArgumentTypes(mg.getArgumentTypes()) + ", " + "new String[] { " + Utility.printArray(mg.getArgumentNames(), false, true) + " }, \""
+ + method.getName() + "\", \"" + clazz.getClassName() + "\", il, _cp);");
final ExceptionTable exceptionTable = method.getExceptionTable();
if (exceptionTable != null) {
final String[] exceptionNames = exceptionTable.getExceptionNames();
@@ -308,4 +298,11 @@ public class BCELifier extends EmptyVisitor {
printWriter.println(" _cg.addMethod(method.getMethod());");
printWriter.println(" il.dispose();");
}
+
+ /**
+ * Enum corresponding to flag source.
+ */
+ public enum FLAGS {
+ UNKNOWN, CLASS, METHOD,
+ }
}
diff --git a/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java b/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java
index f91d394..d170435 100644
--- a/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java
+++ b/src/main/java/haidnor/jvm/bcel/util/ByteSequence.java
@@ -25,6 +25,21 @@ import java.io.DataInputStream;
*/
public final class ByteSequence extends DataInputStream {
+ private final ByteArrayStream byteStream;
+
+ public ByteSequence(final byte[] bytes) {
+ super(new ByteArrayStream(bytes));
+ byteStream = (ByteArrayStream) in;
+ }
+
+ public int getIndex() {
+ return byteStream.getPosition();
+ }
+
+ void unreadByte() {
+ byteStream.unreadByte();
+ }
+
private static final class ByteArrayStream extends ByteArrayInputStream {
ByteArrayStream(final byte[] bytes) {
@@ -42,19 +57,4 @@ public final class ByteSequence extends DataInputStream {
}
}
}
-
- private final ByteArrayStream byteStream;
-
- public ByteSequence(final byte[] bytes) {
- super(new ByteArrayStream(bytes));
- byteStream = (ByteArrayStream) in;
- }
-
- public int getIndex() {
- return byteStream.getPosition();
- }
-
- void unreadByte() {
- byteStream.unreadByte();
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/util/ClassPath.java b/src/main/java/haidnor/jvm/bcel/util/ClassPath.java
index 31b1bb9..3287891 100644
--- a/src/main/java/haidnor/jvm/bcel/util/ClassPath.java
+++ b/src/main/java/haidnor/jvm/bcel/util/ClassPath.java
@@ -35,6 +35,397 @@ import java.util.zip.ZipFile;
*/
public class ClassPath implements Closeable {
+ private static final FilenameFilter ARCHIVE_FILTER = (dir, name) -> {
+ name = name.toLowerCase(Locale.ENGLISH);
+ return name.endsWith(".zip") || name.endsWith(".jar");
+ };
+ private static final FilenameFilter MODULES_FILTER = (dir, name) -> {
+ name = name.toLowerCase(Locale.ENGLISH);
+ return name.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION);
+ };
+ public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath(getClassPath());
+ private final String classPathString;
+ private final ClassPath parent;
+ private final List paths;
+
+ /**
+ * Search for classes in CLASSPATH.
+ *
+ * @deprecated Use SYSTEM_CLASS_PATH constant
+ */
+ @Deprecated
+ public ClassPath() {
+ this(getClassPath());
+ }
+
+ @SuppressWarnings("resource")
+ public ClassPath(final ClassPath parent, final String classPathString) {
+ this.parent = parent;
+ this.classPathString = Objects.requireNonNull(classPathString, "classPathString");
+ this.paths = new ArrayList<>();
+ for (final StringTokenizer tokenizer = new StringTokenizer(classPathString, File.pathSeparator); tokenizer.hasMoreTokens(); ) {
+ final String path = tokenizer.nextToken();
+ if (!path.isEmpty()) {
+ final File file = new File(path);
+ try {
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ paths.add(new Dir(path));
+ } else if (path.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION)) {
+ paths.add(new Module(new ZipFile(file)));
+ } else if (path.endsWith(ModularRuntimeImage.MODULES_PATH)) {
+ paths.add(new JrtModules(ModularRuntimeImage.MODULES_PATH));
+ } else {
+ paths.add(new Jar(new ZipFile(file)));
+ }
+ }
+ } catch (final IOException e) {
+ if (path.endsWith(".zip") || path.endsWith(".jar")) {
+ System.err.println("CLASSPATH component " + file + ": " + e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Search for classes in given path.
+ *
+ * @param classPath
+ */
+ public ClassPath(final String classPath) {
+ this(null, classPath);
+ }
+
+ private static void addJdkModules(final String javaHome, final List list) {
+ String modulesPath = System.getProperty("java.modules.path");
+ if (modulesPath == null || modulesPath.trim().isEmpty()) {
+ // Default to looking in JAVA_HOME/jmods
+ modulesPath = javaHome + File.separator + "jmods";
+ }
+ final File modulesDir = new File(modulesPath);
+ if (modulesDir.exists()) {
+ final String[] modules = modulesDir.list(MODULES_FILTER);
+ if (modules != null) {
+ for (final String module : modules) {
+ list.add(modulesDir.getPath() + File.separatorChar + module);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks for class path components in the following properties: "java.class.path", "sun.boot.class.path",
+ * "java.ext.dirs"
+ *
+ * @return class path as used by default by BCEL
+ */
+ // @since 6.0 no longer final
+ public static String getClassPath() {
+ final String classPathProp = System.getProperty("java.class.path");
+ final String bootClassPathProp = System.getProperty("sun.boot.class.path");
+ final String extDirs = System.getProperty("java.ext.dirs");
+ // System.out.println("java.version = " + System.getProperty("java.version"));
+ // System.out.println("java.class.path = " + classPathProp);
+ // System.out.println("sun.boot.class.path=" + bootClassPathProp);
+ // System.out.println("java.ext.dirs=" + extDirs);
+ final String javaHome = System.getProperty("java.home");
+ final List list = new ArrayList<>();
+
+ // Starting in JRE 9, .class files are in the modules directory. Add them to the path.
+ final Path modulesPath = Paths.get(javaHome).resolve("lib/modules");
+ if (Files.exists(modulesPath) && Files.isRegularFile(modulesPath)) {
+ list.add(modulesPath.toAbsolutePath().toString());
+ }
+ // Starting in JDK 9, .class files are in the jmods directory. Add them to the path.
+ addJdkModules(javaHome, list);
+
+ getPathComponents(classPathProp, list);
+ getPathComponents(bootClassPathProp, list);
+ final List dirs = new ArrayList<>();
+ getPathComponents(extDirs, dirs);
+ for (final String d : dirs) {
+ final File extDir = new File(d);
+ final String[] extensions = extDir.list(ARCHIVE_FILTER);
+ if (extensions != null) {
+ for (final String extension : extensions) {
+ list.add(extDir.getPath() + File.separatorChar + extension);
+ }
+ }
+ }
+
+ return list.stream().collect(Collectors.joining(File.pathSeparator));
+ }
+
+ private static void getPathComponents(final String path, final List list) {
+ if (path != null) {
+ final StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator);
+ while (tokenizer.hasMoreTokens()) {
+ final String name = tokenizer.nextToken();
+ final File file = new File(name);
+ if (file.exists()) {
+ list.add(name);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ for (final AbstractPathEntry path : paths) {
+ path.close();
+ }
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ClassPath other = (ClassPath) obj;
+ return Objects.equals(classPathString, other.classPathString);
+ }
+
+ /**
+ * @param name fully qualified file name, e.g. java/lang/String
+ * @return byte array for class
+ * @throws IOException if an I/O error occurs.
+ */
+ public byte[] getBytes(final String name) throws IOException {
+ return getBytes(name, JavaClass.EXTENSION);
+ }
+
+ /**
+ * @param name fully qualified file name, e.g. java/lang/String
+ * @param suffix file name ends with suffix, e.g. .java
+ * @return byte array for file on class path
+ * @throws IOException if an I/O error occurs.
+ */
+ public byte[] getBytes(final String name, final String suffix) throws IOException {
+ DataInputStream dis = null;
+ try (InputStream inputStream = getInputStream(name, suffix)) {
+ if (inputStream == null) {
+ throw new IOException("Couldn't find: " + name + suffix);
+ }
+ dis = new DataInputStream(inputStream);
+ final byte[] bytes = new byte[inputStream.available()];
+ dis.readFully(bytes);
+ return bytes;
+ } finally {
+ if (dis != null) {
+ dis.close();
+ }
+ }
+ }
+
+ /**
+ * @param name fully qualified class name, e.g. java.lang.String
+ * @return input stream for class
+ * @throws IOException if an I/O error occurs.
+ */
+ public ClassFile getClassFile(final String name) throws IOException {
+ return getClassFile(name, JavaClass.EXTENSION);
+ }
+
+ /**
+ * @param name fully qualified file name, e.g. java/lang/String
+ * @param suffix file name ends with suff, e.g. .java
+ * @return class file for the java class
+ * @throws IOException if an I/O error occurs.
+ */
+ public ClassFile getClassFile(final String name, final String suffix) throws IOException {
+ ClassFile cf = null;
+
+ if (parent != null) {
+ cf = parent.getClassFileInternal(name, suffix);
+ }
+
+ if (cf == null) {
+ cf = getClassFileInternal(name, suffix);
+ }
+
+ if (cf != null) {
+ return cf;
+ }
+
+ throw new IOException("Couldn't find: " + name + suffix);
+ }
+
+ private ClassFile getClassFileInternal(final String name, final String suffix) {
+ for (final AbstractPathEntry path : paths) {
+ final ClassFile cf = path.getClassFile(name, suffix);
+ if (cf != null) {
+ return cf;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets an InputStream.
+ *
+ * The caller is responsible for closing the InputStream.
+ *
+ *
+ * @param name fully qualified class name, e.g. java.lang.String
+ * @return input stream for class
+ * @throws IOException if an I/O error occurs.
+ */
+ public InputStream getInputStream(final String name) throws IOException {
+ return getInputStream(Utility.packageToPath(name), JavaClass.EXTENSION);
+ }
+
+ /**
+ * Gets an InputStream for a class or resource on the classpath.
+ *
+ * The caller is responsible for closing the InputStream.
+ *
+ *
+ * @param name fully qualified file name, e.g. java/lang/String
+ * @param suffix file name ends with suff, e.g. .java
+ * @return input stream for file on class path
+ * @throws IOException if an I/O error occurs.
+ */
+ public InputStream getInputStream(final String name, final String suffix) throws IOException {
+ try {
+ final java.lang.ClassLoader classLoader = getClass().getClassLoader();
+ @SuppressWarnings("resource") // closed by caller
+ final InputStream inputStream = classLoader == null ? null : classLoader.getResourceAsStream(name + suffix);
+ if (inputStream != null) {
+ return inputStream;
+ }
+ } catch (final Exception ignored) {
+ // ignored
+ }
+ return getClassFile(name, suffix).getInputStream();
+ }
+
+ /**
+ * @param name name of file to search for, e.g. java/lang/String.java
+ * @return full (canonical) path for file
+ * @throws IOException if an I/O error occurs.
+ */
+ public String getPath(String name) throws IOException {
+ final int index = name.lastIndexOf('.');
+ String suffix = "";
+ if (index > 0) {
+ suffix = name.substring(index);
+ name = name.substring(0, index);
+ }
+ return getPath(name, suffix);
+ }
+
+ /**
+ * @param name name of file to search for, e.g. java/lang/String
+ * @param suffix file name suffix, e.g. .java
+ * @return full (canonical) path for file, if it exists
+ * @throws IOException if an I/O error occurs.
+ */
+ public String getPath(final String name, final String suffix) throws IOException {
+ return getClassFile(name, suffix).getPath();
+ }
+
+ /**
+ * @param name fully qualified resource name, e.g. java/lang/String.class
+ * @return URL supplying the resource, or null if no resource with that name.
+ * @since 6.0
+ */
+ public URL getResource(final String name) {
+ for (final AbstractPathEntry path : paths) {
+ URL url;
+ if ((url = path.getResource(name)) != null) {
+ return url;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param name fully qualified resource name, e.g. java/lang/String.class
+ * @return InputStream supplying the resource, or null if no resource with that name.
+ * @since 6.0
+ */
+ public InputStream getResourceAsStream(final String name) {
+ for (final AbstractPathEntry path : paths) {
+ InputStream is;
+ if ((is = path.getResourceAsStream(name)) != null) {
+ return is;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param name fully qualified resource name, e.g. java/lang/String.class
+ * @return An Enumeration of URLs supplying the resource, or an empty Enumeration if no resource with that name.
+ * @since 6.0
+ */
+ public Enumeration getResources(final String name) {
+ final Vector results = new Vector<>();
+ for (final AbstractPathEntry path : paths) {
+ URL url;
+ if ((url = path.getResource(name)) != null) {
+ results.add(url);
+ }
+ }
+ return results.elements();
+ }
+
+ @Override
+ public int hashCode() {
+ return classPathString.hashCode();
+ }
+
+ /**
+ * @return used class path string
+ */
+ @Override
+ public String toString() {
+ if (parent != null) {
+ return parent + File.pathSeparator + classPathString;
+ }
+ return classPathString;
+ }
+
+ /**
+ * Contains information about file/ZIP entry of the Java class.
+ */
+ public interface ClassFile {
+
+ /**
+ * @return base path of found class, i.e. class is contained relative to that path, which may either denote a directory,
+ * or zip file
+ */
+ String getBase();
+
+ /**
+ * @return input stream for class file.
+ * @throws IOException if an I/O error occurs.
+ */
+ InputStream getInputStream() throws IOException;
+
+ /**
+ * @return canonical path to class file.
+ */
+ String getPath();
+
+ /**
+ * @return size of class file.
+ */
+ long getSize();
+
+ /**
+ * @return modification time of class file.
+ */
+ long getTime();
+ }
+
private abstract static class AbstractPathEntry implements Closeable {
abstract ClassFile getClassFile(String name, String suffix);
@@ -126,39 +517,6 @@ public class ClassPath implements Closeable {
}
- /**
- * Contains information about file/ZIP entry of the Java class.
- */
- public interface ClassFile {
-
- /**
- * @return base path of found class, i.e. class is contained relative to that path, which may either denote a directory,
- * or zip file
- */
- String getBase();
-
- /**
- * @return input stream for class file.
- * @throws IOException if an I/O error occurs.
- */
- InputStream getInputStream() throws IOException;
-
- /**
- * @return canonical path to class file.
- */
- String getPath();
-
- /**
- * @return size of class file.
- */
- long getSize();
-
- /**
- * @return modification time of class file.
- */
- long getTime();
- }
-
private static class Dir extends AbstractPathEntry {
private final String dir;
@@ -415,367 +773,4 @@ public class ClassPath implements Closeable {
}
}
-
- private static final FilenameFilter ARCHIVE_FILTER = (dir, name) -> {
- name = name.toLowerCase(Locale.ENGLISH);
- return name.endsWith(".zip") || name.endsWith(".jar");
- };
-
- private static final FilenameFilter MODULES_FILTER = (dir, name) -> {
- name = name.toLowerCase(Locale.ENGLISH);
- return name.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION);
- };
-
- public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath(getClassPath());
-
- private static void addJdkModules(final String javaHome, final List list) {
- String modulesPath = System.getProperty("java.modules.path");
- if (modulesPath == null || modulesPath.trim().isEmpty()) {
- // Default to looking in JAVA_HOME/jmods
- modulesPath = javaHome + File.separator + "jmods";
- }
- final File modulesDir = new File(modulesPath);
- if (modulesDir.exists()) {
- final String[] modules = modulesDir.list(MODULES_FILTER);
- if (modules != null) {
- for (final String module : modules) {
- list.add(modulesDir.getPath() + File.separatorChar + module);
- }
- }
- }
- }
-
- /**
- * Checks for class path components in the following properties: "java.class.path", "sun.boot.class.path",
- * "java.ext.dirs"
- *
- * @return class path as used by default by BCEL
- */
- // @since 6.0 no longer final
- public static String getClassPath() {
- final String classPathProp = System.getProperty("java.class.path");
- final String bootClassPathProp = System.getProperty("sun.boot.class.path");
- final String extDirs = System.getProperty("java.ext.dirs");
- // System.out.println("java.version = " + System.getProperty("java.version"));
- // System.out.println("java.class.path = " + classPathProp);
- // System.out.println("sun.boot.class.path=" + bootClassPathProp);
- // System.out.println("java.ext.dirs=" + extDirs);
- final String javaHome = System.getProperty("java.home");
- final List list = new ArrayList<>();
-
- // Starting in JRE 9, .class files are in the modules directory. Add them to the path.
- final Path modulesPath = Paths.get(javaHome).resolve("lib/modules");
- if (Files.exists(modulesPath) && Files.isRegularFile(modulesPath)) {
- list.add(modulesPath.toAbsolutePath().toString());
- }
- // Starting in JDK 9, .class files are in the jmods directory. Add them to the path.
- addJdkModules(javaHome, list);
-
- getPathComponents(classPathProp, list);
- getPathComponents(bootClassPathProp, list);
- final List dirs = new ArrayList<>();
- getPathComponents(extDirs, dirs);
- for (final String d : dirs) {
- final File extDir = new File(d);
- final String[] extensions = extDir.list(ARCHIVE_FILTER);
- if (extensions != null) {
- for (final String extension : extensions) {
- list.add(extDir.getPath() + File.separatorChar + extension);
- }
- }
- }
-
- return list.stream().collect(Collectors.joining(File.pathSeparator));
- }
-
- private static void getPathComponents(final String path, final List list) {
- if (path != null) {
- final StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator);
- while (tokenizer.hasMoreTokens()) {
- final String name = tokenizer.nextToken();
- final File file = new File(name);
- if (file.exists()) {
- list.add(name);
- }
- }
- }
- }
-
- private final String classPathString;
-
- private final ClassPath parent;
-
- private final List paths;
-
- /**
- * Search for classes in CLASSPATH.
- *
- * @deprecated Use SYSTEM_CLASS_PATH constant
- */
- @Deprecated
- public ClassPath() {
- this(getClassPath());
- }
-
- @SuppressWarnings("resource")
- public ClassPath(final ClassPath parent, final String classPathString) {
- this.parent = parent;
- this.classPathString = Objects.requireNonNull(classPathString, "classPathString");
- this.paths = new ArrayList<>();
- for (final StringTokenizer tokenizer = new StringTokenizer(classPathString, File.pathSeparator); tokenizer.hasMoreTokens();) {
- final String path = tokenizer.nextToken();
- if (!path.isEmpty()) {
- final File file = new File(path);
- try {
- if (file.exists()) {
- if (file.isDirectory()) {
- paths.add(new Dir(path));
- } else if (path.endsWith(haidnor.jvm.bcel.classfile.Module.EXTENSION)) {
- paths.add(new Module(new ZipFile(file)));
- } else if (path.endsWith(ModularRuntimeImage.MODULES_PATH)) {
- paths.add(new JrtModules(ModularRuntimeImage.MODULES_PATH));
- } else {
- paths.add(new Jar(new ZipFile(file)));
- }
- }
- } catch (final IOException e) {
- if (path.endsWith(".zip") || path.endsWith(".jar")) {
- System.err.println("CLASSPATH component " + file + ": " + e);
- }
- }
- }
- }
- }
-
- /**
- * Search for classes in given path.
- *
- * @param classPath
- */
- public ClassPath(final String classPath) {
- this(null, classPath);
- }
-
- @Override
- public void close() throws IOException {
- for (final AbstractPathEntry path : paths) {
- path.close();
- }
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final ClassPath other = (ClassPath) obj;
- return Objects.equals(classPathString, other.classPathString);
- }
-
- /**
- * @param name fully qualified file name, e.g. java/lang/String
- * @return byte array for class
- * @throws IOException if an I/O error occurs.
- */
- public byte[] getBytes(final String name) throws IOException {
- return getBytes(name, JavaClass.EXTENSION);
- }
-
- /**
- * @param name fully qualified file name, e.g. java/lang/String
- * @param suffix file name ends with suffix, e.g. .java
- * @return byte array for file on class path
- * @throws IOException if an I/O error occurs.
- */
- public byte[] getBytes(final String name, final String suffix) throws IOException {
- DataInputStream dis = null;
- try (InputStream inputStream = getInputStream(name, suffix)) {
- if (inputStream == null) {
- throw new IOException("Couldn't find: " + name + suffix);
- }
- dis = new DataInputStream(inputStream);
- final byte[] bytes = new byte[inputStream.available()];
- dis.readFully(bytes);
- return bytes;
- } finally {
- if (dis != null) {
- dis.close();
- }
- }
- }
-
- /**
- * @param name fully qualified class name, e.g. java.lang.String
- * @return input stream for class
- * @throws IOException if an I/O error occurs.
- */
- public ClassFile getClassFile(final String name) throws IOException {
- return getClassFile(name, JavaClass.EXTENSION);
- }
-
- /**
- * @param name fully qualified file name, e.g. java/lang/String
- * @param suffix file name ends with suff, e.g. .java
- * @return class file for the java class
- * @throws IOException if an I/O error occurs.
- */
- public ClassFile getClassFile(final String name, final String suffix) throws IOException {
- ClassFile cf = null;
-
- if (parent != null) {
- cf = parent.getClassFileInternal(name, suffix);
- }
-
- if (cf == null) {
- cf = getClassFileInternal(name, suffix);
- }
-
- if (cf != null) {
- return cf;
- }
-
- throw new IOException("Couldn't find: " + name + suffix);
- }
-
- private ClassFile getClassFileInternal(final String name, final String suffix) {
- for (final AbstractPathEntry path : paths) {
- final ClassFile cf = path.getClassFile(name, suffix);
- if (cf != null) {
- return cf;
- }
- }
- return null;
- }
-
- /**
- * Gets an InputStream.
- *
- * The caller is responsible for closing the InputStream.
- *
- * @param name fully qualified class name, e.g. java.lang.String
- * @return input stream for class
- * @throws IOException if an I/O error occurs.
- */
- public InputStream getInputStream(final String name) throws IOException {
- return getInputStream(Utility.packageToPath(name), JavaClass.EXTENSION);
- }
-
- /**
- * Gets an InputStream for a class or resource on the classpath.
- *
- * The caller is responsible for closing the InputStream.
- *
- *
- * @param name fully qualified file name, e.g. java/lang/String
- * @param suffix file name ends with suff, e.g. .java
- * @return input stream for file on class path
- * @throws IOException if an I/O error occurs.
- */
- public InputStream getInputStream(final String name, final String suffix) throws IOException {
- try {
- final java.lang.ClassLoader classLoader = getClass().getClassLoader();
- @SuppressWarnings("resource") // closed by caller
- final
- InputStream inputStream = classLoader == null ? null : classLoader.getResourceAsStream(name + suffix);
- if (inputStream != null) {
- return inputStream;
- }
- } catch (final Exception ignored) {
- // ignored
- }
- return getClassFile(name, suffix).getInputStream();
- }
-
- /**
- * @param name name of file to search for, e.g. java/lang/String.java
- * @return full (canonical) path for file
- * @throws IOException if an I/O error occurs.
- */
- public String getPath(String name) throws IOException {
- final int index = name.lastIndexOf('.');
- String suffix = "";
- if (index > 0) {
- suffix = name.substring(index);
- name = name.substring(0, index);
- }
- return getPath(name, suffix);
- }
-
- /**
- * @param name name of file to search for, e.g. java/lang/String
- * @param suffix file name suffix, e.g. .java
- * @return full (canonical) path for file, if it exists
- * @throws IOException if an I/O error occurs.
- */
- public String getPath(final String name, final String suffix) throws IOException {
- return getClassFile(name, suffix).getPath();
- }
-
- /**
- * @param name fully qualified resource name, e.g. java/lang/String.class
- * @return URL supplying the resource, or null if no resource with that name.
- * @since 6.0
- */
- public URL getResource(final String name) {
- for (final AbstractPathEntry path : paths) {
- URL url;
- if ((url = path.getResource(name)) != null) {
- return url;
- }
- }
- return null;
- }
-
- /**
- * @param name fully qualified resource name, e.g. java/lang/String.class
- * @return InputStream supplying the resource, or null if no resource with that name.
- * @since 6.0
- */
- public InputStream getResourceAsStream(final String name) {
- for (final AbstractPathEntry path : paths) {
- InputStream is;
- if ((is = path.getResourceAsStream(name)) != null) {
- return is;
- }
- }
- return null;
- }
-
- /**
- * @param name fully qualified resource name, e.g. java/lang/String.class
- * @return An Enumeration of URLs supplying the resource, or an empty Enumeration if no resource with that name.
- * @since 6.0
- */
- public Enumeration getResources(final String name) {
- final Vector results = new Vector<>();
- for (final AbstractPathEntry path : paths) {
- URL url;
- if ((url = path.getResource(name)) != null) {
- results.add(url);
- }
- }
- return results.elements();
- }
-
- @Override
- public int hashCode() {
- return classPathString.hashCode();
- }
-
- /**
- * @return used class path string
- */
- @Override
- public String toString() {
- if (parent != null) {
- return parent + File.pathSeparator + classPathString;
- }
- return classPathString;
- }
}
diff --git a/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java b/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java
index 5040160..ec9160f 100644
--- a/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java
+++ b/src/main/java/haidnor/jvm/bcel/util/JavaWrapper.java
@@ -43,6 +43,16 @@ import java.lang.reflect.Modifier;
*/
public class JavaWrapper {
+ private final java.lang.ClassLoader loader;
+
+ public JavaWrapper() {
+ this(getClassLoader());
+ }
+
+ public JavaWrapper(final java.lang.ClassLoader loader) {
+ this.loader = loader;
+ }
+
private static java.lang.ClassLoader getClassLoader() {
final String s = System.getProperty("bcel.classloader");
if (StringUtils.isEmpty(s)) {
@@ -72,21 +82,11 @@ public class JavaWrapper {
new JavaWrapper().runMain(className, newArgv);
}
- private final java.lang.ClassLoader loader;
-
- public JavaWrapper() {
- this(getClassLoader());
- }
-
- public JavaWrapper(final java.lang.ClassLoader loader) {
- this.loader = loader;
- }
-
/**
* Runs the main method of the given class with the arguments passed in argv
*
* @param className the fully qualified class name
- * @param argv the arguments just as you would pass them directly
+ * @param argv the arguments just as you would pass them directly
* @throws ClassNotFoundException if {@code className} can't be found.
*/
public void runMain(final String className, final String[] argv) throws ClassNotFoundException {
diff --git a/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java b/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java
index 38dc24e..fde7d58 100644
--- a/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java
+++ b/src/main/java/haidnor/jvm/bcel/util/ModularRuntimeImage.java
@@ -53,14 +53,13 @@ public class ModularRuntimeImage implements Closeable {
* Constructs an instance using the JRT file system implementation from a specific Java Home.
*
* @param javaHome Path to a Java 9 or greater home.
- *
* @throws IOException an I/O error occurs accessing the file system
*/
public ModularRuntimeImage(final String javaHome) throws IOException {
final Map emptyMap = Collections.emptyMap();
final Path jrePath = Paths.get(javaHome);
final Path jrtFsPath = jrePath.resolve("lib").resolve("jrt-fs.jar");
- this.classLoader = URLClassLoader.newInstance(new URL[] {jrtFsPath.toUri().toURL()});
+ this.classLoader = URLClassLoader.newInstance(new URL[]{jrtFsPath.toUri().toURL()});
this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), emptyMap, classLoader);
}
diff --git a/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java b/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java
index a54dfba..56aa757 100644
--- a/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java
+++ b/src/main/java/haidnor/jvm/bcel/util/SyntheticRepository.java
@@ -36,6 +36,10 @@ public class SyntheticRepository extends MemorySensitiveClassPathRepository {
private static final Map MAP = new HashMap<>(); // CLASSPATH X REPOSITORY
+ private SyntheticRepository(final ClassPath path) {
+ super(path);
+ }
+
public static SyntheticRepository getInstance() {
return getInstance(ClassPath.SYSTEM_CLASS_PATH);
}
@@ -43,8 +47,4 @@ public class SyntheticRepository extends MemorySensitiveClassPathRepository {
public static SyntheticRepository getInstance(final ClassPath classPath) {
return MAP.computeIfAbsent(classPath, SyntheticRepository::new);
}
-
- private SyntheticRepository(final ClassPath path) {
- super(path);
- }
}
diff --git a/src/main/java/haidnor/jvm/classloader/JVMClassLoader.java b/src/main/java/haidnor/jvm/classloader/JVMClassLoader.java
new file mode 100644
index 0000000..46a7ace
--- /dev/null
+++ b/src/main/java/haidnor/jvm/classloader/JVMClassLoader.java
@@ -0,0 +1,108 @@
+package haidnor.jvm.classloader;
+
+import haidnor.jvm.bcel.classfile.ClassParser;
+import haidnor.jvm.bcel.classfile.JavaClass;
+import haidnor.jvm.bcel.classfile.JavaMethod;
+import haidnor.jvm.rtda.Metaspace;
+import lombok.SneakyThrows;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class JVMClassLoader {
+
+ public final static String JAVA_HOME;
+ /**
+ * JDK java.base.jmod path
+ */
+ public final static String javaBaseJmodPath;
+
+ static {
+ JAVA_HOME = System.getenv("JAVA_HOME");
+ javaBaseJmodPath = JAVA_HOME + "/jmods/java.base.jmod";
+ }
+
+ public final String name;
+ public JarFile jarFile = null;
+
+ public JVMClassLoader(String name) {
+ this.name = name;
+ }
+
+ public JVMClassLoader(JarFile jarFile, String name) {
+ this.name = name;
+ this.jarFile = jarFile;
+ }
+
+ /**
+ * @param classPath 类路径,例如 haidnor/jvm/classloader/ClassLoader
+ */
+ @SneakyThrows
+ public JavaClass loadWithClassPath(String classPath) {
+ ClassParser classParser = null;
+ if (classPath.startsWith("java/")) {
+ classParser = new ClassParser(javaBaseJmodPath, "classes/" + classPath + ".class");
+ } else if (jarFile != null) {
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
+ String className = entry.getName().substring(0, entry.getName().length() - 6);
+ if (className.equals(classPath)) {
+ InputStream inputStream = jarFile.getInputStream(entry);
+ classParser = new ClassParser(inputStream, null);
+ }
+ }
+ }
+ } else {
+ URL resource = this.getClass().getResource("/");
+ String fileName = resource.getPath() + classPath + ".class";
+ classParser = new ClassParser(fileName);
+ }
+ return load(classParser);
+ }
+
+ @SneakyThrows
+ public JavaClass loadWithJar(JarFile jarFile, JarEntry entry) {
+ InputStream inputStream = jarFile.getInputStream(entry);
+ ClassParser classParser = new ClassParser(inputStream, null);
+ return load(classParser);
+ }
+
+ public JavaClass loadWithAbsolutePath(String absolutePath) {
+ ClassParser classParser = new ClassParser(absolutePath);
+ return load(classParser);
+ }
+
+ @SneakyThrows
+ private JavaClass load(ClassParser classParser) {
+ JavaClass javaClass = classParser.parse();
+ javaClass.setJVMClassLoader(this);
+ register(javaClass);
+ return javaClass;
+ }
+
+ @SneakyThrows
+ private void register(JavaClass javaClass) {
+ JavaClass superJavaClass = javaClass.getSuperClass();
+ if (superJavaClass != null) {
+ register(superJavaClass);
+ }
+ Metaspace.registerJavaClass(javaClass);
+
+ if (javaClass.getClassName().startsWith("java.")) {
+ return;
+ }
+ for (JavaMethod method : javaClass.getMethods()) {
+ if (method.toString().equals("static void ()")) {
+ // JavaExecutionEngine.callMethod(null, method);
+ break;
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java
new file mode 100644
index 0000000..c1d1979
--- /dev/null
+++ b/src/main/java/haidnor/jvm/core/JavaExecutionEngine.java
@@ -0,0 +1,168 @@
+package haidnor.jvm.core;
+
+
+import haidnor.jvm.bcel.Const;
+import haidnor.jvm.bcel.classfile.*;
+import haidnor.jvm.instruction.Instruction;
+import haidnor.jvm.instruction.InstructionFactory;
+import haidnor.jvm.instruction.ReturnableInstruction;
+import haidnor.jvm.runtime.Frame;
+import haidnor.jvm.runtime.JVMThread;
+import haidnor.jvm.runtime.StackValue;
+import haidnor.jvm.util.CodeStream;
+import haidnor.jvm.util.JVMThreadHolder;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * JVM 字节码执行引擎
+ */
+@Slf4j
+public class JavaExecutionEngine {
+
+ /**
+ * 执行 public static void main(String[] args) 方法
+ */
+ public static void callMainMethod(JavaClass javaClass) {
+ JavaMethod mainMethod = javaClass.getMainMethod();
+ callMethod(null, javaClass, mainMethod);
+ }
+
+ /**
+ * 执行普通方法
+ *
+ * @param lastFrame 方法调用者的栈帧
+ * @param javaMethod 方法元信息
+ */
+ public static void callMethod(Frame lastFrame, JavaClass javaClass, JavaMethod javaMethod) {
+ JVMThread jvmThread = JVMThreadHolder.get();
+ // 调用方法时会创建新的栈帧
+ Frame newFrame = new Frame(jvmThread, javaClass, javaMethod);
+
+ // 如果线程栈内存在栈帧, 代表可能需要方法调用传参
+ if (lastFrame != null) {
+ String signature = javaMethod.getSignature();
+ String[] argumentTypes = Utility.methodSignatureArgumentTypes(signature);
+
+ int argumentSlotSize = argumentTypes.length;
+ if (!javaMethod.isStatic()) {
+ argumentSlotSize++;
+ }
+
+ // 方法调用传参 (原理: 将顶部栈帧的操作数栈中的数据弹出, 存入新栈帧的局部变量表中)
+ LocalVariableTable localVariableTable = javaMethod.getLocalVariableTable();
+ if (localVariableTable != null) {
+ for (int i = argumentSlotSize - 1; i >= 0; i--) {
+ LocalVariable[] localVariableArr = localVariableTable.getLocalVariableTable();
+ LocalVariable localVariable = localVariableArr[i];
+ int slotIndex = localVariable.getIndex();
+ StackValue stackValue = lastFrame.pop();
+ newFrame.slotSet(slotIndex, stackValue);
+ }
+ }
+ }
+
+ // 将新栈帧压入线程栈顶部, 并执行新栈帧中的代码
+ jvmThread.push(newFrame);
+ executeFrame(newFrame);
+ }
+
+ /**
+ * 执行 JVM 线程栈栈帧 (haidnorJVM 中最关键的代码)
+ */
+ @SneakyThrows
+ public static void executeFrame(Frame frame) {
+ int stackSize = frame.getJvmThread().stackSize();
+
+ String blank = getDebugStackInfoBlank(stackSize);
+ log.debug("{}┌──────────────────[{}] {} | {}", blank, stackSize, frame.getJavaClass().getClassName(), frame.getJavaMethod());
+
+ // 解析方法中的字节码指令
+ Map instructionMap = new HashMap<>();
+ CodeStream codeStream = frame.getCodeStream();
+ while (codeStream.available() > 0) {
+ Instruction instruction = InstructionFactory.creatInstruction(codeStream);
+ instructionMap.put(instruction.getIndex(), instruction);
+ // log.debug("{}│> {}", blank, instruction); // debug 输出解析字节码指令的内容
+ }
+ // log.debug("{}├ - - - - - - - - -", blank);
+
+ // 执行方法中的字节码指令
+ // 提示: 变量 pc 相当于程序计数器, 记录当前执行到的字节码指令的"行号"
+ for (int pc = 0; pc < frame.getCodeLength(); ) {
+ Instruction instruction = instructionMap.get(pc);
+ log.debug("{}│ {}", blank, instruction);
+ try {
+ // 执行字节码指令
+ instruction.execute(frame);
+ // 若为 return 系列指令则结束当前栈帧 (RETURN,ARETURN,DRETURN,FRETURN,IRETURN)
+ if (instruction instanceof ReturnableInstruction) {
+ break;
+ }
+ // 程序计数器值增加. 指向下一次执行的字节码行号
+ pc += instruction.getOffSet();
+ }
+ // 捕获执行字节码指令抛出的异常
+ catch (Exception exception) {
+ // 从类元信息中获取异常表
+ CodeException[] exceptionTable = frame.getJavaMethod().getCode().getExceptionTable();
+
+ // handlerPC 是从异常表中获取的处理异常的字节码行号 (如果查询不到就会一直为 null. 代表方法无异常处理代码)
+ Integer handlerPC = null;
+ for (CodeException codeException : exceptionTable) {
+ if (codeException.getStartPC() <= pc && pc <= codeException.getEndPC()) {
+ // 异常类型 (0 代表捕获所有类型的异常)
+ int catchType = codeException.getCatchType();
+ if (catchType == 0) {
+ frame.push(new StackValue(Const.T_OBJECT, exception));
+ handlerPC = codeException.getHandlerPC();
+ } else {
+ // 从常量池中查询异常表定义的异常类型
+ String exceptionClassName = frame.getJavaClass().getConstantPool().constantClass_ClassName(catchType);
+ exceptionClassName = Utility.compactClassName(exceptionClassName, false);
+
+ // 判断异常的泛型类型. 假如执行指令抛出的是 NullPointerException 类型, 异常表定义的是 Exception 类型, 则此异常可以被捕获
+ Class> exceptionClass = Class.forName(exceptionClassName);
+ if (exceptionClass.isAssignableFrom(exception.getClass())) {
+ frame.push(new StackValue(Const.T_OBJECT, exception));
+ handlerPC = codeException.getHandlerPC();
+ }
+ }
+ }
+ }
+ if (handlerPC != null) {
+ // 将程序计数器跳转到处理异常的字节码指令上
+ pc = handlerPC;
+ } else {
+ // 方法无异常处理,结束栈帧. 将异常抛给调用者处理
+ log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize);
+ throw exception;
+ }
+ }
+
+ }
+
+ log.debug("{}└──────────────────[{}] {} | {}", blank, stackSize, frame.getJavaClass().getClassName(), frame.getJavaMethod());
+ }
+
+ /**
+ * 计算绘画 jvm 线程栈 debug 日志信息的空格
+ * 用于表现栈的调用关系
+ *
+ * @param stackSize 当前 JVM 线程栈的栈帧数量
+ */
+ private static String getDebugStackInfoBlank(int stackSize) {
+ StringBuilder blank = new StringBuilder();
+ blank.append(" ".repeat(stackSize - 1));
+ int index = 0;
+ for (int i = 0; i < stackSize - 1; i++) {
+ blank.replace(index, index + 1, "│");
+ index += 20;
+ }
+ return blank.toString();
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/instruction/Instruction.java b/src/main/java/haidnor/jvm/instruction/Instruction.java
new file mode 100644
index 0000000..331db8c
--- /dev/null
+++ b/src/main/java/haidnor/jvm/instruction/Instruction.java
@@ -0,0 +1,31 @@
+package haidnor.jvm.instruction;
+
+import haidnor.jvm.runtime.Frame;
+import haidnor.jvm.util.CodeStream;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+public abstract class Instruction {
+ /**
+ * 指令在字节码 code 数组中的索引下标 (指令行号)
+ */
+ private final int index;
+ /**
+ * 执行下一个指令的偏移量
+ */
+ @Setter
+ private int offSet = 1;
+
+ public Instruction(CodeStream codeStream) {
+ this.index = codeStream.getIndex();
+ }
+
+ public abstract void execute(Frame frame);
+
+ @Override
+ public String toString() {
+ return index + " " + this.getClass().getSimpleName();
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/instruction/InstructionFactory.java b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java
new file mode 100644
index 0000000..6d28943
--- /dev/null
+++ b/src/main/java/haidnor/jvm/instruction/InstructionFactory.java
@@ -0,0 +1,617 @@
+package haidnor.jvm.instruction;
+
+import haidnor.jvm.util.CodeStream;
+
+public abstract class InstructionFactory {
+
+ public static Instruction creatInstruction(CodeStream codeStream) {
+ int opcode = codeStream.readJavaVmOpcode();
+ switch (opcode) {
+// case Const.NOP -> {
+// return new NOP(codeStream);
+// }
+// case Const.ACONST_NULL -> {
+// return new ACONST_NULL(codeStream);
+// }
+// case Const.ICONST_M1 -> {
+// return new ICONST_M1(codeStream);
+// }
+// case Const.ICONST_0 -> {
+// return new ICONST_0(codeStream);
+// }
+// case Const.ICONST_1 -> {
+// return new ICONST_1(codeStream);
+// }
+// case Const.ICONST_2 -> {
+// return new ICONST_2(codeStream);
+// }
+// case Const.ICONST_3 -> {
+// return new ICONST_3(codeStream);
+// }
+// case Const.ICONST_4 -> {
+// return new ICONST_4(codeStream);
+// }
+// case Const.ICONST_5 -> {
+// return new ICONST_5(codeStream);
+// }
+// case Const.LCONST_0 -> {
+// return new LCONST_0(codeStream);
+// }
+// case Const.LCONST_1 -> {
+// return new LCONST_1(codeStream);
+// }
+// case Const.FCONST_1 -> {
+// return new FCONST_1(codeStream);
+// }
+// case Const.FCONST_2 -> {
+// return new FCONST_2(codeStream);
+// }
+// case Const.DCONST_0 -> {
+// return new DCONST_0(codeStream);
+// }
+// case Const.DCONST_1 -> {
+// return new DCONST_1(codeStream);
+// }
+// case Const.BIPUSH -> {
+// return new BIPUSH(codeStream);
+// }
+// case Const.SIPUSH -> {
+// return new SIPUSH(codeStream);
+// }
+// case Const.LDC -> {
+// return new LDC(codeStream);
+// }
+// case Const.LDC_W -> {
+// return new LDC_W(codeStream);
+// }
+// case Const.LDC2_W -> {
+// return new LDC2W(codeStream);
+// }
+// case Const.ILOAD -> {
+// return new ILOAD(codeStream);
+// }
+// case Const.LLOAD -> {
+// return new LLOAD(codeStream);
+// }
+// case Const.FLOAD -> {
+// return new FLOAD(codeStream);
+// }
+// case Const.DLOAD -> {
+// return new DLOAD(codeStream);
+// }
+// case Const.ALOAD -> {
+// return new ALOAD(codeStream);
+// }
+// case Const.ILOAD_0 -> {
+// return new ILOAD_0(codeStream);
+// }
+// case Const.ILOAD_1 -> {
+// return new ILOAD_1(codeStream);
+// }
+// case Const.ILOAD_2 -> {
+// return new ILOAD_2(codeStream);
+// }
+// case Const.ILOAD_3 -> {
+// return new ILOAD_3(codeStream);
+// }
+// case Const.LLOAD_0 -> {
+// return new LLOAD_0(codeStream);
+// }
+// case Const.LLOAD_1 -> {
+// return new LLOAD_1(codeStream);
+// }
+// case Const.LLOAD_2 -> {
+// return new LLOAD_2(codeStream);
+// }
+// case Const.LLOAD_3 -> {
+// return new LLOAD_3(codeStream);
+// }
+// case Const.FLOAD_0 -> {
+// return new FLOAD_0(codeStream);
+// }
+// case Const.FLOAD_1 -> {
+// return new FLOAD_1(codeStream);
+// }
+// case Const.FLOAD_2 -> {
+// return new FLOAD_2(codeStream);
+// }
+// case Const.FLOAD_3 -> {
+// return new FLOAD_3(codeStream);
+// }
+// case Const.DLOAD_0 -> {
+// return new DLOAD_0(codeStream);
+// }
+// case Const.DLOAD_1 -> {
+// return new DLOAD_1(codeStream);
+// }
+// case Const.DLOAD_2 -> {
+// return new DLOAD_2(codeStream);
+// }
+// case Const.DLOAD_3 -> {
+// return new DLOAD_3(codeStream);
+// }
+// case Const.ALOAD_0 -> {
+// return new ALOAD_0(codeStream);
+// }
+// case Const.ALOAD_1 -> {
+// return new ALOAD_1(codeStream);
+// }
+// case Const.ALOAD_2 -> {
+// return new ALOAD_2(codeStream);
+// }
+// case Const.ALOAD_3 -> {
+// return new ALOAD_3(codeStream);
+// }
+// case Const.IALOAD -> {
+// return new IALOAD(codeStream);
+// }
+// case Const.LALOAD -> {
+// return new LALOAD(codeStream);
+// }
+// case Const.FALOAD -> {
+// return new FALOAD(codeStream);
+// }
+// case Const.DALOAD -> {
+// return new DALOAD(codeStream);
+// }
+// case Const.AALOAD -> {
+// return new AALOAD(codeStream);
+// }
+// case Const.BALOAD -> {
+// return new BALOAD(codeStream);
+// }
+// case Const.CALOAD -> {
+// return new CALOAD(codeStream);
+// }
+// case Const.SALOAD -> {
+// return new SALOAD(codeStream);
+// }
+// case Const.ISTORE -> {
+// return new ISTORE(codeStream);
+// }
+// case Const.LSTORE -> {
+// return new LSTORE(codeStream);
+// }
+// case Const.FSTORE -> {
+// return new FSTORE(codeStream);
+// }
+// case Const.DSTORE -> {
+// return new DSTORE(codeStream);
+// }
+// case Const.ASTORE -> {
+// return new ASTORE(codeStream);
+// }
+// case Const.ISTORE_0 -> {
+// return new ISTORE_0(codeStream);
+// }
+// case Const.ISTORE_1 -> {
+// return new ISTORE_1(codeStream);
+// }
+// case Const.ISTORE_2 -> {
+// return new ISTORE_2(codeStream);
+// }
+// case Const.ISTORE_3 -> {
+// return new ISTORE_3(codeStream);
+// }
+// case Const.LSTORE_0 -> {
+// return new LSTORE_0(codeStream);
+// }
+// case Const.LSTORE_1 -> {
+// return new LSTORE_1(codeStream);
+// }
+// case Const.LSTORE_2 -> {
+// return new LSTORE_2(codeStream);
+// }
+// case Const.LSTORE_3 -> {
+// return new LSTORE_3(codeStream);
+// }
+// case Const.FSTORE_0 -> {
+// return new FSTORE_0(codeStream);
+// }
+// case Const.FSTORE_1 -> {
+// return new FSTORE_1(codeStream);
+// }
+// case Const.FSTORE_2 -> {
+// return new FSTORE_2(codeStream);
+// }
+// case Const.FSTORE_3 -> {
+// return new FSTORE_3(codeStream);
+// }
+// case Const.DSTORE_0 -> {
+// return new DSTORE_0(codeStream);
+// }
+// case Const.DSTORE_1 -> {
+// return new DSTORE_1(codeStream);
+// }
+// case Const.DSTORE_2 -> {
+// return new DSTORE_2(codeStream);
+// }
+// case Const.DSTORE_3 -> {
+// return new DSTORE_3(codeStream);
+// }
+// case Const.ASTORE_0 -> {
+// return new ASTORE_0(codeStream);
+// }
+// case Const.ASTORE_1 -> {
+// return new ASTORE_1(codeStream);
+// }
+// case Const.ASTORE_2 -> {
+// return new ASTORE_2(codeStream);
+// }
+// case Const.ASTORE_3 -> {
+// return new ASTORE_3(codeStream);
+// }
+// case Const.IASTORE -> {
+// return new IASTORE(codeStream);
+// }
+// case Const.LASTORE -> {
+// return new LASTORE(codeStream);
+// }
+// case Const.FASTORE -> {
+// return new FASTORE(codeStream);
+// }
+// case Const.DASTORE -> {
+// return new DASTORE(codeStream);
+// }
+// case Const.AASTORE -> {
+// return new AASTORE(codeStream);
+// }
+// case Const.BASTORE -> {
+// return new BASTORE(codeStream);
+// }
+// case Const.CASTORE -> {
+// return new CASTORE(codeStream);
+// }
+// case Const.SASTORE -> {
+// return new SASTORE(codeStream);
+// }
+// case Const.POP -> {
+// return new POP(codeStream);
+// }
+// case Const.POP2 -> {
+// return new POP2(codeStream);
+// }
+// case Const.DUP -> {
+// return new DUP(codeStream);
+// }
+// case Const.DUP_X1 -> {
+// return new DUP_X1(codeStream);
+// }
+// case Const.DUP_X2 -> {
+// return new DUP_X2(codeStream);
+// }
+// case Const.DUP2 -> {
+// return new DUP2(codeStream);
+// }
+// case Const.DUP2_X1 -> {
+// return new DUP2_X1(codeStream);
+// }
+// case Const.DUP2_X2 -> {
+// return new DUP2_X2(codeStream);
+// }
+// case Const.SWAP -> {
+// return new SWAP(codeStream);
+// }
+// case Const.IADD -> {
+// return new IADD(codeStream);
+// }
+// case Const.LADD -> {
+// return new LADD(codeStream);
+// }
+// case Const.FADD -> {
+// return new FADD(codeStream);
+// }
+// case Const.DADD -> {
+// return new DADD(codeStream);
+// }
+// case Const.ISUB -> {
+// return new ISUB(codeStream);
+// }
+// case Const.LSUB -> {
+// return new LSUB(codeStream);
+// }
+// case Const.FSUB -> {
+// return new FSUB(codeStream);
+// }
+// case Const.DSUB -> {
+// return new DSUB(codeStream);
+// }
+// case Const.IMUL -> {
+// return new IMUL(codeStream);
+// }
+// case Const.LMUL -> {
+// return new LMUL(codeStream);
+// }
+// case Const.FMUL -> {
+// return new FMUL(codeStream);
+// }
+// case Const.DMUL -> {
+// return new DMUL(codeStream);
+// }
+// case Const.IDIV -> {
+// return new IDIV(codeStream);
+// }
+// case Const.LDIV -> {
+// return new LDIV(codeStream);
+// }
+// case Const.FDIV -> {
+// return new FDIV(codeStream);
+// }
+// case Const.DDIV -> {
+// return new DDIV(codeStream);
+// }
+// case Const.IREM -> {
+// return new IREM(codeStream);
+// }
+// case Const.LREM -> {
+// return new LREM(codeStream);
+// }
+// case Const.FREM -> {
+// return new FREM(codeStream);
+// }
+// case Const.DREM -> {
+// return new DREM(codeStream);
+// }
+// case Const.INEG -> {
+// return new INEG(codeStream);
+// }
+// case Const.LNEG -> {
+// return new LNEG(codeStream);
+// }
+// case Const.FNEG -> {
+// return new FNEG(codeStream);
+// }
+// case Const.DNEG -> {
+// return new DNEG(codeStream);
+// }
+// case Const.ISHL -> {
+// return new ISHL(codeStream);
+// }
+// case Const.LSHL -> {
+// return new LSHL(codeStream);
+// }
+// case Const.ISHR -> {
+// return new ISHR(codeStream);
+// }
+// case Const.LSHR -> {
+// return new LSHR(codeStream);
+// }
+// case Const.IUSHR -> {
+// return new IUSHR(codeStream);
+// }
+// case Const.LUSHR -> {
+// return new LUSHR(codeStream);
+// }
+// case Const.IAND -> {
+// return new IAND(codeStream);
+// }
+// case Const.LAND -> {
+// return new LAND(codeStream);
+// }
+// case Const.IOR -> {
+// return new IOR(codeStream);
+// }
+// case Const.LOR -> {
+// return new LOR(codeStream);
+// }
+// case Const.IXOR -> {
+// return new IXOR(codeStream);
+// }
+// case Const.LXOR -> {
+// return new LXOR(codeStream);
+// }
+// case Const.IINC -> {
+// return new IINC(codeStream);
+// }
+// case Const.I2L -> {
+// return new I2L(codeStream);
+// }
+// case Const.I2F -> {
+// return new I2F(codeStream);
+// }
+// case Const.I2D -> {
+// return new I2D(codeStream);
+// }
+// case Const.L2I -> {
+// return new L2I(codeStream);
+// }
+// case Const.L2F -> {
+// return new L2F(codeStream);
+// }
+// case Const.L2D -> {
+// return new L2D(codeStream);
+// }
+// case Const.F2I -> {
+// return new F2I(codeStream);
+// }
+// case Const.F2L -> {
+// return new F2L(codeStream);
+// }
+// case Const.F2D -> {
+// return new F2D(codeStream);
+// }
+// case Const.D2I -> {
+// return new D2I(codeStream);
+// }
+// case Const.D2L -> {
+// return new D2L(codeStream);
+// }
+// case Const.D2F -> {
+// return new D2F(codeStream);
+// }
+// case Const.I2B -> {
+// return new I2B(codeStream);
+// }
+// case Const.I2C -> {
+// return new I2C(codeStream);
+// }
+// case Const.I2S -> {
+// return new I2S(codeStream);
+// }
+// case Const.LCMP -> {
+// return new LCMP(codeStream);
+// }
+// case Const.FCMPL -> {
+// return new FCMPL(codeStream);
+// }
+// case Const.FCMPG -> {
+// return new FCMPG(codeStream);
+// }
+// case Const.DCMPL -> {
+// return new DCMPL(codeStream);
+// }
+// case Const.DCMPG -> {
+// return new DCMPG(codeStream);
+// }
+// case Const.IFEQ -> {
+// return new IFEQ(codeStream);
+// }
+// case Const.IFNE -> {
+// return new IFNE(codeStream);
+// }
+// case Const.IFLT -> {
+// return new IFLT(codeStream);
+// }
+// case Const.IFGE -> {
+// return new IFGE(codeStream);
+// }
+// case Const.IFGT -> {
+// return new IFGT(codeStream);
+// }
+// case Const.IFLE -> {
+// return new IFLE(codeStream);
+// }
+// case Const.IF_ICMPEQ -> {
+// return new IF_ICMPEQ(codeStream);
+// }
+// case Const.IF_ICMPNE -> {
+// return new IF_ICMPNE(codeStream);
+// }
+// case Const.IF_ICMPLT -> {
+// return new IF_ICMPLT(codeStream);
+// }
+// case Const.IF_ICMPGE -> {
+// return new IF_ICMPGE(codeStream);
+// }
+// case Const.IF_ICMPGT -> {
+// return new IF_ICMPGT(codeStream);
+// }
+// case Const.IF_ICMPLE -> {
+// return new IF_ICMPLE(codeStream);
+// }
+// case Const.IF_ACMPEQ -> {
+// return new IF_ACMPEQ(codeStream);
+// }
+// case Const.IF_ACMPNE -> {
+// return new IF_ACMPNE(codeStream);
+// }
+// case Const.GOTO -> {
+// return new GOTO(codeStream);
+// }
+// case Const.JSR -> {
+// return new JSR(codeStream);
+// }
+// case Const.RET -> {
+// return new RET(codeStream);
+// }
+// case Const.TABLESWITCH -> {
+// return new TABLESWITCH(codeStream); // TODO
+// }
+// case Const.LOOKUPSWITCH -> {
+// return new LOOKUPSWITCH(codeStream); // TODO
+// }
+// case Const.IRETURN -> {
+// return new IRETURN(codeStream);
+// }
+// case Const.LRETURN -> {
+// return new LRETURN(codeStream);
+// }
+// case Const.FRETURN -> {
+// return new FRETURN(codeStream);
+// }
+// case Const.DRETURN -> {
+// return new DRETURN(codeStream);
+// }
+// case Const.ARETURN -> {
+// return new ARETURN(codeStream);
+// }
+// case Const.RETURN -> {
+// return new RETURN(codeStream);
+// }
+// case Const.GETSTATIC -> {
+// return new GETSTATIC(codeStream);
+// }
+// case Const.PUTSTATIC -> {
+// return new PUTSTATIC(codeStream);
+// }
+// case Const.GETFIELD -> {
+// return new GETFIELD(codeStream);
+// }
+// case Const.PUTFIELD -> {
+// return new PUTFIELD(codeStream);
+// }
+// case Const.INVOKEVIRTUAL -> {
+// return new INVOKEVIRTUAL(codeStream);
+// }
+// case Const.INVOKESPECIAL -> {
+// return new INVOKESPECIAL(codeStream);
+// }
+// case Const.INVOKESTATIC -> {
+// return new INVOKESTATIC(codeStream);
+// }
+// case Const.INVOKEINTERFACE -> {
+// return new INVOKEINTERFACE(codeStream);
+// }
+// case Const.INVOKEDYNAMIC -> {
+// return new INVOKEDYNAMIC(codeStream); // TODO
+// }
+// case Const.NEW -> {
+// return new NEW(codeStream);
+// }
+// case Const.NEWARRAY -> {
+// return new NEWARRAY(codeStream);
+// }
+// case Const.ANEWARRAY -> {
+// return new ANEWARRAY(codeStream);
+// }
+// case Const.ARRAYLENGTH -> {
+// return new ARRAYLENGTH(codeStream);
+// }
+// case Const.ATHROW -> {
+// return new ATHROW(codeStream);
+// }
+// case Const.CHECKCAST -> {
+// return new CHECKCAST(codeStream);
+// }
+// case Const.INSTANCEOF -> {
+// return new INSTANCEOF(codeStream);
+// }
+// case Const.MONITORENTER -> {
+// return new MONITORENTER(codeStream);
+// }
+// case Const.MONITOREXIT -> {
+// return new MONITOREXIT(codeStream);
+// }
+// case Const.WIDE -> {
+// return new WIDE(codeStream);
+// }
+// case Const.MULTIANEWARRAY -> {
+// return new MULTIANEWARRAY(codeStream);
+// }
+// case Const.IFNULL -> {
+// return new IFNULL(codeStream);
+// }
+// case Const.IFNONNULL -> {
+// return new IFNONNULL(codeStream);
+// }
+// case Const.GOTO_W -> {
+// return new GOTO_W(codeStream);
+// }
+// case Const.JSR_W -> {
+// return new JSR_W(codeStream);
+// }
+ default -> throw new Error("Unknown JavaVM opcode " + opcode);
+ }
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/instruction/ReturnableInstruction.java b/src/main/java/haidnor/jvm/instruction/ReturnableInstruction.java
new file mode 100644
index 0000000..b5c91b3
--- /dev/null
+++ b/src/main/java/haidnor/jvm/instruction/ReturnableInstruction.java
@@ -0,0 +1,14 @@
+package haidnor.jvm.instruction;
+
+import haidnor.jvm.util.CodeStream;
+
+/**
+ * return 系列字节码指令的抽象类
+ */
+public abstract class ReturnableInstruction extends Instruction {
+
+ public ReturnableInstruction(CodeStream codeStream) {
+ super(codeStream);
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/rtda/ArrayInstance.java b/src/main/java/haidnor/jvm/rtda/ArrayInstance.java
new file mode 100644
index 0000000..09ccb13
--- /dev/null
+++ b/src/main/java/haidnor/jvm/rtda/ArrayInstance.java
@@ -0,0 +1,14 @@
+package haidnor.jvm.rtda;
+
+import haidnor.jvm.bcel.classfile.JavaClass;
+
+public abstract class ArrayInstance extends Instance {
+
+ public final int size;
+
+ public ArrayInstance(JavaClass javaClass, int size) {
+ super(javaClass);
+ this.size = size;
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/rtda/BasicTypeArray.java b/src/main/java/haidnor/jvm/rtda/BasicTypeArray.java
new file mode 100644
index 0000000..cb4a6b9
--- /dev/null
+++ b/src/main/java/haidnor/jvm/rtda/BasicTypeArray.java
@@ -0,0 +1,62 @@
+package haidnor.jvm.rtda;
+
+public class BasicTypeArray extends ArrayInstance {
+
+ public int[] ints;
+ public long[] longs;
+ public float[] floats;
+ public double[] doubles;
+
+ private BasicTypeArray(int size) {
+ super(null, size);
+ }
+
+ public static BasicTypeArray charArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.ints = new int[size];
+ return array;
+ }
+
+ public static BasicTypeArray boolArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.ints = new int[size];
+ return array;
+ }
+
+ public static BasicTypeArray byteArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.ints = new int[size];
+ return array;
+ }
+
+ public static BasicTypeArray shortArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.ints = new int[size];
+ return array;
+ }
+
+ public static BasicTypeArray intArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.ints = new int[size];
+ return array;
+ }
+
+ public static BasicTypeArray longArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.longs = new long[size];
+ return array;
+ }
+
+ public static BasicTypeArray floatArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.floats = new float[size];
+ return array;
+ }
+
+ public static BasicTypeArray doubleArray(int size) {
+ final BasicTypeArray array = new BasicTypeArray(size);
+ array.doubles = new double[size];
+ return array;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/haidnor/jvm/rtda/Instance.java b/src/main/java/haidnor/jvm/rtda/Instance.java
new file mode 100644
index 0000000..588e6fe
--- /dev/null
+++ b/src/main/java/haidnor/jvm/rtda/Instance.java
@@ -0,0 +1,50 @@
+package haidnor.jvm.rtda;
+
+
+import haidnor.jvm.bcel.classfile.JavaClass;
+import haidnor.jvm.bcel.classfile.JavaField;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class Instance {
+
+ @Getter
+ private final JavaClass javaClass;
+
+ private final List javaFieldList = new ArrayList<>();
+
+ private Instance superInstance;
+
+ public Instance(JavaClass javaClass) {
+ this.javaClass = javaClass;
+ }
+
+ public void setSuperInstance(Instance superInstance) {
+ this.superInstance = superInstance;
+ }
+
+ /**
+ * 获取字段
+ *
+ * @param name 字段名称
+ * @param signature 字段签名
+ */
+ public JavaField getField(String name, String signature) {
+ // this object
+ for (JavaField field : javaFieldList) {
+ if (Objects.equals(field.getName(), name) && Objects.equals(field.getSignature(), signature)) {
+ return field;
+ }
+ }
+ if (this.superInstance == null) {
+ return null;
+ }
+ // super object
+ return this.superInstance.getField(name, signature);
+ }
+
+
+}
diff --git a/src/main/java/haidnor/jvm/rtda/InstanceArray.java b/src/main/java/haidnor/jvm/rtda/InstanceArray.java
new file mode 100644
index 0000000..7935aba
--- /dev/null
+++ b/src/main/java/haidnor/jvm/rtda/InstanceArray.java
@@ -0,0 +1,14 @@
+package haidnor.jvm.rtda;
+
+import haidnor.jvm.bcel.classfile.JavaClass;
+
+public class InstanceArray extends ArrayInstance {
+
+ public final Instance[] items;
+
+ public InstanceArray(JavaClass javaClass, Instance[] items) {
+ super(javaClass, items.length);
+ this.items = items;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/haidnor/jvm/rtda/Metaspace.java b/src/main/java/haidnor/jvm/rtda/Metaspace.java
new file mode 100644
index 0000000..f3ff57b
--- /dev/null
+++ b/src/main/java/haidnor/jvm/rtda/Metaspace.java
@@ -0,0 +1,29 @@
+package haidnor.jvm.rtda;
+
+import haidnor.jvm.bcel.classfile.JavaClass;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class Metaspace {
+
+ private static final Map javaClassMap = new ConcurrentHashMap<>();
+
+ /**
+ * 名称用.符号分割
+ * 例如: haidnor.jvm.test.instruction.references.NEW
+ */
+ public static JavaClass getJavaClass(String className) {
+ return javaClassMap.get(className);
+ }
+
+ /**
+ * 注册名称用.符号分割
+ * 例如: haidnor.jvm.test.instruction.references.NEW
+ */
+ public static void registerJavaClass(JavaClass javaClass) {
+ String className = javaClass.getClassName();
+ javaClassMap.put(className, javaClass);
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/rtda/package-info.java b/src/main/java/haidnor/jvm/rtda/package-info.java
new file mode 100644
index 0000000..bb8b9ce
--- /dev/null
+++ b/src/main/java/haidnor/jvm/rtda/package-info.java
@@ -0,0 +1,17 @@
+/*
+JVM(Java虚拟机)的 RTDA(Run-time Data Area)是指在程序运行时分配给Java应用程序使用的内存区域,它包含了几个重要的组成部分。
+
+1.程序计数器(Program Counter Register):程序计数器是一块较小的内存区域,它保存着当前线程所执行的字节码指令的地址或索引。每个线程都有自己独立的程序计数器,用于记录线程执行的位置,以便线程切换后能够恢复执行。
+
+2.Java虚拟机栈(Java Virtual Machine Stacks):每个线程在创建时都会分配一个对应的Java虚拟机栈,用于存储局部变量、方法参数、动态链接信息和方法返回值等数据。每个方法在执行时会创建一个栈帧(Stack Frame),栈帧用于存储方法的局部变量和操作数栈等信息。
+
+3.本地方法栈(Native Method Stack):本地方法栈与Java虚拟机栈类似,但是它为本地方法(即用其他语言编写的方法)服务。本地方法栈也会为本地方法的调用和执行提供内存空间。
+
+4.Java堆(Java Heap):Java堆是Java虚拟机管理的最大的一块内存区域,用于存储对象实例和数组数据。几乎所有的对象都在Java堆上分配内存,垃圾收集器也主要针对Java堆进行垃圾回收。
+
+5.方法区(Method Area):方法区是存储类的结构信息、常量池、字段和方法的字节码等数据的内存区域。它包括运行时常量池,用于存放编译期生成的各种字面量和符号引用。
+
+RTDA是JVM在运行时为Java应用程序提供的数据区域,每个线程都有自己的私有数据区域(程序计数器、虚拟机栈和本地方法栈),而Java堆和方法区则是所有线程共享的。这些区域的组合提供了Java程序运行所需的内存空间。
+
+*/
+package haidnor.jvm.rtda;
\ No newline at end of file
diff --git a/src/main/java/haidnor/jvm/runtime/Frame.java b/src/main/java/haidnor/jvm/runtime/Frame.java
new file mode 100644
index 0000000..b5075c0
--- /dev/null
+++ b/src/main/java/haidnor/jvm/runtime/Frame.java
@@ -0,0 +1,243 @@
+package haidnor.jvm.runtime;
+
+import haidnor.jvm.bcel.Const;
+import haidnor.jvm.bcel.classfile.Code;
+import haidnor.jvm.bcel.classfile.JavaClass;
+import haidnor.jvm.bcel.classfile.JavaMethod;
+import haidnor.jvm.rtda.Instance;
+import haidnor.jvm.util.CodeStream;
+import lombok.Getter;
+
+import java.util.Stack;
+
+/**
+ * JVM 线程栈帧
+ */
+public class Frame {
+ /**
+ * 每个栈帧中包含一个指向运行时常量池中该栈帧所属的方法的引用。包含这个引用的目的就是为了支持当前方法实现动态链接
+ * 有了这个引用,执行引擎就可以找到指定的方法,加载字节码指令
+ */
+ @Getter
+ public final JavaClass javaClass;
+ /**
+ * 当前栈帧所处于的 JVM 线程
+ */
+ @Getter
+ private final JVMThread jvmThread;
+ /**
+ * 栈帧所属的方法
+ *
+ * <<深入理解JAVA虚拟机>>:
+ * 每一个栈帧都包含一个指向运行时常量池中该栈帧所属的方法引用,持有这个引用的目的是为了支持方法调用过程中的动态链接(Dynamic Linking)
+ */
+ @Getter
+ private final JavaMethod javaMethod;
+ /**
+ * 栈帧所属的方法代码对象
+ */
+ private final Code code;
+
+ @Getter
+ private final CodeStream codeStream;
+
+ /**
+ * 操作数栈
+ */
+ private final Stack operandStack = new Stack<>();
+
+ /**
+ * 槽位
+ */
+ private final Slot[] slots;
+
+ public Frame(JVMThread thread, JavaClass javaClass, JavaMethod javaMethod) {
+ this.jvmThread = thread;
+ this.javaClass = javaClass;
+ this.javaMethod = javaMethod;
+ this.code = javaMethod.getCode();
+ this.codeStream = new CodeStream(javaMethod.getCode());
+ this.slots = new Slot[code.getMaxLocals()];
+ }
+
+ public int getCodeLength() {
+ return this.code.getCode().length;
+ }
+
+ public JavaMethod getMetaMethod() {
+ return javaMethod;
+ }
+
+ /* 操作数栈操作 --------------------------------------------------------------------------------------------------- */
+
+ /**
+ * 压入操作数栈
+ */
+ public void push(StackValue stackValue) {
+ this.operandStack.push(stackValue);
+ }
+
+ /**
+ * 弹出操作数栈顶元素
+ */
+ public StackValue pop() {
+ return this.operandStack.pop();
+ }
+
+ /**
+ * 弹出操作数栈顶元素
+ */
+ public StackValue peek() {
+ return this.operandStack.peek();
+ }
+
+ /**
+ * 从操作数栈中弹出指定数量的元素的值
+ */
+ public Object[] popStacksValue(int num) {
+ Object[] objArr = new Object[num];
+ for (int i = num - 1; i >= 0; i--) {
+ StackValue stackValue = operandStack.pop();
+ switch (stackValue.getValueType()) {
+ case Const.T_CHAR, Const.T_INT, Const.T_OBJECT, Const.T_LONG, Const.T_DOUBLE, Const.T_FLOAT:
+ break;
+ case Const.T_ARRAY:
+ throw new Error("数组类型,未作处理");
+ default:
+ throw new Error("无法识别的参数类型");
+ }
+ objArr[i] = stackValue.getValue();
+ }
+ return objArr;
+ }
+
+
+ public int popInt() {
+ StackValue stackValue = pop();
+ return (int) stackValue.getValue();
+ }
+
+ public void pushInt(int value) {
+ push(new StackValue(Const.T_INT, value));
+ }
+
+ public long popLong() {
+ StackValue stackValue = pop();
+ return (long) stackValue.getValue();
+ }
+
+ public void pushLong(long value) {
+ push(new StackValue(Const.T_LONG, value));
+ }
+
+ public float popFloat() {
+ StackValue stackValue = pop();
+ return (float) stackValue.getValue();
+ }
+
+ public void pushFloat(float value) {
+ push(new StackValue(Const.T_FLOAT, value));
+ }
+
+ public double popDouble() {
+ StackValue stackValue = pop();
+ return (double) stackValue.getValue();
+ }
+
+ public void pushDouble(double value) {
+ push(new StackValue(Const.T_DOUBLE, value));
+ }
+
+ public Instance popRef() {
+ StackValue stackValue = pop();
+ return (Instance) stackValue.getValue();
+ }
+
+ public void pushRef(Object value) {
+ push(new StackValue(Const.T_OBJECT, value));
+ }
+
+ /**
+ * 获取操作数栈中元素的数量
+ */
+ public int operandStackSize() {
+ return this.operandStack.size();
+ }
+
+ /* 局部变量表操作 --------------------------------------------------------------------------------------------------- */
+
+ public void slotSetInt(int index, int val) {
+ slots[index] = new Slot(val);
+ }
+
+ public int slotGetInt(int index) {
+ return slots[index].num;
+ }
+
+ public void slotSetFloat(int index, float val) {
+ int tmp = Float.floatToIntBits(val);
+ slots[index] = new Slot(tmp);
+ }
+
+ public float slotGetFloat(int index) {
+ int num = slots[index].num;
+ return Float.intBitsToFloat(num);
+ }
+
+ public long slotGetLong(int index) {
+ int high = slots[index].num;
+ int low = slots[index + 1].num;
+
+ long l1 = (high & 0x000000ffffffffL) << 32;
+ long l2 = low & 0x00000000ffffffffL;
+ return l1 | l2;
+ }
+
+ public void slotSetLong(int index, long val) {
+ // high 32
+ int high = (int) (val >> 32);
+ // low 32
+ int low = (int) (val & 0x000000ffffffffL);
+
+ slots[index] = new Slot(high);
+ slots[index + 1] = new Slot(low);
+ }
+
+ public void slotSetDouble(int index, double val) {
+ long tmp = Double.doubleToLongBits(val);
+ // high 32
+ int high = (int) (tmp >> 32);
+ // low 32
+ int low = (int) (tmp & 0x000000ffffffffL);
+
+ slots[index] = new Slot(high);
+ slots[index + 1] = new Slot(low);
+ }
+
+ public double slotGetDouble(int index) {
+ long tmp = this.slotGetLong(index);
+ return Double.longBitsToDouble(tmp);
+ }
+
+ public void slotSetRef(int index, Object ref) {
+ slots[index] = new Slot(ref);
+ }
+
+ public Object slotGetRef(int index) {
+ return slots[index].ref;
+ }
+
+ public void slotSet(int index, StackValue stackValue) {
+ switch (stackValue.getValueType()) {
+ case Const.T_CHAR -> throw new Error("T_CHAR,未作处理");
+ case Const.T_INT -> slotSetInt(index, (int) stackValue.getValue());
+ case Const.T_OBJECT -> slotSetRef(index, stackValue.getValue());
+ case Const.T_LONG -> slotSetLong(index, (long) stackValue.getValue());
+ case Const.T_DOUBLE -> slotSetDouble(index, (double) stackValue.getValue());
+ case Const.T_FLOAT -> slotSetFloat(index, (float) stackValue.getValue());
+ case Const.T_ARRAY -> throw new Error("T_ARRAY,未作处理");
+ default -> throw new Error("无法识别的参数类型");
+ }
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/runtime/JVMThread.java b/src/main/java/haidnor/jvm/runtime/JVMThread.java
new file mode 100644
index 0000000..71f355c
--- /dev/null
+++ b/src/main/java/haidnor/jvm/runtime/JVMThread.java
@@ -0,0 +1,36 @@
+package haidnor.jvm.runtime;
+
+import java.util.Stack;
+
+/**
+ * JVM 线程
+ *
+ * 目前这个 JVMThread 并没有真的被 start() 开启, 不继承 Thread 也可以
+ */
+public class JVMThread extends Thread {
+
+ /**
+ * JVM 线程栈
+ */
+ private final Stack stack = new Stack<>();
+
+ public void push(Frame frame) {
+ this.stack.push(frame);
+ }
+
+ public Frame peek() {
+ return this.stack.peek();
+ }
+
+ public void pop() {
+ this.stack.pop();
+ }
+
+ /**
+ * 获取 JVM 线程栈的栈帧数量
+ */
+ public int stackSize() {
+ return this.stack.size();
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/runtime/Slot.java b/src/main/java/haidnor/jvm/runtime/Slot.java
new file mode 100644
index 0000000..c0edea8
--- /dev/null
+++ b/src/main/java/haidnor/jvm/runtime/Slot.java
@@ -0,0 +1,21 @@
+package haidnor.jvm.runtime;
+
+public class Slot {
+ public Integer num;
+ public Object ref;
+
+ public Slot(int num) {
+ this.num = num;
+ this.ref = null;
+ }
+
+ public Slot(Object ref) {
+ this.num = null;
+ this.ref = ref;
+ }
+
+ @Override
+ public String toString() {
+ return "Slot{" + "num=" + num + ", ref=" + ref + '}';
+ }
+}
diff --git a/src/main/java/haidnor/jvm/runtime/StackValue.java b/src/main/java/haidnor/jvm/runtime/StackValue.java
new file mode 100644
index 0000000..90adafa
--- /dev/null
+++ b/src/main/java/haidnor/jvm/runtime/StackValue.java
@@ -0,0 +1,21 @@
+package haidnor.jvm.runtime;
+
+import lombok.Getter;
+
+@Getter
+public class StackValue {
+ /**
+ * 类型
+ */
+ private final int valueType;
+ /**
+ * 值
+ */
+ private final Object value;
+
+ public StackValue(int valueType, Object value) {
+ this.valueType = valueType;
+ this.value = value;
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/util/CodeStream.java b/src/main/java/haidnor/jvm/util/CodeStream.java
new file mode 100644
index 0000000..f662102
--- /dev/null
+++ b/src/main/java/haidnor/jvm/util/CodeStream.java
@@ -0,0 +1,100 @@
+package haidnor.jvm.util;
+
+
+import haidnor.jvm.bcel.classfile.Code;
+import haidnor.jvm.instruction.Instruction;
+import lombok.Getter;
+import lombok.SneakyThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+
+public class CodeStream {
+
+ private final DataInputStream codeStream;
+ @Getter
+ public Code code;
+ /**
+ * 当前读取到的数组下标
+ * -1 代表还没有开始读
+ */
+ @Getter
+ private int index = -1;
+
+ public CodeStream(Code code) {
+ this.code = code;
+ this.codeStream = getDataInputStream(code.getCode());
+ }
+
+ @SneakyThrows
+ public int available() {
+ return codeStream.available();
+ }
+
+ /**
+ * 读取占用一个字节指定代码
+ */
+ @SneakyThrows
+ public int readJavaVmOpcode() {
+ this.index += 1;
+ return this.codeStream.readUnsignedByte();
+ }
+
+ /**
+ * 读取占用一个字节的操作数
+ */
+ @SneakyThrows
+ public int readByte(Instruction instruction) {
+ instruction.setOffSet(instruction.getOffSet() + 1);
+ this.index += 1;
+ return this.codeStream.readByte();
+ }
+
+ /**
+ * 读取占用一个字节的操作数
+ * int 类型
+ */
+ @SneakyThrows
+ public int readUnsignedByte(Instruction instruction) {
+ instruction.setOffSet(instruction.getOffSet() + 1);
+ this.index += 1;
+ return this.codeStream.readUnsignedByte();
+ }
+
+ /**
+ * 读取占用两个字节的操作数
+ */
+ @SneakyThrows
+ public int readShort(Instruction instruction) {
+ instruction.setOffSet(instruction.getOffSet() + 2);
+ this.index += 2;
+ return this.codeStream.readShort();
+ }
+
+ /**
+ * 读取占用两个字节的操作数
+ * int 类型
+ */
+ @SneakyThrows
+ public int readUnsignedShort(Instruction instruction) {
+ instruction.setOffSet(instruction.getOffSet() + 2);
+ this.index += 2;
+ return this.codeStream.readUnsignedShort();
+ }
+
+ /**
+ * 读取占用四个字节的操作数
+ */
+ @SneakyThrows
+ public int readInt(Instruction instruction) {
+ instruction.setOffSet(instruction.getOffSet() + 4);
+ this.index += 4;
+ return this.codeStream.readInt();
+ }
+
+ private DataInputStream getDataInputStream(byte[] bytes) {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
+ return new DataInputStream(inputStream);
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/util/JVMThreadHolder.java b/src/main/java/haidnor/jvm/util/JVMThreadHolder.java
new file mode 100644
index 0000000..e361cbc
--- /dev/null
+++ b/src/main/java/haidnor/jvm/util/JVMThreadHolder.java
@@ -0,0 +1,17 @@
+package haidnor.jvm.util;
+
+import haidnor.jvm.runtime.JVMThread;
+
+public abstract class JVMThreadHolder {
+
+ private static final ThreadLocal holder = new ThreadLocal<>();
+
+ public static void set(JVMThread thread) {
+ holder.set(thread);
+ }
+
+ public static JVMThread get() {
+ return holder.get();
+ }
+
+}
diff --git a/src/main/java/haidnor/jvm/util/SignatureUtil.java b/src/main/java/haidnor/jvm/util/SignatureUtil.java
new file mode 100644
index 0000000..825e744
--- /dev/null
+++ b/src/main/java/haidnor/jvm/util/SignatureUtil.java
@@ -0,0 +1,34 @@
+package haidnor.jvm.util;
+
+import haidnor.jvm.bcel.classfile.Utility;
+import lombok.SneakyThrows;
+
+public abstract class SignatureUtil {
+
+ /**
+ * 解析方法签名返回方法参数类型数组
+ */
+ @SneakyThrows
+ public static Class>[] getParameterTypeArr(String methodeSignature) {
+ String[] argumentTypeArr = Utility.methodSignatureArgumentTypes(methodeSignature, false);
+ Class>[] argumentClassArr = new Class[argumentTypeArr.length];
+ for (int i = 0; i < argumentTypeArr.length; i++) {
+ Class> argumentClass;
+ String argumentType = argumentTypeArr[i];
+ argumentClass = switch (argumentType) {
+ case "byte" -> byte.class;
+ case "short" -> short.class;
+ case "boolean" -> boolean.class;
+ case "char" -> char.class;
+ case "int" -> int.class;
+ case "long" -> long.class;
+ case "float" -> float.class;
+ case "double" -> double.class;
+ default -> Class.forName(argumentType);
+ };
+ argumentClassArr[i] = argumentClass;
+ }
+ return argumentClassArr;
+ }
+
+}
diff --git a/src/test/java/haidnor/jvm/Student.java b/src/test/java/haidnor/jvm/Student.java
new file mode 100644
index 0000000..61aa27b
--- /dev/null
+++ b/src/test/java/haidnor/jvm/Student.java
@@ -0,0 +1,6 @@
+package haidnor.jvm;
+
+public class Student extends SuperStudent{
+ private static String name;
+
+}
diff --git a/src/test/java/haidnor/jvm/SuperStudent.java b/src/test/java/haidnor/jvm/SuperStudent.java
new file mode 100644
index 0000000..9ebb66e
--- /dev/null
+++ b/src/test/java/haidnor/jvm/SuperStudent.java
@@ -0,0 +1,6 @@
+package haidnor.jvm;
+
+public class SuperStudent {
+ private static String name;
+
+}
diff --git a/src/test/java/haidnor/jvm/test/BCELTest.java b/src/test/java/haidnor/jvm/test/BCELTest.java
index 36a90c2..f775631 100644
--- a/src/test/java/haidnor/jvm/test/BCELTest.java
+++ b/src/test/java/haidnor/jvm/test/BCELTest.java
@@ -1,15 +1,15 @@
package haidnor.jvm.test;
-import haidnor.jvm.bcel.classfile.ClassParser;
import haidnor.jvm.bcel.classfile.JavaClass;
+import haidnor.jvm.classloader.JVMClassLoader;
-import java.io.FileInputStream;
import java.io.IOException;
public class BCELTest {
public static void main(String[] args) throws IOException {
- ClassParser classParser = new ClassParser(new FileInputStream("D:\\project_javaXL\\xuanleOa\\project-main\\target\\classes\\com\\xuanleOa\\XuanleOaApplication.class"), null);
- JavaClass javaClass = classParser.parse();
- System.out.println(javaClass);
+ JVMClassLoader classLoader = new JVMClassLoader("JVMClassLoader");
+ JavaClass javaClass = classLoader.loadWithAbsolutePath("D:\\project_haidnor\\haidnorJVM\\target\\test-classes\\haidnor\\jvm\\Student.class");
+
+ System.out.println(javaClass.getStaticJavaFieldMap());
}
}