X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fclassgen%2FMethodGen.java;h=3405fc943c70d291326c868cc92e7e1b25cc02c3;hb=069115fd4de6720de0a4a1ee37f05fec438fc325;hp=acb6c5cb3fd2bc1fcbf1abec95903742e0aa13eb;hpb=1be1acc8b4262fd60e615446a866dc5c54eb0a45;p=org.ibex.classgen.git diff --git a/src/org/ibex/classgen/MethodGen.java b/src/org/ibex/classgen/MethodGen.java index acb6c5c..3405fc9 100644 --- a/src/org/ibex/classgen/MethodGen.java +++ b/src/org/ibex/classgen/MethodGen.java @@ -25,7 +25,8 @@ public class MethodGen implements CGConst { private byte[] op; private Object[] arg; private ConstantPool.Ent[] cparg; - + + // Constructors ////////////////////////////////////////////////////////////////////////////// MethodGen(Type.Class.Method method, int flags) { @@ -38,7 +39,7 @@ public class MethodGen implements CGConst { if (((flags & INTERFACE) != 0) || (flags & (ABSTRACT|NATIVE)) != 0) size = capacity = -1; - maxLocals = Math.max(args.length + (flags&STATIC)==0 ? 1 : 0, 4); + maxLocals = Math.max(method.getNumArgs() + (flags&STATIC)==0 ? 1 : 0, 4); } MethodGen(Type.Class c, DataInput in, ConstantPool cp) throws IOException { @@ -142,12 +143,14 @@ public class MethodGen implements CGConst { ConstantPool.Ent ent = cp.getByIndex(in.readUnsignedShort()); if (ent.tag != CONSTANT_INTERFACEMETHODREF) throw new ClassFile.ClassReadExn("illegal argument to bytecode"); arg = ((ConstantPool.InterfaceMethodKey)ent.key()).method; - if (in.readByte() == 0 || in.readByte() != 0) throw new ClassFile.ClassReadExn("illegal count or 0 arg to invokeinterface"); + if (in.readByte() == 0 || in.readByte() != 0) + throw new ClassFile.ClassReadExn("illegal count or 0 arg to invokeinterface"); break; } default: if ((opdata&OP_CPENT_FLAG)!=0) { - ConstantPool.Ent ent = cp.getByIndex(argLength == 2 ? in.readUnsignedShort() : argLength == 1 ? in.readUnsignedByte() : -1); + ConstantPool.Ent ent = + cp.getByIndex(argLength == 2 ? in.readUnsignedShort() : argLength == 1 ? in.readUnsignedByte() : -1); int tag = ent.tag; Object key = ent.key(); switch(op) { @@ -163,25 +166,32 @@ public class MethodGen implements CGConst { case CONSTANT_CLASS: break; default: - throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + Integer.toString(op&0xff,16)); + throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + + Integer.toString(op&0xff,16)); } break; case GETSTATIC: case PUTSTATIC: case GETFIELD: case PUTFIELD: - if (tag != CONSTANT_FIELDREF) throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + Integer.toString(op&0xff,16)); + if (tag != CONSTANT_FIELDREF) + throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + + Integer.toString(op&0xff,16)); break; case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: - if (tag != CONSTANT_METHODREF) throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + Integer.toString(op&0xff,16)); + if (tag != CONSTANT_METHODREF) + throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + + Integer.toString(op&0xff,16)); break; case NEW: case ANEWARRAY: case CHECKCAST: case INSTANCEOF: - if (tag != CONSTANT_CLASS) throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + Integer.toString(op&0xff,16)); + if (tag != CONSTANT_CLASS) + throw new ClassFile.ClassReadExn("illegal argument to bytecode 0x" + + Integer.toString(op&0xff,16)); break; default: throw new Error("should never happen"); @@ -211,7 +221,8 @@ public class MethodGen implements CGConst { Switch si = (Switch) arg[i]; int pos = map[si.getDefaultTarget()]; - if (pos < 0) throw new ClassFile.ClassReadExn("default target points to invalid bytecode: " + si.getDefaultTarget()); + if (pos < 0) + throw new ClassFile.ClassReadExn("default target points to invalid bytecode: " + si.getDefaultTarget()); si.setDefaultTarget(pos); for(int j=0;jpos to op */ public final void set(int pos, byte op) { this.op[pos] = op; } @@ -326,12 +339,16 @@ public class MethodGen implements CGConst { @return The position of the new bytecode */ public final int add(byte op, Object arg) { if (capacity == size) grow(); set(size, op, arg); return size++; } + /** Adds a bytecode with a boolean argument - equivalent to add(op, arg?1:0); @return The position of the new bytecode @see #add(byte, int) */ public final int add(byte op, boolean arg) { if (capacity == size) grow(); set(size, op, arg); return size++; } - /** Adds a bytecode with an integer argument. This is equivalent to add(op, new Integer(arg)), but optimized to prevent the allocation when possible + + /** Adds a bytecode with an integer argument. This is equivalent + * to add(op, new Integer(arg)), but optimized to prevent the + * allocation when possible @return The position of the new bytecode @see #add(byte, Object) */ @@ -350,13 +367,15 @@ public class MethodGen implements CGConst { */ public final Object getArg(int pos) { return arg[pos]; } - /** Sets the argument for pos to arg. This is equivalent to set(pos, op, new Integer(arg)), but optimized to prevent the allocation when possible. + /** Sets the argument for pos to arg. This is + * equivalent to set(pos, op, new Integer(arg)), but optimized to + * prevent the allocation when possible. @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size() @see #setArg(int, Object) */ public final void setArg(int pos, int arg) { set(pos, op[pos], N(arg)); } + /** Sets the argument for pos to arg. - @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size() - */ + @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size() */ public final void setArg(int pos, Object arg) { set(pos, op[pos], arg); } /** Sets the bytecode and argument at pos to op and arg respectivly. @@ -450,6 +469,20 @@ public class MethodGen implements CGConst { this.arg[pos] = arg; } + /** Sets the maximum number of locals in the function to + maxLocals. NOTE: This defaults to 0 and is + automatically increased as necessary when *LOAD/*STORE + bytecodes are added. You do not need to call this function in + most cases */ + public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; } + + /** Sets the maxinum size of th stack for this function to + * maxStack. This defaults to 16< */ + public void setMaxStack(int maxStack) { this.maxStack = maxStack; } + + + // Bytecode-Specific inner classes //////////////////////////////////////////////////////////////////////////////// + public static abstract class Switch { public final Object[] targets; public Object defaultTarget; @@ -480,7 +513,7 @@ public class MethodGen implements CGConst { int length() { return 12 + targets.length * 4; } // 4bytes/target, hi, lo, default } - public static class Lookup extends Table { + public static class Lookup extends Switch { public final int[] vals; public Lookup(int size) { super(size); @@ -512,12 +545,23 @@ public class MethodGen implements CGConst { Wide(byte op, int varNum) { this(op, varNum, 0); } Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; } } - - /** Sets the maximum number of locals in the function to maxLocals. NOTE: This defaults to 0 and is automatically increased as - necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */ - public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; } - /** Sets the maxinum size of th stack for this function to maxStack. This defaults to 16< */ - public void setMaxStack(int maxStack) { this.maxStack = maxStack; } + + + // Emitting Bits ////////////////////////////////////////////////////////////////////////////// + + private Object resolveTarget(Object arg) { + int target; + if (arg instanceof PhantomTarget) { + target = ((PhantomTarget)arg).getTarget(); + if (target == -1) throw new IllegalStateException("unresolved phantom target"); + arg = N(target); + } else { + target = ((Integer)arg).intValue(); + } + if (target < 0 || target >= size) + throw new IllegalStateException("invalid target address " + target + "/" + size); + return arg; + } /** Computes the final bytecode for this method. @exception IllegalStateException if the data for a method is in an inconsistent state (required arguments missing, etc) @@ -569,21 +613,7 @@ public class MethodGen implements CGConst { } } } - - private Object resolveTarget(Object arg) { - int target; - if (arg instanceof PhantomTarget) { - target = ((PhantomTarget)arg).getTarget(); - if (target == -1) throw new IllegalStateException("unresolved phantom target"); - arg = N(target); - } else { - target = ((Integer)arg).intValue(); - } - if (target < 0 || target >= size) - throw new IllegalStateException("invalid target address " + target + "/" + size); - return arg; - } - + private void generateCode(ConstantPool cp) { try { _generateCode(cp); @@ -815,10 +845,12 @@ public class MethodGen implements CGConst { } else { int iarg = ((Integer)arg).intValue(); if (argLength == 1) { - if ((opdata & OP_UNSIGNED_FLAG) != 0 ? iarg >= 256 : (iarg < -128 || iarg >= 128)) throw new ClassFile.Exn("overflow of s/u1 option"); + if ((opdata & OP_UNSIGNED_FLAG) != 0 ? iarg >= 256 : (iarg < -128 || iarg >= 128)) + throw new ClassFile.Exn("overflow of s/u1 option"); o.writeByte(iarg); } else if (argLength == 2) { - if ((opdata & OP_UNSIGNED_FLAG) != 0 ? iarg >= 65536 : (iarg < -32768 || iarg >= 32768)) throw new ClassFile.Exn("overflow of s/u2 option"); + if ((opdata & OP_UNSIGNED_FLAG) != 0 ? iarg >= 65536 : (iarg < -32768 || iarg >= 32768)) + throw new ClassFile.Exn("overflow of s/u2 option"); o.writeShort(iarg); } else { throw new Error("should never happen"); @@ -863,32 +895,10 @@ public class MethodGen implements CGConst { attrs.dump(o,cp); } - /** Negates the IF* instruction, op (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ, etc) - @exception IllegalArgumentException if op isn't an IF* instruction */ - public static byte negate(byte op) { - switch(op) { - case IFEQ: return IFNE; - case IFNE: return IFEQ; - case IFLT: return IFGE; - case IFGE: return IFLT; - case IFGT: return IFLE; - case IFLE: return IFGT; - case IF_ICMPEQ: return IF_ICMPNE; - case IF_ICMPNE: return IF_ICMPEQ; - case IF_ICMPLT: return IF_ICMPGE; - case IF_ICMPGE: return IF_ICMPLT; - case IF_ICMPGT: return IF_ICMPLE; - case IF_ICMPLE: return IF_ICMPGT; - case IF_ACMPEQ: return IF_ACMPNE; - case IF_ACMPNE: return IF_ACMPEQ; - - default: - throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op)); - } - } - - /** Class that represents a target that isn't currently know. The target MUST be set with setTarget() before the classfile is written. - This class is more or less a mutable integer */ + + /** Class that represents a target that isn't currently know. The + target MUST be set with setTarget() before the classfile is + written. This class is more or less a mutable integer */ public static class PhantomTarget { private int target = -1; public void setTarget(int target) { this.target = target; } @@ -1012,4 +1022,31 @@ public class MethodGen implements CGConst { } } + // Unused ////////////////////////////////////////////////////////////////////////////// + + /** Negates the IF* instruction, op (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ, etc) + @exception IllegalArgumentException if op isn't an IF* instruction */ + public static byte negate(byte op) { + switch(op) { + case IFEQ: return IFNE; + case IFNE: return IFEQ; + case IFLT: return IFGE; + case IFGE: return IFLT; + case IFGT: return IFLE; + case IFLE: return IFGT; + case IF_ICMPEQ: return IF_ICMPNE; + case IF_ICMPNE: return IF_ICMPEQ; + case IF_ICMPLT: return IF_ICMPGE; + case IF_ICMPGE: return IF_ICMPLT; + case IF_ICMPGT: return IF_ICMPLE; + case IF_ICMPLE: return IF_ICMPGT; + case IF_ACMPEQ: return IF_ACMPNE; + case IF_ACMPNE: return IF_ACMPEQ; + + default: + throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op)); + } + } + + }