/* --- Copyright (c) Chris Rathman 1999. All rights reserved. ----------------- > File: jasper/Code_Collection.java > Purpose: Collection of code defined for a method > Author: Chris Rathman, 12 June 1999 > Version: 1.00 */ package jasper; import java.io.*; import java.lang.reflect.*; /*======================================================================= = Class: Code_Collection = = = = Desc: java bytecode for the method = =======================================================================*/ class Code_Collection extends Attribute { private int pcReturnLabel = 0; // program counter if end method label needed private short maxStack; // max stack space for method private short maxLocals; // max local variable index private int codeLength; // length of code block private java.util.Vector code = new java.util.Vector(); // collection of code operations private TryCatch_Collection trycatches; // try catch blocks private Attribute_Collection attributes; // code attributes // (LineNumberTable, LocalVariableTable) /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the code for the method from the input stream - -----------------------------------------------------------------------*/ Code_Collection(DataInputStream ios, Pool_Collection pool, int attribute_index) throws IOException { // set the common variables for attributes super(ios, pool, attribute_index); // get the max stack space maxStack = ios.readShort(); // get the max number for local variable index maxLocals = ios.readShort(); // get the length of the code block codeLength = ios.readInt(); // read in the individual code operations for (int i = 0, pc = 0; pc < codeLength; i++) { // get the opcode for the instruction int opcode = ios.read(); Code myCode; if (dispatch[opcode][3] == null) { // create instance of Code class myCode = new Code(ios, pool, opcode, pc); } else { // create instance of a Code subclass try { Constructor myConstructor; // get subclass that handles the opcode Class newClass = (Class)dispatch[opcode][3]; try { // for some reason this technique is not working in JDK1.2? myConstructor = newClass.getConstructor(new Class[] {ios.getClass(), pool.getClass(), int.class, int.class}); } catch (NoSuchMethodException e) { // since there is only one constructor, we can use this technique if above fails myConstructor = newClass.getDeclaredConstructors()[0]; } // read in the bytecode instruction myCode = (Code)myConstructor.newInstance(new Object[] {ios, pool, new Integer(opcode), new Integer(pc)}); } catch (InstantiationException e) { throw new IOException("InstantiationException"); } catch (IllegalAccessException e) { throw new IOException("IllegalAccessException"); } catch (InvocationTargetException e) { throw new IOException("InvocationTargetException"); } } // increment the program counter by number of bytes occupied by the instruction pc += myCode.opbytes; // add code class to the collection code.addElement(myCode); } // read in the try catch definitions trycatches = new TryCatch_Collection(ios, pool); // get the attributes associated with this code (LineNumberTable, LocalVariableTable) attributes = new Attribute_Collection(ios, pool); // now iterate through the collection and find where in the code block labels are needed for (int i = 0; i < code.size(); i++) { Code myCode = ((Code)code.elementAt(i)); myCode.getLabel(this); } trycatches.getLabel(this); attributes.getLabel(this); } /*----------------------------------------------------------------------- - Method: setLabel - - - - Desc: set the code to print label at given program counter - -----------------------------------------------------------------------*/ int setLabel(int pc) { int maxPC = 0; // initialize the maximum PC for (int i = 0; i < code.size(); i++) { Code myCode = (Code)code.elementAt(i); maxPC = myCode.setLabel(pc); // get the PC of the next instruction } if (pc > maxPC) pcReturnLabel = pc; // if pc exceeds code range then set end method pc return pc; } /*----------------------------------------------------------------------- - Method: toLabel - - - - Desc: return label string - -----------------------------------------------------------------------*/ static String toLabel(int pc) { return "LABEL0x" + Integer.toHexString(pc); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the instructions of the method - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) throws IOException { // output the .limit directives out.println(ClassFile.pad(" .limit stack", ClassFile.SPACER) + maxStack); out.println(ClassFile.pad(" .limit locals", ClassFile.SPACER) + maxLocals); // output the .var and .throws directives attributes.jasmin(out); // output the opcode instructions for (int k = 0; k < code.size(); k++) { // get current code instruction Code myCode = (Code)code.elementAt(k); // get lines associated with current code pc int[] lines = attributes.getLineNumberTable(myCode.pc); // output the .line directives if associated source lines found if (lines != null) { for (int i = 0; i < lines.length; i++) { out.println(ClassFile.pad(" .line", ClassFile.SPACER) + lines[i]); } } // output the instruction myCode.jasmin(out); out.println(""); } // if label need for end method, then output the label if (pcReturnLabel > 0) out.println(toLabel(pcReturnLabel) + ":"); // output the .catch directives trycatches.jasmin(out); } /*----------------------------------------------------------------------- - Method: browseFieldrefs - - - - Desc: ask the code what fields are referenced - -----------------------------------------------------------------------*/ String[] browseFieldrefs() { java.util.Vector x = new java.util.Vector(); for (int i = 0; i < code.size(); i++) { Code myCode = (Code)code.elementAt(i); int cptIndex = myCode.browseFieldref(); if (cptIndex > 0) { boolean found = false; String s = pool.browseString(cptIndex); for (int j = 0; j < x.size(); j++) { if (((String)x.elementAt(j)).equals(s)) { found = true; break; } } if (!found) x.add(pool.browseString(cptIndex)); } } String[] retVal = new String[x.size()]; x.copyInto(retVal); return retVal; } /*----------------------------------------------------------------------- - Method: browseMethodrefs - - - - Desc: ask the code what methods are referenced - -----------------------------------------------------------------------*/ String[] browseMethodrefs() { java.util.Vector x = new java.util.Vector(); for (int i = 0; i < code.size(); i++) { Code myCode = (Code)code.elementAt(i); int cptIndex = myCode.browseMethodref(); if (cptIndex > 0) { boolean found = false; String s = pool.browseString(cptIndex); for (int j = 0; j < x.size(); j++) { if (((String)x.elementAt(j)).equals(s)) { found = true; break; } } if (!found) x.add(pool.browseString(cptIndex)); } } String[] retVal = new String[x.size()]; x.copyInto(retVal); return retVal; } /*----------------------------------------------------------------------- - Method: browseInterfaceMethodrefs - - - - Desc: ask the code what interface methods are referenced - -----------------------------------------------------------------------*/ String[] browseInterfaceMethodrefs() { java.util.Vector x = new java.util.Vector(); for (int i = 0; i < code.size(); i++) { Code myCode = (Code)code.elementAt(i); int cptIndex = myCode.browseInterfaceMethodref(); if (cptIndex > 0) { boolean found = false; String s = pool.browseString(cptIndex); for (int j = 0; j < x.size(); j++) { if (((String)x.elementAt(j)).equals(s)) { found = true; break; } } if (!found) x.add(pool.browseString(cptIndex)); } } String[] retVal = new String[x.size()]; x.copyInto(retVal); return retVal; } /*----------------------------------------------------------------------- - Field: dispatch - - - - Desc: array used to dispatch for object instantiation - - element[i][0] = opcode (same as array index) - - element[i][1] = number of bytes for operation - - element[i][2] = bytecode operation - - element[i][3] = subclass for opcode (null = Code) - -----------------------------------------------------------------------*/ static Object[][] dispatch = { {"0x00", "1", "nop", null}, {"0x01", "1", "aconst_null", null}, {"0x02", "1", "iconst_m1", null}, {"0x03", "1", "iconst_0", null}, {"0x04", "1", "iconst_1", null}, {"0x05", "1", "iconst_2", null}, {"0x06", "1", "iconst_3", null}, {"0x07", "1", "iconst_4", null}, {"0x08", "1", "iconst_5", null}, {"0x09", "1", "lconst_0", null}, {"0x0a", "1", "lconst_1", null}, {"0x0b", "1", "fconst_0", null}, {"0x0c", "1", "fconst_1", null}, {"0x0d", "1", "fconst_2", null}, {"0x0e", "1", "dconst_0", null}, {"0x0f", "1", "dconst_1", null}, {"0x10", "2", "bipush", Code_bipush.class}, {"0x11", "3", "sipush", Code_sipush.class}, {"0x12", "2", "ldc", Code_ldc.class}, {"0x13", "3", "ldc_w", Code_Pool.class}, {"0x14", "3", "ldc2_w", Code_Pool.class}, {"0x15", "2", "iload", Code_VarTable.class}, {"0x16", "2", "lload", Code_VarTable.class}, {"0x17", "2", "fload", Code_VarTable.class}, {"0x18", "2", "dload", Code_VarTable.class}, {"0x19", "2", "aload", Code_VarTable.class}, {"0x1a", "1", "iload_0", null}, {"0x1b", "1", "iload_1", null}, {"0x1c", "1", "iload_2", null}, {"0x1d", "1", "iload_3", null}, {"0x1e", "1", "lload_0", null}, {"0x1f", "1", "lload_1", null}, {"0x20", "1", "lload_2", null}, {"0x21", "1", "lload_3", null}, {"0x22", "1", "fload_0", null}, {"0x23", "1", "fload_1", null}, {"0x24", "1", "fload_2", null}, {"0x25", "1", "fload_3", null}, {"0x26", "1", "dload_0", null}, {"0x27", "1", "dload_1", null}, {"0x28", "1", "dload_2", null}, {"0x29", "1", "dload_3", null}, {"0x2a", "1", "aload_0", null}, {"0x2b", "1", "aload_1", null}, {"0x2c", "1", "aload_2", null}, {"0x2d", "1", "aload_3", null}, {"0x2e", "1", "iaload", null}, {"0x2f", "1", "laload", null}, {"0x30", "1", "faload", null}, {"0x31", "1", "daload", null}, {"0x32", "1", "aaload", null}, {"0x33", "1", "baload", null}, {"0x34", "1", "caload", null}, {"0x35", "1", "saload", null}, {"0x36", "2", "istore", Code_VarTable.class}, {"0x37", "2", "lstore", Code_VarTable.class}, {"0x38", "2", "fstore", Code_VarTable.class}, {"0x39", "2", "dstore", Code_VarTable.class}, {"0x3a", "2", "astore", Code_VarTable.class}, {"0x3b", "1", "istore_0", null}, {"0x3c", "1", "istore_1", null}, {"0x3d", "1", "istore_2", null}, {"0x3e", "1", "istore_3", null}, {"0x3f", "1", "lstore_0", null}, {"0x40", "1", "lstore_1", null}, {"0x41", "1", "lstore_2", null}, {"0x42", "1", "lstore_3", null}, {"0x43", "1", "fstore_0", null}, {"0x44", "1", "fstore_1", null}, {"0x45", "1", "fstore_2", null}, {"0x46", "1", "fstore_3", null}, {"0x47", "1", "dstore_0", null}, {"0x48", "1", "dstore_1", null}, {"0x49", "1", "dstore_2", null}, {"0x4a", "1", "dstore_3", null}, {"0x4b", "1", "astore_0", null}, {"0x4c", "1", "astore_1", null}, {"0x4d", "1", "astore_2", null}, {"0x4e", "1", "astore_3", null}, {"0x4f", "1", "iastore", null}, {"0x50", "1", "lastore", null}, {"0x51", "1", "fastore", null}, {"0x52", "1", "dastore", null}, {"0x53", "1", "aastore", null}, {"0x54", "1", "bastore", null}, {"0x55", "1", "castore", null}, {"0x56", "1", "sastore", null}, {"0x57", "1", "pop", null}, {"0x58", "1", "pop2", null}, {"0x59", "1", "dup", null}, {"0x5a", "1", "dup_x1", null}, {"0x5b", "1", "dup_x2", null}, {"0x5c", "1", "dup2", null}, {"0x5d", "1", "dup2_x1", null}, {"0x5e", "1", "dup2_x2", null}, {"0x5f", "1", "swap", null}, {"0x60", "1", "iadd", null}, {"0x61", "1", "ladd", null}, {"0x62", "1", "fadd", null}, {"0x63", "1", "dadd", null}, {"0x64", "1", "isub", null}, {"0x65", "1", "lsub", null}, {"0x66", "1", "fsub", null}, {"0x67", "1", "dsub", null}, {"0x68", "1", "imul", null}, {"0x69", "1", "lmul", null}, {"0x6a", "1", "fmul", null}, {"0x6b", "1", "dmul", null}, {"0x6c", "1", "idiv", null}, {"0x6d", "1", "ldiv", null}, {"0x6e", "1", "fdiv", null}, {"0x6f", "1", "ddiv", null}, {"0x70", "1", "irem", null}, {"0x71", "1", "lrem", null}, {"0x72", "1", "frem", null}, {"0x73", "1", "drem", null}, {"0x74", "1", "ineg", null}, {"0x75", "1", "lneg", null}, {"0x76", "1", "fneg", null}, {"0x77", "1", "dneg", null}, {"0x78", "1", "ishl", null}, {"0x79", "1", "lshl", null}, {"0x7a", "1", "ishr", null}, {"0x7b", "1", "lshr", null}, {"0x7c", "1", "iushr", null}, {"0x7d", "1", "lushr", null}, {"0x7e", "1", "iand", null}, {"0x7f", "1", "land", null}, {"0x80", "1", "ior", null}, {"0x81", "1", "lor", null}, {"0x82", "1", "ixor", null}, {"0x83", "1", "lxor", null}, {"0x84", "3", "iinc", Code_iinc.class}, {"0x85", "1", "i2l", null}, {"0x86", "1", "i2f", null}, {"0x87", "1", "i2d", null}, {"0x88", "1", "l2i", null}, {"0x89", "1", "l2f", null}, {"0x8a", "1", "l2d", null}, {"0x8b", "1", "f2i", null}, {"0x8c", "1", "f2l", null}, {"0x8d", "1", "f2d", null}, {"0x8e", "1", "d2i", null}, {"0x8f", "1", "d2l", null}, {"0x90", "1", "d2f", null}, {"0x91", "1", "i2b", null}, {"0x92", "1", "i2c", null}, {"0x93", "1", "i2s", null}, {"0x94", "1", "lcmp", null}, {"0x95", "1", "fcmpl", null}, {"0x96", "1", "fcmpg", null}, {"0x97", "1", "dcmpl", null}, {"0x98", "1", "dcmpg", null}, {"0x99", "3", "ifeq", Code_Branch.class}, {"0x9a", "3", "ifne", Code_Branch.class}, {"0x9b", "3", "iflt", Code_Branch.class}, {"0x9c", "3", "ifge", Code_Branch.class}, {"0x9d", "3", "ifgt", Code_Branch.class}, {"0x9e", "3", "ifle", Code_Branch.class}, {"0x9f", "3", "if_icmpeq", Code_Branch.class}, {"0xa0", "3", "if_icmpne", Code_Branch.class}, {"0xa1", "3", "if_icmplt", Code_Branch.class}, {"0xa2", "3", "if_icmpge", Code_Branch.class}, {"0xa3", "3", "if_icmpgt", Code_Branch.class}, {"0xa4", "3", "if_icmple", Code_Branch.class}, {"0xa5", "3", "if_acmpeq", Code_Branch.class}, {"0xa6", "3", "if_acmpne", Code_Branch.class}, {"0xa7", "3", "goto", Code_Branch.class}, {"0xa8", "3", "jsr", Code_Branch.class}, {"0xa9", "2", "ret", Code_VarTable.class}, {"0xaa", "0", "tableswitch", Code_tableswitch.class}, {"0xab", "0", "lookupswitch", Code_lookupswitch.class}, {"0xac", "1", "ireturn", null}, {"0xad", "1", "lreturn", null}, {"0xae", "1", "freturn", null}, {"0xaf", "1", "dreturn", null}, {"0xb0", "1", "areturn", null}, {"0xb1", "1", "return", null}, {"0xb2", "3", "getstatic", Code_Pool.class}, {"0xb3", "3", "putstatic", Code_Pool.class}, {"0xb4", "3", "getfield", Code_Pool.class}, {"0xb5", "3", "putfield", Code_Pool.class}, {"0xb6", "3", "invokevirtual", Code_Pool.class}, {"0xb7", "3", "invokespecial", Code_Pool.class}, {"0xb8", "3", "invokestatic", Code_Pool.class}, {"0xb9", "5", "invokeinterface", Code_invokeinterface.class}, {"0xba", "1", "xxxunusedxxx", null}, {"0xbb", "3", "new", Code_Pool.class}, {"0xbc", "2", "newarray", Code_newarray.class}, {"0xbd", "3", "anewarray", Code_Pool.class}, {"0xbe", "1", "arraylength", null}, {"0xbf", "1", "athrow", null}, {"0xc0", "3", "checkcast", Code_Pool.class}, {"0xc1", "3", "instanceof", Code_Pool.class}, {"0xc2", "1", "monitorenter", null}, {"0xc3", "1", "monitorexit", null}, {"0xc4", "4", "wide", Code_wide.class}, {"0xc5", "4", "multianewarray", Code_multianewarray.class}, {"0xc6", "3", "ifnull", Code_Branch.class}, {"0xc7", "3", "ifnonnull", Code_Branch.class}, {"0xc8", "5", "goto_w", Code_BranchInt.class}, {"0xc9", "5", "jsr_w", Code_BranchInt.class}, {"0xca", "1", "breakpoint", null}, {"0xcb", "1", "xxxunusedxxx", null}, {"0xcc", "1", "xxxunusedxxx", null}, {"0xcd", "1", "xxxunusedxxx", null}, {"0xce", "1", "xxxunusedxxx", null}, {"0xcf", "1", "xxxunusedxxx", null}, {"0xd0", "1", "xxxunusedxxx", null}, {"0xd1", "1", "xxxunusedxxx", null}, {"0xd2", "1", "xxxunusedxxx", null}, {"0xd3", "1", "xxxunusedxxx", null}, {"0xd4", "1", "xxxunusedxxx", null}, {"0xd5", "1", "xxxunusedxxx", null}, {"0xd6", "1", "xxxunusedxxx", null}, {"0xd7", "1", "xxxunusedxxx", null}, {"0xd8", "1", "xxxunusedxxx", null}, {"0xd9", "1", "xxxunusedxxx", null}, {"0xda", "1", "xxxunusedxxx", null}, {"0xdb", "1", "xxxunusedxxx", null}, {"0xdc", "1", "xxxunusedxxx", null}, {"0xdd", "1", "xxxunusedxxx", null}, {"0xde", "1", "xxxunusedxxx", null}, {"0xdf", "1", "xxxunusedxxx", null}, {"0xe0", "1", "xxxunusedxxx", null}, {"0xe1", "1", "xxxunusedxxx", null}, {"0xe2", "1", "xxxunusedxxx", null}, {"0xe3", "1", "xxxunusedxxx", null}, {"0xe4", "1", "xxxunusedxxx", null}, {"0xe5", "1", "xxxunusedxxx", null}, {"0xe6", "1", "xxxunusedxxx", null}, {"0xe7", "1", "xxxunusedxxx", null}, {"0xe8", "1", "xxxunusedxxx", null}, {"0xe9", "1", "xxxunusedxxx", null}, {"0xea", "1", "xxxunusedxxx", null}, {"0xeb", "1", "xxxunusedxxx", null}, {"0xec", "1", "xxxunusedxxx", null}, {"0xed", "1", "xxxunusedxxx", null}, {"0xee", "1", "xxxunusedxxx", null}, {"0xef", "1", "xxxunusedxxx", null}, {"0xf0", "1", "xxxunusedxxx", null}, {"0xf1", "1", "xxxunusedxxx", null}, {"0xf2", "1", "xxxunusedxxx", null}, {"0xf3", "1", "xxxunusedxxx", null}, {"0xf4", "1", "xxxunusedxxx", null}, {"0xf5", "1", "xxxunusedxxx", null}, {"0xf6", "1", "xxxunusedxxx", null}, {"0xf7", "1", "xxxunusedxxx", null}, {"0xf8", "1", "xxxunusedxxx", null}, {"0xf9", "1", "xxxunusedxxx", null}, {"0xfa", "1", "xxxunusedxxx", null}, {"0xfb", "1", "xxxunusedxxx", null}, {"0xfc", "1", "xxxunusedxxx", null}, {"0xfd", "1", "xxxunusedxxx", null}, {"0xfe", "1", "impdep1", null}, {"0xff", "1", "impdep2", null} }; } /*======================================================================= = Class: Code = = = = Desc: java bytecode instruction = =======================================================================*/ class Code { protected Pool_Collection pool; // constant pool table protected String opdesc; // operation description protected int opcode; // operation code protected int opbytes = 0; // bytes that the operation occupies protected int pc = 0; // program counter for the operation protected boolean label = false; // flag whether a label should be printed at this address /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code(DataInputStream ios, Pool_Collection pool, int opcode, int pc) { // save off the constant pool table for later reference this.pool = pool; // save off the operation code this.opcode = opcode; // save off the program counter of the code this.pc = pc; // save off the description of the operation this.opdesc = (String)Code_Collection.dispatch[opcode][2]; // save off the number of bytes for the operations (note: lookupswitch & tableswitch overwrite) opbytes = Integer.parseInt((String)Code_Collection.dispatch[opcode][1]); } /*----------------------------------------------------------------------- - Method: getLabel - - - - Desc: default to no labels needed by operation - - overridden by subclass: Code_Branch; Code_BranchInt; - - Code_lookupswitch; Code_tableswitch - -----------------------------------------------------------------------*/ void getLabel(Code_Collection code) { } /*----------------------------------------------------------------------- - Method: setLabel - - - - Desc: if pc for label is pc for opcode then set label flag - -----------------------------------------------------------------------*/ int setLabel(int pc) { if (this.pc == pc) label = true; return this.pc; } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { if (label) out.println(Code_Collection.toLabel(pc) + ":"); out.print(pad(" " + jasminDesc(), ClassFile.SPACER)); } /*----------------------------------------------------------------------- - Method: jasminDesc - - - - Desc: return the operator description - - may be overriden by wide instructions - -----------------------------------------------------------------------*/ String jasminDesc() { return opdesc; } /*----------------------------------------------------------------------- - Method: browseFieldref - - - - Desc: default to no fields referenced by operation code - - overridden by subclass: Code_Pool - -----------------------------------------------------------------------*/ int browseFieldref() { return -1; } /*----------------------------------------------------------------------- - Method: browseMethodref - - - - Desc: default to no methods referenced by operation code - - overridden by subclass: Code_Pool - -----------------------------------------------------------------------*/ int browseMethodref() { return -1; } /*----------------------------------------------------------------------- - Method: browseInterfaceMethodref - - - - Desc: default to no interfaces referenced by operation code - - overridden by subclass: Code_Pool - -----------------------------------------------------------------------*/ int browseInterfaceMethodref() { return -1; } /*----------------------------------------------------------------------- - Method: pad - - - - Desc: pad a string with specified spaces. Done here to - - keep the code length manageable. - -----------------------------------------------------------------------*/ static String pad(String s, int pad) { return ClassFile.pad(s, pad); } /*----------------------------------------------------------------------- - Method: pad - - - - Desc: pad a string with specified spaces. this overload of - - the function prevents having to convert int to string - -----------------------------------------------------------------------*/ static String pad(int n, int pad) { return pad(n + "", pad); } } /*======================================================================= = Class: Code_Branch = = = = Desc: instructions which perform relative branches = = goto if_acmpeq if_acmpne = = if_icmpeq if_icmpge if_icmpgt = = if_icmple if_icmplt if_icmpne = = ifeq ifge ifgt = = ifle iflt ifne = = ifnonnull ifnull = =======================================================================*/ class Code_Branch extends Code { private int branch; // branch offset for the operation (relative to current pc) /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_Branch(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the branch offset for the operation branch = ios.readShort(); } /*----------------------------------------------------------------------- - Method: getLabel - - - - Desc: label needed for branch address - -----------------------------------------------------------------------*/ void getLabel(Code_Collection code) { code.setLabel(branch + pc); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(Code_Collection.toLabel(pc+branch)); } } /*======================================================================= = Class: Code_BranchInt = = = = Desc: instructions which perform branches (integer offset) = = goto_w jsr_w = =======================================================================*/ class Code_BranchInt extends Code { private int branch; // branch offset for the operation (relative to current pc) /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_BranchInt(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the branch offset for the operation (branch is relative to current pc) branch = ios.readInt(); } /*----------------------------------------------------------------------- - Method: getLabel - - - - Desc: label needed for branch address - -----------------------------------------------------------------------*/ void getLabel(Code_Collection code) { code.setLabel(pc+branch); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(Code_Collection.toLabel(pc+branch)); } } /*======================================================================= = Class: Code_VarTable = = = = Desc: instructions which access local variables = = aload astore dload = = dstore fload fstore = = iload istore lload = = lstore ret = =======================================================================*/ class Code_VarTable extends Code { private int lvtIndex; // index into the local variable table /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_VarTable(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the local variable table index lvtIndex = ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(lvtIndex); } } /*======================================================================= = Class: Code_Pool = = = = Desc: instructions which access the constant pool table = = anewarray checkcast getfield = = getstatic instanceof invokespecial = = invokestatic invokevirtual ldc_w = = ldc2_w new putfield = = putstatic = =======================================================================*/ class Code_Pool extends Code { private int cptIndex; // index into the constant pool table /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_Pool(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the constant pool index for the referenced constant cptIndex = ios.readShort(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(pool.toString(cptIndex)); } /*----------------------------------------------------------------------- - Method: browseFieldref - - - - Desc: check if this instruction is referencing a field - -----------------------------------------------------------------------*/ int browseFieldref() { if (pool.isFieldref(cptIndex)) return cptIndex; else return -1; } /*----------------------------------------------------------------------- - Method: browseMethodref - - - - Desc: check if this instruction is referencing a method - -----------------------------------------------------------------------*/ int browseMethodref() { if (pool.isMethodref(cptIndex)) return cptIndex; else return -1; } /*----------------------------------------------------------------------- - Method: browseInterfaceMethodref - - - - Desc: check if this instruction is referencing an interface - -----------------------------------------------------------------------*/ int browseInterfaceMethodref() { if (pool.isInterfaceMethodref(cptIndex)) return cptIndex; else return -1; } } /*======================================================================= = Class: Code_bipush = = = = Desc: push byte = =======================================================================*/ class Code_bipush extends Code { private int value; // value to push onto the stack /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_bipush(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get value being pushed value = (byte)ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(value); } } /*======================================================================= = Class: Code_iinc = = = = Desc: increment local variable by constant = =======================================================================*/ class Code_iinc extends Code_VarTable { private int value; // increment value for the operation /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_iinc(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the signed byte value for the increment value = (byte)ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(" " + value); } } /*======================================================================= = Class: Code_invokeinterface = = = = Desc: invoke interface method = =======================================================================*/ class Code_invokeinterface extends Code_Pool { private int count; // number of words to pop off the stack private int unused; /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_invokeinterface(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the number of words to pop off the operand stack count = ios.read(); // get past the unused byte unused = ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(" " + count); } } /*======================================================================= = Class: Code_ldc = = = = Desc: push item from runtime constant pool = =======================================================================*/ class Code_ldc extends Code { private int cptIndex; // index into the constant pool table /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_ldc(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the index into the constant pool table for the constant (note that index is a byte) cptIndex = ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(pool.toString(cptIndex)); } } /*======================================================================= = Class: Code_lookupswitch = = = = Desc: switch instruction for non-sequential indexes = =======================================================================*/ class Code_lookupswitch extends Code { private int lookupSkip; // number of pad bytes to allign default integer private int lookupDefault; // offset to the default handler private int count; // number of match-branch pairs private int[] match; // case values to match int private int[] branch; // offset to the handler for the match /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_lookupswitch(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // calculate the number of bytes to skip to make default offset be 4 byte alligned lookupSkip = 4 - (pc + 1) % 4; if (lookupSkip == 4) lookupSkip = 0; if (lookupSkip > 0) ios.skip(lookupSkip); // get the offset to the default handler lookupDefault = ios.readInt(); // get the number of match-branch pairs count = ios.readInt(); // allocate the arrays to hold the pairs match = new int[count]; branch = new int[count]; for (int i = 0; i < count; i++) { // get the value to match for the case match[i] = ios.readInt(); // get the branch offset for this match branch[i] = ios.readInt(); } // calculate the number of bytes that the lookupswitch occupies opbytes = 9 + lookupSkip + count*8; } /*----------------------------------------------------------------------- - Method: getLabel - - - - Desc: label needed for branch addresses - -----------------------------------------------------------------------*/ void getLabel(Code_Collection code) { for (int i = 0; i < count; i++) code.setLabel(pc+branch[i]); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.println(""); for (int i = 0; i < count; i++) { out.println(pad(" " + match[i] + " :", ClassFile.SPACER) + Code_Collection.toLabel(pc+branch[i])); } out.println(pad(" default :", ClassFile.SPACER) + Code_Collection.toLabel(pc+lookupDefault)); } } /*======================================================================= = Class: Code_multianewarray = = = = Desc: create a new multidimensional array = =======================================================================*/ class Code_multianewarray extends Code_Pool { private int dimensions; // number of dimensions to allocate for the multidimensional array /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_multianewarray(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get number dimensions to allocate dimensions = ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(" " + dimensions); } } /*======================================================================= = Class: Code_newarray = = = = Desc: create new array = =======================================================================*/ class Code_newarray extends Code { private int arrayType; // type of array to allocate /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_newarray(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the array type arrayType = ios.read(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(getArrayType(arrayType)); } /*----------------------------------------------------------------------- - Method: getArrayType - - - - Desc: get type of array being allocated - -----------------------------------------------------------------------*/ static String getArrayType(int arrayType) { String s = "unknown"; if (arrayType < arrayTypeMap.length) s = arrayTypeMap[arrayType][1]; return s; } /*----------------------------------------------------------------------- - Field: arrayTypeMap - - - - Desc: array used to determine array type from index - - element[i][0] = array type index - - element[i][1] = array type description - -----------------------------------------------------------------------*/ private static String[][] arrayTypeMap = { {"0", "unknown"}, {"1", "unknown"}, {"2", "unknown"}, {"3", "unknown"}, {"4", "boolean"}, {"5", "char"}, {"6", "float"}, {"7", "double"}, {"8", "byte"}, {"9", "short"}, {"10", "int"}, {"11", "long"}, }; } /*======================================================================= = Class: Code_sipush = = = = Desc: push short = =======================================================================*/ class Code_sipush extends Code { private int value; // short value to be pushed on stack /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_sipush(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get signed short value to push on stack value = (short)ios.readShort(); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(value); } } /*======================================================================= = Class: Code_tableswitch = = = = Desc: switch instruction for sequential indexes = =======================================================================*/ class Code_tableswitch extends Code { private int tableSkip; // number of bytes to skip to 4-byte allign the default offset private int tableDefault; // branch offset for the default handler private int tableLow; // low value for sequence of matches private int tableHigh; // high value for sequence of matches private int count; // number of cases in switch (computed internally from low & high) private int[] branch; // branch offset for match /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_tableswitch(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // calculate the number of bytes to skip to 4-byte allign the default branch offset tableSkip = 4 - (pc + 1) % 4; if (tableSkip == 4) tableSkip = 0; if (tableSkip > 0) ios.skip(tableSkip); // get the default branch offset for the default case in the switch tableDefault = ios.readInt(); // get the low value for the matches tableLow = ios.readInt(); // get the high value for the matches tableHigh = ios.readInt(); // compute the number of entries count = tableHigh - tableLow + 1; // allocate the array to hold the branch offsets branch = new int[count]; // read in the branch offsets for (int i = 0; i < count; i++) branch[i] = ios.readInt(); // calculate the number of bytes that the tableswitch operation occupies opbytes = 13 + tableSkip + count*4; } /*----------------------------------------------------------------------- - Method: getLabel - - - - Desc: label needed for branch addresses - -----------------------------------------------------------------------*/ void getLabel(Code_Collection code) { for (int i = 0; i < count; i++) code.setLabel(pc+branch[i]); } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.println(tableLow + " " + tableHigh); for (int i = 0; i < count; i++) { out.println(pad("", ClassFile.SPACER) + Code_Collection.toLabel(pc+branch[i])); } out.println(pad(" default :", ClassFile.SPACER) + Code_Collection.toLabel(pc+tableDefault)); } } /*======================================================================= = Class: Code_wide = = = = Desc: extend access of local variable index to 32 bit range = =======================================================================*/ class Code_wide extends Code { private int widecode; // opcode for the wide extended instruction private int lvtIndex; // index into the local variable table private int value; // increment value for the wide iinc operation private String wideDesc; // description of the wide extended operation /*----------------------------------------------------------------------- - Method: Class Constructor - - - - Desc: read in the instruction from the input stream - -----------------------------------------------------------------------*/ Code_wide(DataInputStream ios, Pool_Collection pool, int opcode, int pc) throws IOException { super(ios, pool, opcode, pc); // get the opcode being wide extended widecode = ios.read(); // get the index into the local variable table lvtIndex = ios.readShort(); // get the description of the wide extended opcode wideDesc = (String)Code_Collection.dispatch[lvtIndex][2]; // if the iinc is being extended, then 2 additional bytes need to be read in if (wideDesc.equals("iinc")) { // set the number of bytes occupied by the wide extended iinc opcode opbytes = 6; // read the increment value for the iinc instruction value = ios.readShort(); } } /*----------------------------------------------------------------------- - Method: jasminDesc - - - - Desc: override the operation description (don't want 'wide')- -----------------------------------------------------------------------*/ String jasminDesc() { return wideDesc; } /*----------------------------------------------------------------------- - Method: jasmin - - - - Desc: output the operation instruction to the jasmin file - -----------------------------------------------------------------------*/ void jasmin(PrintStream out) { super.jasmin(out); out.print(lvtIndex); if (wideDesc.equals("iinc")) out.print(" " + value); } }