1 package org.ibex.classgen;
6 import org.ibex.classgen.util.*;
9 private final Hashtable entries = new Hashtable();
10 private Ent[] entriesByIndex; // only valid when stable
12 private int usedSlots = 1; // 0 is reserved
13 private int state = OPEN;
14 private static final int OPEN = 0;
15 private static final int STABLE = 1; // existing entries won't change
16 private static final int SEALED = 2; // no new entries
23 public abstract class Ent {
24 int n; // this is the refcount if state == OPEN, index if >= STABLE
27 Ent(int tag) { this.tag = tag; }
29 void dump(DataOutput o) throws IOException { o.writeByte(tag); }
30 String debugToString() { return toString(); } // so we can remove this method when not debugging
31 abstract Object key() throws ClassGen.ClassReadExn; // be careful using this, it drags in a bunch of code
34 // INVARIANTS: tag == 3 || tag == 4
35 class IntEnt extends Ent {
37 IntEnt(int tag) { super(tag); }
38 void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
41 case 3: return new Integer(i);
42 case 4: return new Float(Float.intBitsToFloat(i));
43 default: throw new Error("should never happen");
48 // INVARIANTS: tag == 5 || tag == 6
49 class LongEnt extends Ent {
51 LongEnt(int tag) { super(tag); }
52 void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
55 case 5: return new Long(l);
56 case 6: return new Double(Double.longBitsToDouble(l));
57 default: throw new Error("should never happen");
64 if(tag == 7 || tag == 8) e0 instanceof Utf8Ent
65 if(tag == 9 || tag == 10 || tag == 11) {
66 e0 instanceof CPRefEnt && e0.tag == 7
67 e1 instanceof CPRefEnt && e0.tag == 12
73 class CPRefEnt extends Ent {
76 CPRefEnt(int tag) { super(tag); }
78 String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
80 void dump(DataOutput o) throws IOException {
83 if(e2 != null) o.writeShort(e2.n);
86 private String fixme() { throw new Error("fixme"); }
87 Object key() throws ClassGen.ClassReadExn {
89 case 7: return Type.instance(((Utf8Ent)e1).s);
90 case 8: return (((Utf8Ent)e1).s);
92 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
93 Type t = Type.instance(nt.type);
94 if(t == null) throw new ClassGen.ClassReadExn("invalid type descriptor");
95 return new FieldRef((Type.Class)e1.key(), nt.name, t);
98 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
99 if (e1.key() == null) throw new Error(e1.tag + " => " + e1.key());
100 return new MethodRef((Type.Class)e1.key(), "methodname", Type.VOID, new Type[0]); // FIXME FIXME
103 return new NameAndTypeKey(((Utf8Ent)e1).s, ((Utf8Ent)e2).s);
106 throw new Error("FIXME " + tag);
110 class Utf8Ent extends Ent {
112 Utf8Ent() { super(1); }
113 String debugToString() { return s; }
114 void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
123 public static class Utf8Key {
125 public Utf8Key(String s) { this.s = s; }
126 public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
127 public int hashCode() { return ~s.hashCode(); }
130 public static class NameAndTypeKey {
133 NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
134 public boolean equals(Object o_) {
135 if(!(o_ instanceof NameAndTypeKey)) return false;
136 NameAndTypeKey o = (NameAndTypeKey) o_;
137 return o.name.equals(name) && o.type.equals(type);
139 public int hashCode() { return name.hashCode() ^ type.hashCode(); }
146 public final Ent get(Object o) { return (Ent) entries.get(o); }
147 public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
148 public final int getIndex(Object o) {
150 if(e == null) throw new IllegalStateException("entry not found");
153 public final String getUtf8ByIndex(int i) {
154 return ((Utf8Ent)getByIndex(i)).s;
156 public final int getUtf8Index(String s) {
158 if(e == null) throw new IllegalStateException("entry not found");
161 public final int getIndex(Ent ent) {
162 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
166 public final Type getType(int index) throws ClassGen.ClassReadExn {
167 Ent e = getByIndex(index);
168 if (e instanceof Utf8Ent) return Type.instance(((Utf8Ent)e).s);
169 else return (Type)e.key();
172 public final Ent getByIndex(int index) {
173 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
175 if(index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
176 throw new IllegalStateException("invalid cp index");
180 public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name, descriptor)); }
181 public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
183 public final Ent add(Object o) {
184 if(state == SEALED) throw new IllegalStateException("constant pool is sealed");
188 if(state == OPEN) ent.n++;
192 if(o instanceof Type.Class) {
193 CPRefEnt ce = new CPRefEnt(7);
194 ce.e1 = addUtf8(((Type.Class)o).internalForm());
196 } else if(o instanceof String) {
197 CPRefEnt ce = new CPRefEnt(8);
198 ce.e1 = addUtf8((String)o);
200 } else if(o instanceof Integer) {
201 IntEnt ue = new IntEnt(3);
202 ue.i = ((Integer)o).intValue();
204 } else if(o instanceof Float) {
205 IntEnt ue = new IntEnt(4);
206 ue.i = Float.floatToIntBits(((Float)o).floatValue());
208 } else if(o instanceof Long) {
209 LongEnt le = new LongEnt(5);
210 le.l = ((Long)o).longValue();
212 } else if(o instanceof Double) {
213 LongEnt le = new LongEnt(6);
214 le.l = Double.doubleToLongBits(((Double)o).doubleValue());
216 } else if(o instanceof Utf8Key) {
217 Utf8Ent ue = new Utf8Ent();
218 ue.s = ((Utf8Key)o).s;
220 } else if(o instanceof NameAndTypeKey) {
221 CPRefEnt ce = new CPRefEnt(12);
222 NameAndTypeKey key = (NameAndTypeKey) o;
223 ce.e1 = addUtf8(key.name);
224 ce.e2 = addUtf8(key.type);
226 } else if(o instanceof ClassGen.FieldOrMethodRef) {
227 ClassGen.FieldOrMethodRef key = (ClassGen.FieldOrMethodRef) o;
228 int tag = o instanceof FieldRef ? 9 : o instanceof MethodRef ? 10 : o instanceof MethodRef.I ? 11 : 0;
229 if(tag == 0) throw new Error("should never happen");
230 CPRefEnt ce = new CPRefEnt(tag);
231 ce.e1 = add(key.klass);
232 ce.e2 = addNameAndType(key.name, key.descriptor);
235 throw new IllegalArgumentException("Unknown type passed to add");
238 int spaces = ent instanceof LongEnt ? 2 : 1;
239 if(usedSlots + spaces > 65536) throw new ClassGen.Exn("constant pool full");
241 ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
249 public int slots() { return usedSlots; }
251 public void seal() { state = SEALED; }
253 private Ent[] asArray() {
254 int count = entries.size();
255 Ent[] ents = new Ent[count];
257 Enumeration e = entries.keys();
258 while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
259 if(i != count) throw new Error("should never happen");
263 private void assignIndex(Ent[] ents) {
265 entriesByIndex = new Ent[ents.length*2];
266 for(int i=0;i<ents.length;i++) {
269 entriesByIndex[index] = ent;
270 index += ent instanceof LongEnt ? 2 : 1;
274 public void stable() {
275 if(state != OPEN) return;
277 assignIndex(asArray());
280 private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
281 public int compare(Object a_, Object b_) {
282 return ((Ent)a_).n - ((Ent)b_).n;
286 private static final Sort.CompareFunc reverseCompareFunc = new Sort.CompareFunc() {
287 public int compare(Object a_, Object b_) {
288 return ((Ent)b_).n - ((Ent)a_).n;
292 public void optimize() {
293 if(state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
294 Ent[] ents = asArray();
295 Sort.sort(ents, reverseCompareFunc);
300 public void unsafeReopen() {
301 if(state == OPEN) return;
302 for(int i=1;i<entriesByIndex.length;i++) {
303 Ent e = entriesByIndex[i];
304 if(e == null) continue;
307 entriesByIndex = null;
311 public void dump(DataOutput o) throws IOException {
312 Ent[] ents = asArray();
313 Sort.sort(ents, compareFunc);
314 o.writeShort(usedSlots);
315 for(int i=0;i<ents.length;i++) {
316 //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
321 CPGen(DataInput in) throws ClassGen.ClassReadExn, IOException {
322 usedSlots = in.readUnsignedShort();
323 if(usedSlots==0) throw new ClassGen.ClassReadExn("invalid used slots");
325 // these are to remember the CPRefEnt e1 and e2s we have to fix up
326 int[] e1s = new int[usedSlots];
327 int[] e2s = new int[usedSlots];
329 entriesByIndex = new Ent[usedSlots];
331 for(int index=1;index<usedSlots;index++) {
332 byte tag = in.readByte();
335 case 7: // Object Type
338 case 10: // MethodRef
339 case 11: // Instance Method Ref
340 case 12: // NameAndType
342 e = new CPRefEnt(tag);
343 e1s[index] = in.readUnsignedShort();
344 if(tag != 7 && tag != 8) e2s[index] = in.readUnsignedShort();
351 e = ie = new IntEnt(tag);
359 e = le = new LongEnt(tag);
360 le.l = in.readLong();
366 e = ue = new Utf8Ent();
371 throw new ClassGen.ClassReadExn("invalid cp ent tag");
373 entriesByIndex[index] = e;
374 if (e instanceof LongEnt) index++;
377 for(int index=1;index<usedSlots;index++) {
379 Ent e = entriesByIndex[index];
380 if (e == null) throw new Error("should never happen: " + i + "/"+usedSlots);
381 if (e instanceof LongEnt) {
385 if (!(e instanceof CPRefEnt)) continue;
386 CPRefEnt ce = (CPRefEnt) e;
387 if(e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
388 ce.e1 = entriesByIndex[e1s[i]];
389 if(ce.e1 == null) throw new ClassGen.ClassReadExn("invalid cp index");
390 if(ce.tag != 7 && ce.tag != 8) {
391 if(e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
392 ce.e2 = entriesByIndex[e2s[i]];
393 if(ce.e2 == null) throw new ClassGen.ClassReadExn("invalid cp index");
398 if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
403 if(!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
404 throw new ClassGen.ClassReadExn("expected a type ent");
405 if(!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
406 throw new ClassGen.ClassReadExn("expected a name and type ent");
409 if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
410 if(!(ce.e2 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
414 for(int i=1; i<usedSlots; i++) {
415 Ent e = entriesByIndex[i];
416 entries.put(e.key(), e);
417 if (e instanceof LongEnt) i++;