/* --- 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);
}
}