1 package org.ibex.classgen;
5 public class MethodGen implements CGConst {
6 private final static boolean EMIT_NOPS = true;
8 private final CPGen cp;
9 private final String name;
10 private final Type ret;
11 private final Type[] args;
12 private final int flags;
13 private final AttrGen attrs;
14 private final AttrGen codeAttrs;
16 private final int nameIndex;
17 private final int descriptorIndex;
19 private int maxStack = 16;
20 private int maxLocals=1;
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);
39 nameIndex = cp.addUtf8(name).index;
40 descriptorIndex = cp.addUtf8(descriptor()).index;
42 if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
45 public String descriptor() { return descriptor(ret,args); }
46 public static String descriptor(Type ret, Type[] args) {
47 StringBuffer sb = new StringBuffer(args.length*4);
49 for(int i=0;i<args.length;i++) sb.append(args[i].getDescriptor());
51 sb.append(ret.getDescriptor());
55 private final void grow() { if(size == capacity) grow(size+1); }
56 private final void grow(int newCap) {
57 if(newCap <= capacity) return;
58 newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
60 byte[] op2 = new byte[newCap];
61 if(capacity != 0) System.arraycopy(op,0,op2,0,size);
64 Object[] arg2 = new Object[newCap];
65 if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
70 public final int size() { return size; }
72 public final int addPushConst(int n) { grow(); setPushConst(size,n); return size++; }
73 public final int addPushConst(long n) { grow(); setPushConst(size,n); return size++; }
74 public final int addPushConst(float n) { grow(); setPushConst(size,n); return size++; }
75 public final int addPushConst(double n) { grow(); setPushConst(size,n); return size++; }
76 public final int addPushConst(Object o) { grow(); setPushConst(size,o); return size++; }
77 public final int add(byte op, int arg) { return add(op,N(arg)); }
78 public final int add(byte op, Object arg) { grow(); set(size,op,arg); return size++; }
79 public final int add(byte op) { return add(op,null); }
81 public final void set(int pos, byte op) { set(pos,op,null); }
82 public final void set(int pos, byte op, int n) { set(pos,op,N(n)); }
83 public final void set(int pos, byte op, Object arg) {
84 if(capacity == -1) throw new IllegalStateException("method can't have code");
85 if(size == -1) throw new IllegalStateException("method is finalized");
86 int iarg = arg instanceof Integer ? ((Integer)arg).intValue() : -1;
89 case LDC: if(iarg >= 256) op = LDC_W; break;
95 public final void setPushConst(int pos, int n) {
97 case -1: set(pos,ICONST_M1); break;
98 case 0: set(pos,ICONST_0); break;
99 case 1: set(pos,ICONST_1); break;
100 case 2: set(pos,ICONST_2); break;
101 case 3: set(pos,ICONST_3); break;
102 case 4: set(pos,ICONST_4); break;
103 case 5: set(pos,ICONST_5); break;
105 if(n >= -128 && n <= 127) set(pos,BIPUSH,n);
106 if(n >= -32767 && n <= 32767) set(pos,SIPUSH,n);
111 public final void setPushConst(int pos, long l) {
112 if(l==0) set(pos,LCONST_0);
113 else if(l==1) set(pos,LCONST_1);
114 else setLDC(pos,N(l));
117 public final void setPushConst(int pos, float f) {
118 if(f == 1.0f) set(pos,FCONST_0);
119 else if(f == 1.0f) set(pos,FCONST_1);
120 else if(f == 2.0f) set(pos,FCONST_2);
121 else setLDC(pos,N(f));
123 public final void setPushConst(int pos, double d) {
124 if(d == 1.0) set(pos,DCONST_0);
125 else if(d == 2.0) set(pos,DCONST_1);
126 else setLDC(pos,N(d));
128 public final void setPushConst(int pos, Object o) {
129 if(o instanceof Integer) setPushConst(pos,((Integer)o).intValue());
130 else if(o instanceof Long) setPushConst(pos,((Long)o).longValue());
131 else if(o instanceof Float) setPushConst(pos,((Float)o).floatValue());
132 else if(o instanceof Double) setPushConst(pos,((Double)o).doubleValue());
136 private void setLDC(int pos, Object o) { set(pos,LDC,cp.add(o)); }
138 public final CPGen.Ent methodRef(Type.Object c, String name, Type ret, Type[] args) {
139 return methodRef(c,name,MethodGen.descriptor(ret,args));
141 public final CPGen.Ent methodRef(Type.Object c, String name, String descriptor) {
142 return cp.add(new CPGen.MethodRef(c,new CPGen.NameAndType(name,descriptor)));
144 public final CPGen.Ent fieldRef(Type.Object c, String name, Type type) {
145 return fieldRef(c,name,type.getDescriptor());
147 public final CPGen.Ent fieldRef(Type.Object c, String name, String descriptor) {
148 return cp.add(new CPGen.FieldRef(c,new CPGen.NameAndType(name,descriptor)));
151 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
152 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
154 public void finish() {
157 } catch(IOException e) {
158 throw new Error("should never happen");
162 private void _finish() throws IOException {
163 if(size == -1) return;
165 ByteArrayOutputStream baos = new ByteArrayOutputStream();
166 DataOutput o = new DataOutputStream(baos);
168 int[] pc = new int[size];
172 // Pass1 - Calculate maximum pc of each bytecode
173 for(i=0,p=0;i<size;i++) {
174 byte op = this.op[i];
177 case GOTO: p += 3; break;
178 case JSR: p += 3; break;
179 case NOP: if(!EMIT_NOPS) continue; /* fall though */
180 default: p += 1 + opArgLength(op); break;
183 // Pass2 - Widen instructions if they can possibly be too short
184 for(i=0;i<size;i++) {
188 int arg = ((Integer)this.arg[i]).intValue();
189 int diff = maxpc[arg] - maxpc[i];
190 if(diff < -32768 || diff > 32767)
191 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
195 // Pass3 - Calculate actual pc
196 for(i=0,p=0;i<size;i++) {
197 byte op = this.op[i];
199 p += op != NOP || EMIT_NOPS ? 1 + opArgLength(op) : 0;
202 o.writeShort(maxStack);
203 o.writeShort(maxLocals);
206 // Pass 4 - Actually write the bytecodes
207 for(i=0;i<size;i++) {
208 byte op = this.op[i];
209 System.err.println("" + i + " Writing " + Integer.toHexString(op) + " at " + pc[i]);
210 if(op == NOP && !EMIT_NOPS) continue;
211 int argLength = opArgLength(op);
212 o.writeByte(op&0xff);
213 if(argLength == 0) continue;
214 Object arg = this.arg[i];
215 int iarg = arg instanceof Integer ? ((Integer)arg).intValue() : -1;
220 int[] pair = (int[]) arg;
221 if(pair[0] > 255 || pair[1] < -128 || pair[1] > 127) throw new ClassGen.Exn("overflow of iinc arg");
222 o.writeByte(pair[0]);
223 o.writeByte(pair[1]);
231 outArg = pc[iarg] - pc[i];
232 if(outArg < -32768 || outArg > 32767) throw new ClassGen.Exn("overflow of s2 offset");
243 outArg = ((CPGen.Ent)arg).index;
247 if(argLength == 1) o.writeByte(outArg);
248 else if(argLength == 2) o.writeShort(outArg);
249 else throw new Error("should never happen");
252 o.writeShort(0); // FIXME: Exception table
253 o.writeShort(codeAttrs.size());
258 byte[] codeAttribute = baos.toByteArray();
259 attrs.add("Code",codeAttribute);
263 public void dump(DataOutput o) throws IOException {
265 o.writeShort(nameIndex);
266 o.writeShort(descriptorIndex);
267 o.writeShort(attrs.size());
271 private static int opArgLength(byte op) {
318 throw new ClassGen.Exn("unknown bytecode " + Integer.toHexString(op&0xff));
322 private static Integer N(int n) { return new Integer(n); }
323 private static Long N(long n) { return new Long(n); }
324 private static Float N(float f) { return new Float(f); }
325 private static Double N(double d) { return new Double(d); }
326 private static int max(int a, int b) { return a > b ? a : b; }