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(newCap <= capacity) return;
79 newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
81 byte[] op2 = new byte[newCap];
82 if(capacity != 0) System.arraycopy(op,0,op2,0,size);
85 Object[] arg2 = new Object[newCap];
86 if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
91 public final int size() { return size; }
93 // FEATURE: Deprecate this
94 public final int addPushConst(int n) { return add(LDC,n); }
96 public final int add(byte op, Object arg) { grow(); set(size,op,arg); return size++; }
97 public final int add(byte op, boolean arg) { grow(); set(size,op,arg); return size++; }
98 public final int add(byte op, int arg) { grow(); set(size,op,arg); return size++; }
99 public final int add(byte op) { grow(); set(size,op); return size++; }
101 public final byte get(int pos) { return op[pos]; }
102 public final Object getArg(int pos) { return arg[pos]; }
104 public final void setArg(int pos, int arg) { set(pos,op[pos],N(arg)); }
105 public final void setArg(int pos, Object arg) { set(pos,op[pos],arg); }
107 public final void set(int pos, byte op) { set(pos,op,null); }
109 public final void set(int pos, byte op, boolean b) { set(pos,op,b?1:0); }
110 public final void set(int pos, byte op, int n) {
113 case -1: set(pos,ICONST_M1); return;
114 case 0: set(pos,ICONST_0); return;
115 case 1: set(pos,ICONST_1); return;
116 case 2: set(pos,ICONST_2); return;
117 case 3: set(pos,ICONST_3); return;
118 case 4: set(pos,ICONST_4); return;
119 case 5: set(pos,ICONST_5); return;
121 if(n >= -128 && n <= 127) set(pos,BIPUSH,N(n));
122 else if(n >= -32767 && n <= 32767) set(pos,SIPUSH,N(n));
123 else set(pos,LDC,cp.add(N(n)));
129 public void set(int pos, byte op, Object arg) {
130 int iarg = arg instanceof Integer ? ((Integer)arg).intValue() : -1;
133 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
134 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
136 if(iarg >= 0 && iarg <= 3) {
139 case ILOAD: base = ILOAD_0; break;
140 case ISTORE: base = ISTORE_0; break;
141 case LLOAD: base = LLOAD_0; break;
142 case LSTORE: base = LSTORE_0; break;
143 case FLOAD: base = FLOAD_0; break;
144 case FSTORE: base = FSTORE_0; break;
145 case DLOAD: base = DLOAD_0; break;
146 case DSTORE: base = DSTORE_0; break;
147 case ALOAD: base = ALOAD_0; break;
148 case ASTORE: base = ASTORE_0; break;
150 op = (byte)((base&0xff) + iarg);
152 if(iarg >= maxLocals) maxLocals = iarg + 1;
157 if(arg instanceof Integer) { set(pos,op,iarg); return; }
158 if(arg instanceof Boolean) { set(pos,op,((Boolean)arg).booleanValue()); return; }
159 if(arg instanceof Long) {
160 long l = ((Long)arg).longValue();
161 if(l == 0L) { set(pos,LCONST_0); return; }
162 if(l == 1L) { set(pos,LCONST_1); return; }
165 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
168 if(OP_CPENT(op) && !(arg instanceof CPGen.Ent)) arg = cp.add(arg);
174 private final void _set(int pos, byte op, Object arg) {
175 if(capacity == -1) throw new IllegalStateException("method can't have code");
176 if(size == -1) throw new IllegalStateException("method is finalized");
177 if(!OP_VALID(op)) throw new IllegalArgumentException("unknown bytecode");
183 public static class SI {
184 public final Object[] targets;
185 public Object defaultTarget;
187 SI(int size) { targets = new Object[size]; }
188 public void setTarget(int pos, Object val) { targets[pos] = val; }
189 public void setTarget(int pos, int val) { targets[pos] = N(val); }
190 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
191 public void setDefaultTarget(Object o) { defaultTarget = o; }
192 public int size() { return targets.length; }
194 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
195 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
198 public static class TSI extends SI {
201 public int defaultTarget = -1;
202 public TSI(int lo, int hi) {
207 public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
208 public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
211 public static class LSI extends SI {
212 public final int[] vals;
213 public LSI(int size) {
215 this.vals = new int[size];
217 public final void setVal(int pos, int val) { vals[pos] = val; }
220 public static class Pair {
223 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
226 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
227 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
229 public void finish() {
232 } catch(IOException e) {
233 throw new Error("should never happen");
237 private Object resolveTarget(Object arg) {
239 if(arg instanceof PhantomTarget) {
240 target = ((PhantomTarget)arg).getTarget();
241 if(target == -1) throw new IllegalStateException("unresolved phantom target");
244 target = ((Integer)arg).intValue();
246 if(target < 0 || target >= size)
247 throw new IllegalStateException("invalid target address");
251 private void _finish() throws IOException {
252 if(size == -1) return;
254 ByteArrayOutputStream baos = new ByteArrayOutputStream();
255 DataOutput o = new DataOutputStream(baos);
257 int[] pc = new int[size];
261 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
262 for(i=0,p=0;i<size;i++) {
263 byte op = this.op[i];
269 arg[i] = resolveTarget(arg[i]);
270 } catch(RuntimeException e) {
271 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
287 Object[] targets = si.targets;
288 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
289 si.defaultTarget = resolveTarget(si.defaultTarget);
290 p += 1 + 3 + 4; // opcode itself, padding, default
291 if(op == TABLESWITCH) p += 4 + 4 + targets.length * 4; // lo, hi, targets
292 else p += 4 + targets.length * 4 * 2; // count, key,val * targets
296 j = ((CPGen.Ent)arg[i]).getIndex();
297 if(j >= 256) this.op[i] = op = LDC_W;
300 if((j = OP_ARG_SIZE(op)) == -1) throw new Error("shouldn't be here");
306 // Pass2 - Widen instructions if they can possibly be too short
307 for(i=0;i<size;i++) {
311 int arg = ((Integer)this.arg[i]).intValue();
312 int diff = maxpc[arg] - maxpc[i];
313 if(diff < -32768 || diff > 32767)
314 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
320 // Pass3 - Calculate actual pc
321 for(i=0,p=0;i<size;i++) {
322 byte op = this.op[i];
331 p++; // opcpde itself
332 p = (p + 3) & ~3; // padding
334 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
335 else p += 4 + si.size() * 4 * 2; // count, key,val * targets
339 int l = OP_ARG_SIZE(op);
340 if(l == -1) throw new Error("shouldn't be here");
348 o.writeShort(maxStack);
349 o.writeShort(maxLocals);
350 o.writeInt(codeSize);
352 // Pass 4 - Actually write the bytecodes
353 for(i=0;i<size;i++) {
354 byte op = this.op[i];
355 if(op == NOP && !EMIT_NOPS) continue;
357 o.writeByte(op&0xff);
358 int argLength = OP_ARG_SIZE(op);
360 if(argLength == 0) continue; // skip if no args
363 Object arg = this.arg[i];
364 boolean wasInt = arg instanceof Integer;
365 int iarg = wasInt ? ((Integer)arg).intValue() : -1;
369 Pair pair = (Pair) arg;
370 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
371 o.writeByte(pair.i1);
372 o.writeByte(pair.i2);
378 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
379 o.writeInt(pc[si.getDefaultTarget()] - mypc);
380 if(op == LOOKUPSWITCH) {
381 int[] vals = ((LSI)si).vals;
382 o.writeInt(si.size());
383 for(int j=0;j<si.size();j++) {
385 o.writeInt(pc[si.getTarget(j)] - mypc);
391 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
398 int v = pc[iarg] - pc[i];
399 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
401 } else if(OP_CPENT(op)) {
402 int v = ((CPGen.Ent)arg).getIndex();
403 if(argLength == 1) o.writeByte(v);
404 else if(argLength == 2) o.writeShort(v);
405 else throw new Error("should never happen");
406 } else if(argLength == -1) {
407 throw new Error("should never happen - variable length instruction not explicitly handled");
409 if(!wasInt) throw new IllegalStateException("Invalid argument given for " + Integer.toHexString(op&0xff));
411 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
413 } else if(argLength == 2) {
414 if(iarg < -32767 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
417 throw new Error("should never happen");
424 if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
426 o.writeShort(exnTable.size());
427 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
428 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o,pc,codeSize);
430 o.writeShort(codeAttrs.size());
435 byte[] codeAttribute = baos.toByteArray();
436 attrs.add("Code",codeAttribute);
439 o.writeShort(thrownExceptions.size());
440 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
441 o.writeShort(((CPGen.Ent)thrownExceptions.get(e.nextElement())).getIndex());
442 attrs.add("Exceptions",baos.toByteArray());
447 public void dump(DataOutput o) throws IOException {
449 o.writeShort(cp.getUtf8Index(name));
450 o.writeShort(cp.getUtf8Index(getDescriptor()));
451 o.writeShort(attrs.size());
455 public static byte negate(byte op) {
457 case IFEQ: return IFNE;
458 case IFNE: return IFEQ;
459 case IFLT: return IFGE;
460 case IFGE: return IFLT;
461 case IFGT: return IFLE;
462 case IFLE: return IFGT;
463 case IF_ICMPEQ: return IF_ICMPNE;
464 case IF_ICMPNE: return IF_ICMPEQ;
465 case IF_ICMPLT: return IF_ICMPGE;
466 case IF_ICMPGE: return IF_ICMPLT;
467 case IF_ICMPGT: return IF_ICMPLE;
468 case IF_ICMPLE: return IF_ICMPGT;
469 case IF_ACMPEQ: return IF_ACMPNE;
470 case IF_ACMPNE: return IF_ACMPEQ;
473 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
477 public static class PhantomTarget {
478 private int target = -1;
479 public void setTarget(int target) { this.target = target; }
480 public int getTarget() { return target; }
483 private static Integer N(int n) { return new Integer(n); }
484 private static Long N(long n) { return new Long(n); }
485 private static Float N(float f) { return new Float(f); }
486 private static Double N(double d) { return new Double(d); }
487 private static int max(int a, int b) { return a > b ? a : b; }
489 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & 1) != 0; }
490 private static final int OP_ARG_SIZE(byte op) { int n = ((OP_DATA[op&0xff]>>1)&3); return n == 7 ? -1 : n; }
491 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&(1<<4)) != 0; }
492 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&(1<<5)) != 0; }
494 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
495 private static final byte[] OP_DATA = {
496 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
497 0x03, 0x05, 0x13, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
498 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
499 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
500 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
501 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
502 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
503 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
504 0x01, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
505 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
506 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x03, 0x0f, 0x0f, 0x01, 0x01, 0x01, 0x01,
507 0x01, 0x01, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x02, 0x15, 0x03, 0x15, 0x01, 0x01,
508 0x15, 0x15, 0x01, 0x01, 0x0f, 0x07, 0x25, 0x25, 0x29, 0x29, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
509 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
510 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
511 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02