got it to compile
[org.ibex.classgen.git] / src / org / ibex / classgen / MethodGen.java
1 package org.ibex.classgen;
2
3 import java.io.*;
4 import java.util.*;
5
6 /** A class representing a method in a generated classfile
7     @see ClassGen#addMethod */
8 public class MethodGen implements CGConst {
9     private final static boolean EMIT_NOPS = false;
10     
11     private static final int NO_CODE = -1;
12     private static final int FINISHED = -2;
13     
14     private final CPGen cp;
15     private final String name;
16     private final Type ret;
17     private final Type[] args;
18     private final int flags;
19     private final ClassGen.AttrGen attrs;
20     private final ClassGen.AttrGen codeAttrs;
21     private final Hashtable exnTable = new Hashtable();
22     private final Hashtable thrownExceptions = new Hashtable();
23     
24     private int maxStack = 16;
25     private int maxLocals;
26     
27     private int size;
28     private int capacity;
29     private byte[] op;
30     private Object[] arg;
31     
32     MethodGen(DataInput in) { throw new Error("Brian is lame"); }
33     MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
34         if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
35             throw new IllegalArgumentException("invalid flags");
36         this.cp = owner.cp;
37         this.name = name;
38         this.ret = ret;
39         this.args = args;
40         this.flags = flags;
41         
42         attrs = new ClassGen.AttrGen(cp);
43         codeAttrs = new ClassGen.AttrGen(cp);
44         
45         cp.addUtf8(name);
46         cp.addUtf8(getDescriptor());
47         
48         if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
49         
50         maxLocals = Math.max(args.length + (flags&ACC_STATIC)==0 ? 1 : 0,4);
51     }
52     
53     /** Returns the descriptor string for this method */
54     public String getDescriptor() { return MethodRef.getDescriptor(ret,args); }
55     
56     private class ExnTableEnt {
57         public int start;
58         public int end;
59         public int handler;
60         public CPGen.Ent typeEnt;
61         public ExnTableEnt(int start, int end, int handler, CPGen.Ent typeEnt) {
62             this.start = start;
63             this.end = end;
64             this.handler = handler;
65             this.typeEnt = typeEnt;
66         }
67         public void dump(DataOutput o, int[] pc, int endPC) throws IOException {
68             o.writeShort(pc[start]);
69             o.writeShort(end==pc.length ? endPC : pc[end]);
70             o.writeShort(pc[handler]);
71             o.writeShort(cp.getIndex(typeEnt));
72         }
73     }
74     
75     /** Adds an exception handler for the range [<i>start</i>,<i>end</i>) pointing to <i>handler</i>
76         @param start The instruction to start at (inclusive)
77         @param end The instruction to end at (exclusive)
78         @param handler The instruction of the excepton handler
79         @param type The type of exception that is to be handled (MUST inherit from Throwable)
80     */
81     public final void addExceptionHandler(int start, int end, int handler, Type.Object type) {
82         exnTable.put(type, new ExnTableEnt(start,end,handler,cp.add(type)));
83     }
84     
85     /** Adds a exception type that can be thrown from this method
86         NOTE: This isn't enforced by the JVM. This is for reference only. A method can throw exceptions not declared to be thrown 
87         @param type The type of exception that can be thrown 
88     */
89     public final void addThrow(Type.Object type) {
90         thrownExceptions.put(type,cp.add(type));
91     }
92     
93     private final void grow() { if(size == capacity) grow(size+1); }
94     private final void grow(int newCap) {
95         if(capacity == NO_CODE) throw new IllegalStateException("method can't have code");
96         if(capacity == FINISHED) throw new IllegalStateException("method has been finished");
97         if(newCap <= capacity) return;
98         newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
99         
100         byte[] op2 = new byte[newCap];
101         if(capacity != 0) System.arraycopy(op,0,op2,0,size);
102         op = op2;
103         
104         Object[] arg2 = new Object[newCap];
105         if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
106         arg = arg2;
107         
108         capacity = newCap;
109     }
110     
111     /** Returns the size (in instructions) of this method 
112         @return The size of the method (in instructions)
113     */
114     public final int size() { return size; }
115     
116     // These two are optimized for speed, they don't call set() below
117     /** Add a bytecode (with no argument) to the method */
118     public final int add(byte op) {
119         int s = size;
120         if(s == capacity) grow();
121         this.op[s] = op;
122         size++;
123         return s;
124     }
125     /** Set the bytecode at position <i>pos</i> to <i>op</i> */
126     public final void set(int pos, byte op) { this.op[pos] = op; }
127         
128     /** Adds a bytecode, <i>op</i>, with argument <i>arg</i> to the method 
129         @return The position of the new bytecode
130         */
131     public final int add(byte op, Object arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
132     /** Adds a bytecode with a boolean argument - equivalent to add(op,arg?1:0);
133         @return The position of the new bytecode
134         @see #add(byte,int)
135     */
136     public final int add(byte op, boolean arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
137     /** Adds a bytecode with an integer argument. This is equivalent to add(op,new Integer(arg)), but optimized to prevent the allocation when possible
138         @return The position of the new bytecode
139         @see #add(byte,Object)
140     */
141     public final int add(byte op, int arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
142     
143     /** Gets the bytecode at position <i>pos</i>
144         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
145     */
146     public final byte get(int pos) { return op[pos]; }
147     
148     /** Gets the bytecode at position <i>pos</i>. NOTE: This isn't necessarily the same object that was set with add or set.
149         Arguments for instructions which access the constant pool (LDC, INVOKEVIRTUAL, etc) are converted to a more efficient
150         interal form when they are added. The value returned from this method for these instruction can be reused, but there
151         is no way to retrieve the original object 
152         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
153     */    
154     public final Object getArg(int pos) { return arg[pos]; }
155     
156     /** Sets the argument for <i>pos</i> to <i>arg</i>. This is equivalent to set(pos,op,new Integer(arg)), but optimized to prevent the allocation when possible.
157         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
158         @see #setArg(int,Object) */
159     public final void setArg(int pos, int arg) { set(pos,op[pos],N(arg)); }
160     /** Sets the argument for <i>pos</i> to <i>arg</i>.
161         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
162     */
163     public final void setArg(int pos, Object arg) { set(pos,op[pos],arg); }
164     
165     /** Sets the bytecode and argument  at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly. 
166         This is equivalent to set(pos,op,arg?1:0) 
167         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
168     */
169     public final void set(int pos, byte op, boolean arg) { set(pos,op,arg?1:0); }
170     
171     // This MUST handle x{LOAD,STORE} and LDC with an int arg WITHOUT falling back to set(int,byte,Object)
172     /** Sets the bytecode and argument  at <i>pos</i> to <i>op</i> and <i>n</i> respectivly.
173         This is equivalent to set(pos,op, new Integer(n)), but optimized to prevent the allocation when possible.
174         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
175     */
176     public final void set(int pos, byte op, int n) {
177         Object arg = null;
178         OUTER: switch(op) {
179             case LDC:
180                 switch(n) {
181                     case -1: op = ICONST_M1; break OUTER;
182                     case 0:  op = ICONST_0;  break OUTER;
183                     case 1:  op = ICONST_1;  break OUTER;
184                     case 2:  op = ICONST_2;  break OUTER; 
185                     case 3:  op = ICONST_3;  break OUTER;
186                     case 4:  op = ICONST_4;  break OUTER;
187                     case 5:  op = ICONST_5;  break OUTER;
188                 }
189                 if(n >= -128 && n <= 127) { op = BIPUSH; arg = N(n); } 
190                 else if(n >= -32768 && n <= 32767) { op = SIPUSH; arg = N(n); }
191                 else { arg = cp.add(N(n)); }
192                 break;
193             case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
194             case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
195                 if(n >= maxLocals) maxLocals = n + 1;
196                 if(n >= 0 && n <= 3) {
197                     byte base = 0;
198                     switch(op) {
199                         case ILOAD:  base = ILOAD_0;  break;
200                         case ISTORE: base = ISTORE_0; break;
201                         case LLOAD:  base = LLOAD_0;  break;
202                         case LSTORE: base = LSTORE_0; break; 
203                         case FLOAD:  base = FLOAD_0;  break;
204                         case FSTORE: base = FSTORE_0; break;
205                         case DLOAD:  base = DLOAD_0;  break;
206                         case DSTORE: base = DSTORE_0; break;
207                         case ALOAD:  base = ALOAD_0;  break;
208                         case ASTORE: base = ASTORE_0; break;
209                     }
210                     op = (byte)((base&0xff) + n);
211                 } else {
212                     arg = N(n);
213                 }
214                 break;
215             default:
216                 set(pos,op,N(n));
217                 return;
218         }            
219         this.op[pos] = op;
220         this.arg[pos] = arg;
221     }
222     
223     /** Sets the bytecode and argument  at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
224         @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
225         */
226     public final void set(int pos, byte op, Object arg) {
227         switch(op) {
228             case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
229             case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
230                 // set(int,byte,int) always handles these ops itself
231                 set(pos,op,((Integer)arg).intValue());
232                 return;
233             case LDC:
234                 // set(int,byte,int) always handles these opts itself
235                 if(arg instanceof Integer) { set(pos,op,((Integer)arg).intValue()); return; }
236                 if(arg instanceof Boolean) { set(pos,op,((Boolean)arg).booleanValue()); return; }
237                 
238                 if(arg instanceof Long) {
239                     long l = ((Long)arg).longValue();
240                     if(l == 0L) { this.op[pos] = LCONST_0; return; }
241                     if(l == 1L) { this.op[pos] = LCONST_1; return; }
242                 }
243                 
244                 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
245                 break;
246             case INVOKEINTERFACE:
247                 if(arg instanceof MethodRef) arg = new MethodRef.I((MethodRef)arg);
248                 break;
249         }
250         int opdata = OP_DATA[op&0xff];
251         if((opdata&OP_CPENT_FLAG) != 0 && !(arg instanceof CPGen.Ent))
252             arg = cp.add(arg);
253         else if((opdata&OP_VALID_FLAG) == 0)
254             throw new IllegalArgumentException("unknown bytecode");
255         this.op[pos] = op;
256         this.arg[pos] = arg;
257     }
258     
259     /** This class represents the arguments to the TABLESWITH and LOOKUPSWITCH bytecodes
260         @see MethodGen.TSI
261         @see MethodGen.LSI
262     */
263     public static abstract class SI {
264         public final Object[] targets;
265         public Object defaultTarget;
266
267         SI(int size) { targets = new Object[size]; }
268         public void setTarget(int pos, Object val) { targets[pos] = val; }
269         public void setTarget(int pos, int val) { targets[pos] = N(val); }
270         public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
271         public void setDefaultTarget(Object o) { defaultTarget = o; }
272         public int size() { return targets.length; }
273         
274         public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
275         public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }   
276         
277         abstract int length();
278     }
279     
280     /** This class represents the arguments to the TABLESWITCH bytecode */
281     public static class TSI extends SI {
282         public final int lo;
283         public final int hi;
284         public TSI(int lo, int hi) {
285             super(hi-lo+1);
286             this.lo = lo;
287             this.hi = hi;
288         }
289         public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
290         public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
291         
292         int length() { return 12 + targets.length * 4; } // 4bytes/target, hi, lo, default
293     }
294     
295     /** This class represents the arguments to the LOOKUPSWITCH bytecode */
296     public static class LSI extends SI {
297         public final int[] vals;
298         public LSI(int size) {
299            super(size);
300            this.vals = new int[size];
301         }
302         public final void setVal(int pos, int val) { vals[pos] = val; }
303         
304         int length() { return 8 + targets.length * 8; } // key/val per target, default, count
305     }
306     
307     /** This class represents the arguments to byecodes that take two integer arguments. */
308     public static class Pair {
309         public int i1;
310         public int i2;
311         public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
312     }
313     
314     public static class Wide {
315         public final byte op;
316         public final int varNum;
317         public final int n;
318         Wide(byte op, int varNum) { this(op,varNum,0); }
319         Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; }
320     }
321         
322     /** Sets the maximum number of locals in the function to <i>maxLocals</i>. NOTE: This defaults to 0 and is automatically increased as
323         necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */
324     public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
325     /** Sets the maxinum size of th stack for this function  to <i>maxStack</i>. This defaults to 16< */
326     public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
327     
328     /** Computes the final bytecode for this method. 
329         @exception IllegalStateException if the data for a method is in an inconsistent state (required arguments missing, etc)
330         @exception Exn if the byteocode could not be generated for any other reason (constant pool full, etc)
331     */
332     public void finish() {
333         try {
334             _finish();
335         } catch(IOException e) {
336             throw new Error("should never happen");
337         }
338     }
339     
340     private Object resolveTarget(Object arg) {
341         int target;
342         if(arg instanceof PhantomTarget) {
343             target = ((PhantomTarget)arg).getTarget();
344             if(target == -1) throw new IllegalStateException("unresolved phantom target");
345             arg = N(target);
346         } else {
347             target = ((Integer)arg).intValue();
348         }
349         if(target < 0 || target >= size)
350             throw new IllegalStateException("invalid target address");
351         return arg;
352     }
353     
354     private void _finish() throws IOException {
355         if(size == FINISHED) return;
356         
357         cp.stable();
358         
359         ByteArrayOutputStream baos = new ByteArrayOutputStream();
360         DataOutput o = new DataOutputStream(baos);
361     
362         int[] pc = new int[size];
363         int[] maxpc = pc;
364         int p,i;
365         
366         // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
367         for(i=0,p=0;i<size;i++) {
368             byte op = this.op[i];
369             int opdata = OP_DATA[op&0xff];
370             int j;
371             maxpc[i] = p;
372             
373             if((opdata & OP_BRANCH_FLAG)!= 0) { 
374                 try { 
375                     arg[i] = resolveTarget(arg[i]);
376                 } catch(RuntimeException e) {
377                     System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
378                     throw e;
379                 }
380             }
381             
382             switch(op) {
383                 // Speical caculations
384                 case GOTO:
385                 case JSR: {
386                     int arg = ((Integer)this.arg[i]).intValue();
387                     if(arg < i && p - maxpc[arg] <= 32768) p += 3; 
388                     else p += 5;
389                     continue;
390                 }
391                 case NOP:
392                     if(EMIT_NOPS) p++;
393                     continue;
394                 case LOOKUPSWITCH:
395                 case TABLESWITCH: {
396                     SI si = (SI) arg[i];
397                     Object[] targets = si.targets;
398                     for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
399                     si.defaultTarget = resolveTarget(si.defaultTarget);
400                     p += 1 + 3 + si.length(); // opcode itself, padding, data
401                     if(op == LOOKUPSWITCH) { // verify sanity of lookupswitch vals
402                         int[] vals = ((LSI)si).vals;
403                         for(j=1;j<vals.length;j++)
404                             if(vals[j] <= vals[j-1])
405                                 throw new IllegalStateException("out of order/duplicate lookupswitch values");
406                     }
407                     continue;
408                 }
409                 // May need widening
410                 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
411                 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
412                 case RET: {
413                     int arg = ((Integer)this.arg[i]).intValue();
414                     if(arg > 255) {
415                         this.op[i] = WIDE;
416                         this.arg[i] = new Wide(op,arg);
417                     }
418                     break;
419                 }
420                 case IINC: {
421                     Pair pair = (Pair) this.arg[i];
422                     if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) {
423                         this.op[i] = WIDE;
424                         this.arg[i] = new Wide(IINC,pair.i1,pair.i2);
425                     }
426                     break;
427                 }
428                 case LDC:
429                     j = cp.getIndex((CPGen.Ent)arg[i]);
430                     if(j >= 256) this.op[i] = op = LDC_W;
431                     break;
432                 default:
433             }
434             if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
435             p += 1 + j;
436         }
437         
438         // Pass2 - Widen instructions if they can possibly be too short
439         for(i=0;i<size;i++) {
440             switch(op[i]) {
441                 case GOTO:
442                 case JSR: {
443                     int arg = ((Integer)this.arg[i]).intValue();
444                     int diff = maxpc[arg] - maxpc[i];
445                     if(diff < -32768 || diff > 32767)
446                         op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
447                     break;
448                 }
449             }
450         }
451         
452         // Pass3 - Calculate actual pc
453         for(i=0,p=0;i<size;i++) {
454             byte op = this.op[i];
455             pc[i] = p;
456             switch(op) {
457                 case NOP:
458                     if(EMIT_NOPS) p++;
459                     break;
460                 case TABLESWITCH:
461                 case LOOKUPSWITCH: {
462                     SI si = (SI) arg[i];
463                     p++; // opcode itself
464                     p = (p + 3) & ~3; // padding
465                     p += 4; // default
466                     if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
467                     else p += 4 + si.size() * 4 * 2; // count, key,val * targets
468                     break;
469                 }
470                 case WIDE:
471                     p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
472                     break;                
473                 default: {
474                     int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
475                     if(l == 7) throw new Error("shouldn't be here");
476                     p += 1 + l;                    
477                 }
478             }
479         }
480         int codeSize = p;
481         
482         if(codeSize >= 65536) throw new ClassGen.Exn("method too large in size");
483         
484         o.writeShort(maxStack);
485         o.writeShort(maxLocals);
486         o.writeInt(codeSize);
487         
488         // Pass 4 - Actually write the bytecodes
489         for(i=0;i<size;i++) {
490             byte op = this.op[i];
491             int opdata = OP_DATA[op&0xff];
492             if(op == NOP && !EMIT_NOPS) continue;
493             o.writeByte(op);
494             int argLength = opdata & OP_ARG_LENGTH_MASK;
495             
496             if(argLength == 0) continue; // skip if no args
497             
498             // Write args
499             Object arg = this.arg[i];  
500             
501             switch(op) {
502                 case IINC: {
503                     Pair pair = (Pair) arg;
504                     if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg"); 
505                     o.writeByte(pair.i1);
506                     o.writeByte(pair.i2);
507                     break;
508                 }
509                 case TABLESWITCH:
510                 case LOOKUPSWITCH: {
511                     SI si = (SI) arg;
512                     int mypc = pc[i];
513                     for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
514                     o.writeInt(pc[si.getDefaultTarget()] - mypc);
515                     if(op == LOOKUPSWITCH) {
516                         int[] vals = ((LSI)si).vals;
517                         o.writeInt(si.size());
518                         for(int j=0;j<si.size();j++) {
519                             o.writeInt(vals[j]);
520                             o.writeInt(pc[si.getTarget(j)] - mypc);
521                         }
522                     } else {
523                         TSI tsi = (TSI) si;
524                         o.writeInt(tsi.lo);
525                         o.writeInt(tsi.hi);
526                         for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
527                     }
528                     break;
529                 }
530                 case WIDE: {
531                     Wide wide = (Wide) arg;
532                     o.writeByte(wide.op);
533                     o.writeShort(wide.varNum);
534                     if(wide.op == IINC) o.writeShort(wide.n);
535                     break;
536                 }
537                     
538                 default:
539                     if((opdata & OP_BRANCH_FLAG) != 0) {
540                         int v = pc[((Integer)arg).intValue()] - pc[i];
541                         if(argLength == 2) {
542                             if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
543                             o.writeShort(v);
544                         } else if(argLength == 4) {
545                             o.writeInt(v);
546                         } else {
547                             throw new Error("should never happen");
548                         }
549                     } else if((opdata & OP_CPENT_FLAG) != 0) {
550                         int v = cp.getIndex((CPGen.Ent)arg);
551                         if(argLength == 1) o.writeByte(v);
552                         else if(argLength == 2) o.writeShort(v);
553                         else throw new Error("should never happen");
554                     } else if(argLength == 7) {
555                         throw new Error("should never happen - variable length instruction not explicitly handled");
556                     } else {
557                         int iarg  = ((Integer)arg).intValue();
558                         if(argLength == 1) {
559                             if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
560                             o.writeByte(iarg);
561                         } else if(argLength == 2) {
562                             if(iarg < -32768 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option"); 
563                             o.writeShort(iarg);
564                         } else {
565                             throw new Error("should never happen");
566                         }
567                     }
568                     break;
569             }
570         }
571
572         //if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
573         
574         o.writeShort(exnTable.size());
575         for(Enumeration e = exnTable.keys();e.hasMoreElements();)
576             ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o,pc,codeSize);
577         
578         o.writeShort(codeAttrs.size());
579         codeAttrs.dump(o);
580         
581         baos.close();
582         
583         byte[] codeAttribute = baos.toByteArray();
584         attrs.add("Code",codeAttribute);
585         
586         baos.reset();
587         o.writeShort(thrownExceptions.size());
588         for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
589             o.writeShort(cp.getIndex((CPGen.Ent)thrownExceptions.get(e.nextElement())));
590         attrs.add("Exceptions",baos.toByteArray());
591         
592         size = capacity = FINISHED;        
593     }
594         
595     void dump(DataOutput o) throws IOException {
596         o.writeShort(flags);
597         o.writeShort(cp.getUtf8Index(name));
598         o.writeShort(cp.getUtf8Index(getDescriptor()));
599         o.writeShort(attrs.size());
600         attrs.dump(o);
601     }
602     
603     /** Negates the IF* instruction, <i>op</i>  (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ,  etc)
604         @exception IllegalArgumentException if <i>op</i> isn't an IF* instruction */
605     public static byte negate(byte op) {
606         switch(op) {
607             case IFEQ: return IFNE;
608             case IFNE: return IFEQ;
609             case IFLT: return IFGE;
610             case IFGE: return IFLT;
611             case IFGT: return IFLE;
612             case IFLE: return IFGT;
613             case IF_ICMPEQ: return IF_ICMPNE;
614             case IF_ICMPNE: return IF_ICMPEQ;
615             case IF_ICMPLT: return IF_ICMPGE;
616             case IF_ICMPGE: return IF_ICMPLT;
617             case IF_ICMPGT: return IF_ICMPLE;
618             case IF_ICMPLE: return IF_ICMPGT;
619             case IF_ACMPEQ: return IF_ACMPNE;
620             case IF_ACMPNE: return IF_ACMPEQ;
621             
622             default:
623                 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
624         }
625     }
626     
627     /** Class that represents a target that isn't currently know. The target MUST be set with setTarget() before the classfile is written. 
628         This class is more or less a mutable integer */
629     public static class PhantomTarget {
630         private int target = -1;
631         public void setTarget(int target) { this.target = target; }
632         public int getTarget() { return target; }
633     }
634     
635     private static Integer N(int n) { return new Integer(n); }
636     private static Long N(long n) { return new Long(n); }
637     private static Float N(float f) { return new Float(f); }
638     private static Double N(double d) { return new Double(d); }
639     private static int max(int a, int b) { return a > b ? a : b; }
640     
641     private static final int OP_BRANCH_FLAG = 1<<3;
642     private static final int OP_CPENT_FLAG = 1<<4;
643     private static final int OP_VALID_FLAG = 1<<5;
644     private static final int OP_ARG_LENGTH_MASK = 7;
645     private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & OP_VALID_FLAG) != 0; }
646     private static final int OP_ARG_LENGTH(byte op) { return (OP_DATA[op&0xff]&OP_ARG_LENGTH_MASK); }
647     private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&OP_CPENT_FLAG) != 0; }
648     private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&OP_BRANCH_FLAG ) != 0; }
649     
650     // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
651     private static final byte[] OP_DATA = {
652             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
653             0x21, 0x22, 0x31, 0x32, 0x32, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
654             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
655             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
656             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
657             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
658             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
659             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
660             0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
661             0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
662             0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x21, 0x27, 0x27, 0x20, 0x20, 0x20, 0x20,
663             0x20, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x01, 0x32, 0x21, 0x32, 0x20, 0x20,
664             0x32, 0x32, 0x20, 0x20, 0x27, 0x23, 0x2a, 0x2a, 0x2c, 0x2c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
665             0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
666             0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
667             0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
668     };
669 }