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