// This is not visible outside the // package. It is used to // handle the various types // of operands used by Insns. package jas; import java.io.*; abstract class InsnOperand { abstract void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError; abstract int size(ClassEnv e, CodeAttr code) throws jasError; abstract void resolve(ClassEnv e); void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { return; } } // Used to implement targets of Insns class LabelOperand extends InsnOperand { Label target; Insn source; boolean wide; int ref; LabelOperand(Label l, Insn source, int line) { target = l; this.source = source; this.wide = false; this.ref = line; } LabelOperand(Label l, Insn source, boolean wide, int line) { target = l; this.source = source; this.wide = wide; this.ref = line; } int size(ClassEnv ce, CodeAttr code) { if (wide) return 4; else return 2; } void resolve(ClassEnv e) { return; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { if (wide) { target.writeWideOffset(ce, source, out); } else { int offset = ce.getPc(target); if (source != null) offset -= ce.getPc(source); if (offset > 32767 || offset < -32768) throw new jasError ("reference from line " +ref+ " exceed size for short"); target.writeOffset(ce, source, out); } } } class UnsignedByteOperand extends InsnOperand { int val; UnsignedByteOperand(int n) { val = n; } int size(ClassEnv ce, CodeAttr code) { return 1; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { if (val >= 256) throw new jasError("Operand is too large (" +val+ ") for this instruction"); out.writeByte((byte)(0xff & val)); } void resolve(ClassEnv e) { return; } } // This (conditionally) adds a wide // prefix if the value is larger than // 256 class UnsignedByteWideOperand extends InsnOperand implements RuntimeConstants { int val; boolean Wide; UnsignedByteWideOperand(int n, boolean Wide) { val = n; this.Wide = (Wide || val > 255); } int size(ClassEnv ce, CodeAttr code) { return Wide ? 3: 1; } void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { if (Wide) out.writeByte((byte)(opc_wide)); } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { if (Wide) out.writeShort((short)(0xffff & val)); else out.writeByte((byte)(val & 0xff)); } void resolve(ClassEnv e) { return; } } class ByteOperand extends InsnOperand { int val; ByteOperand(int n) { val = n; } int size(ClassEnv ce, CodeAttr code) { return 1; } void resolve(ClassEnv e) { return; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { out.writeByte((byte)val); } } class IntegerOperand extends InsnOperand { int val; IntegerOperand(int n) { val = n; } int size(ClassEnv ce, CodeAttr code) { return 4; } void resolve(ClassEnv e) { return; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { out.writeInt(val); } } class ShortOperand extends InsnOperand { int offset; ShortOperand(int n) { offset = n; } void resolve(ClassEnv e) { return; } int size(ClassEnv ce, CodeAttr code) { return 2; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { out.writeShort((short)offset); } } class CPOperand extends InsnOperand { CP cpe; boolean wide; int size(ClassEnv ce, CodeAttr code) { if (wide) return 2; else return 1; } CPOperand(CP cpe) { this.cpe = cpe; wide = true; } CPOperand(CP cpe, boolean wide) { this.cpe = cpe; this.wide = wide; } void resolve(ClassEnv e) { e.addCPItem(cpe); } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { int idx = e.getCPIndex(cpe); if (wide) { out.writeShort((short) idx); } else { if (idx > 255) { throw new jasError("exceeded size for small cpidx" + cpe); } out.writeByte((byte) (0xff & (idx))); } } } // these are unique enough that // they need a separate handler for their // args class LdcOperand extends InsnOperand implements RuntimeConstants { CP cpe; Insn source; boolean wide; int size(ClassEnv ce, CodeAttr code) throws jasError { if (wide) { return 2; } else { // Should we promote it? int idx = ce.getCPIndex(cpe); if (idx > 255) { wide = true; source.opc = opc_ldc_w; return 2; } return 1; } } LdcOperand(Insn s, CP cpe) { source = s; this.cpe = cpe; wide = true; } LdcOperand(Insn s, CP cpe, boolean wide) { source = s; this.cpe = cpe; this.wide = wide; } void resolve(ClassEnv e) { e.addCPItem(cpe); } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { int idx = e.getCPIndex(cpe); if (wide) { out.writeShort((short) idx); } else { if (idx > 255) { throw new jasError("exceeded size for small cpidx" + cpe); } out.writeByte((byte) (0xff & (idx))); } } } class InvokeinterfaceOperand extends InsnOperand { CP cpe; int nargs; InvokeinterfaceOperand(CP cpe, int nargs) { this.cpe = cpe; this.nargs = nargs; } int size(ClassEnv ce, CodeAttr code) { return 4; } void resolve(ClassEnv e) { e.addCPItem(cpe); } void write (ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { out.writeShort(e.getCPIndex(cpe)); out.writeByte((byte) (0xff & nargs)); out.writeByte(0); } } class IincOperand extends InsnOperand implements RuntimeConstants { int vindex, constt; boolean Wide; IincOperand(int vindex, int constt, boolean Wide) { this.vindex = vindex; this.constt = constt; this.Wide = (Wide || vindex > 255 || constt > 127 || constt < 127); } int size(ClassEnv ce, CodeAttr code) { return Wide ? 5 : 2; } void resolve(ClassEnv e) { return; } void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { if (Wide) out.writeByte((byte)opc_wide); } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException { if (Wide) { out.writeShort((short)(0xffff & vindex)); out.writeShort((short)(0xffff & constt)); } else { out.writeByte((byte) (0xff & vindex)); out.writeByte((byte) (0xff & constt)); } } } class MultiarrayOperand extends InsnOperand { CP cpe; int sz; MultiarrayOperand(CP cpe, int sz) { this.cpe = cpe; this.sz = sz; } void resolve(ClassEnv e) { e.addCPItem(cpe); } int size(ClassEnv ce, CodeAttr code) { return 3; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { out.writeShort(e.getCPIndex(cpe)); out.writeByte((byte)(0xff & sz)); } } class LookupswitchOperand extends InsnOperand { LabelOrOffset dflt; Insn source; int match[]; LabelOrOffset jmp[]; LookupswitchOperand(Insn s, LabelOrOffset def, int m[], LabelOrOffset j[]) { dflt = def; jmp = j; match = m; source = s; } void resolve (ClassEnv e) { return; } int size(ClassEnv ce, CodeAttr code) throws jasError { int sz = 8; // 4 + 4 + padding + jumptable int source_pc = code.getPc(source); if (((source_pc+1) % 4) != 0) { // need padding sz += (4 - ((source_pc+1) % 4)); } if (jmp != null) { sz += 8*(jmp.length); } return sz; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { int pad; int source_pc = ce.getPc(source); if (((source_pc+1) % 4) != 0) { // need padding pad = (4 - ((source_pc+1) % 4)); for (int x=0; x<pad; x++) out.writeByte(0); } // write offset to default // as a 4 byte signed value dflt.writeWideOffset(ce, source, out); if (jmp == null) { out.writeInt(0); } else { out.writeInt(jmp.length); for (int x=0; x<jmp.length; x++) { out.writeInt(match[x]); jmp[x].writeWideOffset(ce, source, out); } } } } class TableswitchOperand extends InsnOperand { int min, max; LabelOrOffset dflt; LabelOrOffset jmp[]; Insn source; TableswitchOperand(Insn s,int min, int max, LabelOrOffset def, LabelOrOffset j[]) { this.min = min; this.max = max; dflt = def; jmp = j; source = s; } void resolve(ClassEnv e) { return; } int size(ClassEnv ce, CodeAttr code) throws jasError // the *real* reason for making it a // method.. { int sz = 12; // 4+4+4+jmptable+padding... int source_pc = code.getPc(source); if (((source_pc+1) % 4) != 0) { // need padding sz += (4 - ((source_pc+1) % 4)); } if (jmp != null) { sz += 4*(jmp.length); } return sz; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { int pad; int source_pc = ce.getPc(source); if (((source_pc+1) % 4) != 0) { // need padding pad = (4 - ((source_pc+1) % 4)); for (int x=0; x<pad; x++) out.writeByte(0); } dflt.writeWideOffset(ce, source, out); out.writeInt(min); out.writeInt(max); int cnt = jmp.length; for (int x=0; x<cnt; x++) { jmp[x].writeWideOffset(ce, source, out); } } } class OffsetOperand extends InsnOperand { int val; boolean wide; Insn parent; OffsetOperand(Insn parent, int val) { this(parent, val, false); } OffsetOperand(Insn parent, int val, boolean wide) { this.parent = parent; this.val = val; this.wide = wide; } void resolve(ClassEnv e) { return; } int size(ClassEnv e, CodeAttr ce) { return wide ? 4 : 2; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { if(wide) out.writeInt(val); else out.writeShort(val); } } class RelativeOffsetOperand extends InsnOperand { int val; boolean wide; Insn parent; RelativeOffsetOperand(Insn parent, int val) { this(parent, val, false); } RelativeOffsetOperand(Insn parent, int val, boolean wide) { this.parent = parent; this.val = val; this.wide = wide; } void resolve(ClassEnv e) { return; } int size(ClassEnv e, CodeAttr ce) { return wide ? 4 : 2; } void write(ClassEnv e, CodeAttr ce, DataOutputStream out) throws IOException, jasError { if(wide) out.writeInt(val); else out.writeShort(val); } } /* --- Revision History --------------------------------------------------- --- Iouri Kharon, Aug 10 2006 Added 'Wide' prefix support to IincOperand and UnsideWideOperand */