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 private 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 + iarg);
152 if(iarg > maxLocals) maxLocals = iarg;
156 if(arg instanceof Integer) { set(pos,op,iarg); return; }
157 if(arg instanceof Boolean) { set(pos,op,((Boolean)arg).booleanValue()); return; }
158 if(arg instanceof Long) {
159 long l = ((Long)arg).longValue();
160 if(l == 0L) { set(pos,LCONST_0); return; }
161 if(l == 1L) { set(pos,LCONST_1); return; }
164 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
167 if(OP_CPENT(op) && !(arg instanceof CPGen.Ent)) arg = cp.add(arg);
173 public final void _set(int pos, byte op, Object arg) {
174 if(capacity == -1) throw new IllegalStateException("method can't have code");
175 if(size == -1) throw new IllegalStateException("method is finalized");
176 if(!OP_VALID(op)) throw new IllegalArgumentException("unknown bytecode");
182 public static class SI {
183 public final Object[] targets;
184 public Object defaultTarget;
186 SI(int size) { targets = new Object[size]; }
187 public void setTarget(int pos, Object val) { targets[pos] = val; }
188 public void setTarget(int pos, int val) { targets[pos] = N(val); }
189 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
190 public void setDefaultTarget(Object o) { defaultTarget = o; }
191 public int size() { return targets.length; }
193 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
194 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
197 public static class TSI extends SI {
200 public int defaultTarget = -1;
201 public TSI(int lo, int hi) {
206 public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
207 public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
210 public static class LSI extends SI {
211 public final int[] vals;
212 public LSI(int size) {
214 this.vals = new int[size];
216 public final void setVal(int pos, int val) { vals[pos] = val; }
219 public static class Pair {
222 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
225 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
226 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
228 public void finish() {
231 } catch(IOException e) {
232 throw new Error("should never happen");
236 private Object resolveTarget(Object arg) {
238 if(arg instanceof PhantomTarget) {
239 target = ((PhantomTarget)arg).getTarget();
240 if(target == -1) throw new IllegalStateException("unresolved phantom target");
243 target = ((Integer)arg).intValue();
245 if(target < 0 || target >= size)
246 throw new IllegalStateException("invalid target address");
250 private void _finish() throws IOException {
251 if(size == -1) return;
253 ByteArrayOutputStream baos = new ByteArrayOutputStream();
254 DataOutput o = new DataOutputStream(baos);
256 int[] pc = new int[size];
260 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
261 for(i=0,p=0;i<size;i++) {
262 byte op = this.op[i];
268 arg[i] = resolveTarget(arg[i]);
269 } catch(RuntimeException e) {
270 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
286 Object[] targets = si.targets;
287 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
288 si.defaultTarget = resolveTarget(si.defaultTarget);
289 p += 1 + 3 + 4; // opcode itself, padding, default
290 if(op == TABLESWITCH) p += 4 + 4 + targets.length * 4; // lo, hi, targets
291 else p += 4 + targets.length * 4 * 2; // count, key,val * targets
295 j = ((CPGen.Ent)arg[i]).getIndex();
296 if(j >= 256) this.op[i] = op = LDC_W;
299 if((j = OP_ARG_SIZE(op)) == -1) throw new Error("shouldn't be here");
305 // Pass2 - Widen instructions if they can possibly be too short
306 for(i=0;i<size;i++) {
310 int arg = ((Integer)this.arg[i]).intValue();
311 int diff = maxpc[arg] - maxpc[i];
312 if(diff < -32768 || diff > 32767)
313 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
319 // Pass3 - Calculate actual pc
320 for(i=0,p=0;i<size;i++) {
321 byte op = this.op[i];
330 p++; // opcpde itself
331 p = (p + 3) & ~3; // padding
333 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
334 else p += 4 + si.size() * 4 * 2; // count, key,val * targets
338 int l = OP_ARG_SIZE(op);
339 if(l == -1) throw new Error("shouldn't be here");
347 o.writeShort(maxStack);
348 o.writeShort(maxLocals);
349 o.writeInt(codeSize);
351 // Pass 4 - Actually write the bytecodes
352 for(i=0;i<size;i++) {
353 byte op = this.op[i];
354 if(op == NOP && !EMIT_NOPS) continue;
356 o.writeByte(op&0xff);
357 int argLength = OP_ARG_SIZE(op);
359 if(argLength == 0) continue; // skip if no args
362 Object arg = this.arg[i];
363 boolean wasInt = arg instanceof Integer;
364 int iarg = wasInt ? ((Integer)arg).intValue() : -1;
368 Pair pair = (Pair) arg;
369 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
370 o.writeByte(pair.i1);
371 o.writeByte(pair.i2);
377 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
378 o.writeInt(pc[si.getDefaultTarget()] - mypc);
379 if(op == LOOKUPSWITCH) {
380 int[] vals = ((LSI)si).vals;
381 o.writeInt(si.size());
382 for(int j=0;j<si.size();j++) {
384 o.writeInt(pc[si.getTarget(j)] - mypc);
390 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
397 int v = pc[iarg] - pc[i];
398 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
400 } else if(OP_CPENT(op)) {
401 int v = ((CPGen.Ent)arg).getIndex();
402 if(argLength == 1) o.writeByte(v);
403 else if(argLength == 2) o.writeShort(v);
404 else throw new Error("should never happen");
405 } else if(argLength == -1) {
406 throw new Error("should never happen - variable length instruction not explicitly handled");
408 if(!wasInt) throw new IllegalStateException("Invalid argument given for " + Integer.toHexString(op&0xff));
410 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
412 } else if(argLength == 2) {
413 if(iarg < -32767 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
416 throw new Error("should never happen");
423 if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
425 o.writeShort(exnTable.size());
426 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
427 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o,pc,codeSize);
429 o.writeShort(codeAttrs.size());
434 byte[] codeAttribute = baos.toByteArray();
435 attrs.add("Code",codeAttribute);
438 o.writeShort(thrownExceptions.size());
439 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
440 o.writeShort(((CPGen.Ent)thrownExceptions.get(e.nextElement())).getIndex());
441 attrs.add("Exceptions",baos.toByteArray());
446 public void dump(DataOutput o) throws IOException {
448 o.writeShort(cp.getUtf8Index(name));
449 o.writeShort(cp.getUtf8Index(getDescriptor()));
450 o.writeShort(attrs.size());
454 public static byte negate(byte op) {
456 case IFEQ: return IFNE;
457 case IFNE: return IFEQ;
458 case IFLT: return IFGE;
459 case IFGE: return IFLT;
460 case IFGT: return IFLE;
461 case IFLE: return IFGT;
462 case IF_ICMPEQ: return IF_ICMPNE;
463 case IF_ICMPNE: return IF_ICMPEQ;
464 case IF_ICMPLT: return IF_ICMPGE;
465 case IF_ICMPGE: return IF_ICMPLT;
466 case IF_ICMPGT: return IF_ICMPLE;
467 case IF_ICMPLE: return IF_ICMPGT;
468 case IF_ACMPEQ: return IF_ACMPNE;
469 case IF_ACMPNE: return IF_ACMPEQ;
472 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
476 public static class PhantomTarget {
477 private int target = -1;
478 public void setTarget(int target) { this.target = target; }
479 public int getTarget() { return target; }
482 private static Integer N(int n) { return new Integer(n); }
483 private static Long N(long n) { return new Long(n); }
484 private static Float N(float f) { return new Float(f); }
485 private static Double N(double d) { return new Double(d); }
486 private static int max(int a, int b) { return a > b ? a : b; }
488 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & 1) != 0; }
489 private static final int OP_ARG_SIZE(byte op) { int n = ((OP_DATA[op&0xff]>>1)&3); return n == 7 ? -1 : n; }
490 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&(1<<4)) != 0; }
491 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&(1<<5)) != 0; }
493 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
494 private static final byte[] OP_DATA = {
495 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
496 0x03, 0x05, 0x13, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
497 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
498 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x13, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
499 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 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, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
504 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
505 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x03, 0x0f, 0x0f, 0x01, 0x01, 0x01, 0x01,
506 0x01, 0x01, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x02, 0x15, 0x03, 0x15, 0x01, 0x01,
507 0x15, 0x15, 0x01, 0x01, 0x0f, 0x07, 0x25, 0x25, 0x29, 0x29, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
508 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 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