1 package org.ibex.classgen;
6 public class MethodGen implements CGConst {
7 private final static boolean EMIT_NOPS = true;
9 private final CPGen cp;
10 private final String name;
11 private final Type ret;
12 private final Type[] args;
13 private final int flags;
14 private final AttrGen attrs;
15 private final AttrGen codeAttrs;
16 private final Hashtable exnTable = new Hashtable();
17 private final Hashtable thrownExceptions = new Hashtable();
19 private int maxStack = 16;
20 private int maxLocals;
27 MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
28 if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
29 throw new IllegalArgumentException("invalid flags");
36 attrs = new AttrGen(cp);
37 codeAttrs = new AttrGen(cp);
40 cp.addUtf8(getDescriptor());
42 if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
44 maxLocals = Math.max(args.length + (flags&ACC_STATIC)==0 ? 1 : 0,4);
47 public String getDescriptor() { return MethodRef.getDescriptor(ret,args); }
49 private class ExnTableEnt {
53 public CPGen.Ent typeEnt;
54 public ExnTableEnt(int start, int end, int handler, CPGen.Ent typeEnt) {
57 this.handler = handler;
58 this.typeEnt = typeEnt;
60 public void dump(DataOutput o, int[] pc, int endPC) throws IOException {
61 o.writeShort(pc[start]);
62 o.writeShort(end==pc.length ? endPC : pc[end]);
63 o.writeShort(pc[handler]);
64 o.writeShort(typeEnt.getIndex());
68 public final void addExceptionHandler(int startPC, int endPC, int handlerPC, Type.Object type) {
69 exnTable.put(type, new ExnTableEnt(startPC,endPC,handlerPC,cp.add(type)));
72 public final void addThrow(Type.Object type) {
73 thrownExceptions.put(type,cp.add(type));
76 private final void grow() { if(size == capacity) grow(size+1); }
77 private final void grow(int newCap) {
78 if(capacity == -1) throw new IllegalStateException("method can't have code");
79 if(newCap <= capacity) return;
80 newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
82 byte[] op2 = new byte[newCap];
83 if(capacity != 0) System.arraycopy(op,0,op2,0,size);
86 Object[] arg2 = new Object[newCap];
87 if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
92 public final int size() { return size; }
94 // FEATURE: Deprecate this
95 public final int addPushConst(int n) { return add(LDC,n); }
97 // These two are optimized for speed, they don't call set() below
98 public final int add(byte op) {
100 if(s == capacity) grow();
105 public final void set(int pos, byte op) { this.op[pos] = op; }
107 public final int add(byte op, Object arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
108 public final int add(byte op, boolean arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
109 public final int add(byte op, int arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
111 public final byte get(int pos) { return op[pos]; }
112 public final Object getArg(int pos) { return arg[pos]; }
114 public final void setArg(int pos, int arg) { set(pos,op[pos],N(arg)); }
115 public final void setArg(int pos, Object arg) { set(pos,op[pos],arg); }
118 public final void set(int pos, byte op, boolean b) { set(pos,op,b?1:0); }
119 public final void set(int pos, byte op, int n) {
122 case -1: set(pos,ICONST_M1); return;
123 case 0: set(pos,ICONST_0); return;
124 case 1: set(pos,ICONST_1); return;
125 case 2: set(pos,ICONST_2); return;
126 case 3: set(pos,ICONST_3); return;
127 case 4: set(pos,ICONST_4); return;
128 case 5: set(pos,ICONST_5); return;
131 if(n >= -128 && n <= 127) { op = BIPUSH; arg = N(n); }
132 else if(n >= -32767 && n <= 32767) { op = SIPUSH; arg = N(n); }
133 else { arg = cp.add(N(n)); }
141 public void set(int pos, byte op, Object arg) {
143 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
144 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
146 int iarg = ((Integer)arg).intValue();
147 if(iarg >= 0 && iarg <= 3) {
150 case ILOAD: base = ILOAD_0; break;
151 case ISTORE: base = ISTORE_0; break;
152 case LLOAD: base = LLOAD_0; break;
153 case LSTORE: base = LSTORE_0; break;
154 case FLOAD: base = FLOAD_0; break;
155 case FSTORE: base = FSTORE_0; break;
156 case DLOAD: base = DLOAD_0; break;
157 case DSTORE: base = DSTORE_0; break;
158 case ALOAD: base = ALOAD_0; break;
159 case ASTORE: base = ASTORE_0; break;
161 op = (byte)((base&0xff) + iarg);
163 if(iarg >= maxLocals) maxLocals = iarg + 1;
168 if(arg instanceof Integer) { set(pos,op,((Integer)arg).intValue()); return; }
169 if(arg instanceof Boolean) { set(pos,op,((Boolean)arg).booleanValue()); return; }
170 if(arg instanceof Long) {
171 long l = ((Long)arg).longValue();
172 if(l == 0L) { set(pos,LCONST_0); return; }
173 if(l == 1L) { set(pos,LCONST_1); return; }
176 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
179 int opdata = OP_DATA[op&0xff];
180 if((opdata&OP_CPENT_FLAG) != 0 && !(arg instanceof CPGen.Ent))
182 else if((opdata&OP_VALID_FLAG) == 0)
183 throw new IllegalArgumentException("unknown bytecode");
191 public static class SI {
192 public final Object[] targets;
193 public Object defaultTarget;
195 SI(int size) { targets = new Object[size]; }
196 public void setTarget(int pos, Object val) { targets[pos] = val; }
197 public void setTarget(int pos, int val) { targets[pos] = N(val); }
198 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
199 public void setDefaultTarget(Object o) { defaultTarget = o; }
200 public int size() { return targets.length; }
202 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
203 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
206 public static class TSI extends SI {
209 public int defaultTarget = -1;
210 public TSI(int lo, int hi) {
215 public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
216 public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
219 public static class LSI extends SI {
220 public final int[] vals;
221 public LSI(int size) {
223 this.vals = new int[size];
225 public final void setVal(int pos, int val) { vals[pos] = val; }
228 public static class Pair {
231 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
234 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
235 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
237 public void finish() {
240 } catch(IOException e) {
241 throw new Error("should never happen");
245 private Object resolveTarget(Object arg) {
247 if(arg instanceof PhantomTarget) {
248 target = ((PhantomTarget)arg).getTarget();
249 if(target == -1) throw new IllegalStateException("unresolved phantom target");
252 target = ((Integer)arg).intValue();
254 if(target < 0 || target >= size)
255 throw new IllegalStateException("invalid target address");
259 private void _finish() throws IOException {
260 if(size == -1) return;
262 ByteArrayOutputStream baos = new ByteArrayOutputStream();
263 DataOutput o = new DataOutputStream(baos);
265 int[] pc = new int[size];
269 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
270 for(i=0,p=0;i<size;i++) {
271 byte op = this.op[i];
272 int opdata = OP_DATA[op&0xff];
276 if((opdata & OP_BRANCH_FLAG)!= 0) {
278 arg[i] = resolveTarget(arg[i]);
279 } catch(RuntimeException e) {
280 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
296 Object[] targets = si.targets;
297 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
298 si.defaultTarget = resolveTarget(si.defaultTarget);
299 p += 1 + 3 + 4; // opcode itself, padding, default
300 if(op == TABLESWITCH) p += 4 + 4 + targets.length * 4; // lo, hi, targets
301 else p += 4 + targets.length * 4 * 2; // count, key,val * targets
305 j = ((CPGen.Ent)arg[i]).getIndex();
306 if(j >= 256) this.op[i] = op = LDC_W;
309 if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
315 // Pass2 - Widen instructions if they can possibly be too short
316 for(i=0;i<size;i++) {
320 int arg = ((Integer)this.arg[i]).intValue();
321 int diff = maxpc[arg] - maxpc[i];
322 if(diff < -32768 || diff > 32767)
323 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
329 // Pass3 - Calculate actual pc
330 for(i=0,p=0;i<size;i++) {
331 byte op = this.op[i];
340 p++; // opcpde itself
341 p = (p + 3) & ~3; // padding
343 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
344 else p += 4 + si.size() * 4 * 2; // count, key,val * targets
348 int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
349 if(l == 7) throw new Error("shouldn't be here");
357 o.writeShort(maxStack);
358 o.writeShort(maxLocals);
359 o.writeInt(codeSize);
361 // Pass 4 - Actually write the bytecodes
362 for(i=0;i<size;i++) {
363 byte op = this.op[i];
364 int opdata = OP_DATA[op&0xff];
365 if(op == NOP && !EMIT_NOPS) continue;
367 o.writeByte(op&0xff);
368 int argLength = opdata & OP_ARG_LENGTH_MASK;
370 if(argLength == 0) continue; // skip if no args
373 Object arg = this.arg[i];
377 Pair pair = (Pair) arg;
378 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
379 o.writeByte(pair.i1);
380 o.writeByte(pair.i2);
386 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
387 o.writeInt(pc[si.getDefaultTarget()] - mypc);
388 if(op == LOOKUPSWITCH) {
389 int[] vals = ((LSI)si).vals;
390 o.writeInt(si.size());
391 for(int j=0;j<si.size();j++) {
393 o.writeInt(pc[si.getTarget(j)] - mypc);
399 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
405 if((opdata & OP_BRANCH_FLAG) != 0) {
406 int v = pc[((Integer)arg).intValue()] - pc[i];
407 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
409 } else if((opdata & OP_CPENT_FLAG) != 0) {
410 int v = ((CPGen.Ent)arg).getIndex();
411 if(argLength == 1) o.writeByte(v);
412 else if(argLength == 2) o.writeShort(v);
413 else throw new Error("should never happen");
414 } else if(argLength == -1) {
415 throw new Error("should never happen - variable length instruction not explicitly handled");
417 int iarg = ((Integer)arg).intValue();
419 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
421 } else if(argLength == 2) {
422 if(iarg < -32767 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
425 throw new Error("should never happen");
432 //if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
434 o.writeShort(exnTable.size());
435 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
436 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o,pc,codeSize);
438 o.writeShort(codeAttrs.size());
443 byte[] codeAttribute = baos.toByteArray();
444 attrs.add("Code",codeAttribute);
447 o.writeShort(thrownExceptions.size());
448 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
449 o.writeShort(((CPGen.Ent)thrownExceptions.get(e.nextElement())).getIndex());
450 attrs.add("Exceptions",baos.toByteArray());
455 public void dump(DataOutput o) throws IOException {
457 o.writeShort(cp.getUtf8Index(name));
458 o.writeShort(cp.getUtf8Index(getDescriptor()));
459 o.writeShort(attrs.size());
463 public static byte negate(byte op) {
465 case IFEQ: return IFNE;
466 case IFNE: return IFEQ;
467 case IFLT: return IFGE;
468 case IFGE: return IFLT;
469 case IFGT: return IFLE;
470 case IFLE: return IFGT;
471 case IF_ICMPEQ: return IF_ICMPNE;
472 case IF_ICMPNE: return IF_ICMPEQ;
473 case IF_ICMPLT: return IF_ICMPGE;
474 case IF_ICMPGE: return IF_ICMPLT;
475 case IF_ICMPGT: return IF_ICMPLE;
476 case IF_ICMPLE: return IF_ICMPGT;
477 case IF_ACMPEQ: return IF_ACMPNE;
478 case IF_ACMPNE: return IF_ACMPEQ;
481 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
485 public static class PhantomTarget {
486 private int target = -1;
487 public void setTarget(int target) { this.target = target; }
488 public int getTarget() { return target; }
491 private static Integer N(int n) { return new Integer(n); }
492 private static Long N(long n) { return new Long(n); }
493 private static Float N(float f) { return new Float(f); }
494 private static Double N(double d) { return new Double(d); }
495 private static int max(int a, int b) { return a > b ? a : b; }
497 private static final int OP_BRANCH_FLAG = 1<<3;
498 private static final int OP_CPENT_FLAG = 1<<4;
499 private static final int OP_VALID_FLAG = 1<<5;
500 private static final int OP_ARG_LENGTH_MASK = 7;
501 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & OP_VALID_FLAG) != 0; }
502 private static final int OP_ARG_LENGTH(byte op) { return (OP_DATA[op&0xff]&OP_ARG_LENGTH_MASK); }
503 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&OP_CPENT_FLAG) != 0; }
504 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&OP_BRANCH_FLAG ) != 0; }
506 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
507 private static final byte[] OP_DATA = {
508 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
509 0x21, 0x22, 0x31, 0x32, 0x32, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
510 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
511 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
512 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
513 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
514 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
515 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
516 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
517 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
518 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x21, 0x27, 0x27, 0x20, 0x20, 0x20, 0x20,
519 0x20, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x01, 0x32, 0x21, 0x32, 0x20, 0x20,
520 0x32, 0x32, 0x20, 0x20, 0x27, 0x23, 0x2a, 0x2a, 0x2c, 0x2c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
521 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
522 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
523 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01