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 static class Ent {
24 CPGen owner; // don't need this yet, but we will to implement ref() and unref()
25 int n; // this is the refcount if state == OPEN, index if >= STABLE
29 Ent(CPGen owner, int tag) { this.owner = owner; this.tag = tag; }
31 void dump(DataOutput o) throws IOException { o.writeByte(tag); }
32 String debugToString() { return toString(); } // so we can remove this method when not debugging
33 abstract Object key() throws ClassGen.ClassReadExn; // be careful using this, it drags in a bunch of code
36 // INVARIANTS: tag == 3 || tag == 4
37 static class IntEnt extends Ent {
39 IntEnt(CPGen owner, int tag) { super(owner, tag); }
40 void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
43 case 3: return new Integer(i);
44 case 4: return new Float(Float.intBitsToFloat(i));
45 default: throw new Error("should never happen");
50 // INVARIANTS: tag == 5 || tag == 6
51 static class LongEnt extends Ent {
53 LongEnt(CPGen owner, int tag) { super(owner, tag); }
54 void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
57 case 5: return new Long(l);
58 case 6: return new Double(Double.longBitsToDouble(l));
59 default: throw new Error("should never happen");
66 if(tag == 7 || tag == 8) e0 instanceof Utf8Ent
67 if(tag == 9 || tag == 10 || tag == 11) {
68 e0 instanceof CPRefEnt && e0.tag == 7
69 e1 instanceof CPRefEnt && e0.tag == 12
75 static class CPRefEnt extends Ent {
78 CPRefEnt(CPGen owner, int tag) { super(owner, tag); }
80 String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
82 void dump(DataOutput o) throws IOException {
85 if(e2 != null) o.writeShort(e2.n);
88 private String fixme() { throw new Error("fixme"); }
89 Object key() throws ClassGen.ClassReadExn {
91 case 7: return Type.fromDescriptor(((Utf8Ent)e0).s);
92 case 8: return (((Utf8Ent)e1).s);
94 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
95 Type t = Type.fromDescriptor(nt.type);
96 if(t == null) throw new ClassGen.ClassReadExn("invalid type descriptor");
97 return new FieldRef((Type.Object)e1.key(), nt.name, t);
100 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
101 return new MethodRef((Type.Object)e1.key(), fixme(), null, null);
104 throw new Error("FIXME");
108 static class Utf8Ent extends Ent {
110 Utf8Ent(CPGen owner) { super(owner, 1); }
111 String debugToString() { return s; }
112 void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
113 Object key() { throw new Error("Brian is lame"); }
119 public static class Utf8Key {
121 public Utf8Key(String s) { this.s = s; }
122 public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
123 public int hashCode() { return ~s.hashCode(); }
126 public static class NameAndTypeKey {
129 NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
130 public boolean equals(Object o_) {
131 if(!(o_ instanceof NameAndTypeKey)) return false;
132 NameAndTypeKey o = (NameAndTypeKey) o_;
133 return o.name.equals(name) && o.type.equals(type);
135 public int hashCode() { return name.hashCode() ^ type.hashCode(); }
142 public final Ent get(Object o) { return (Ent) entries.get(o); }
143 public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
144 public final int getIndex(Object o) {
146 if(e == null) throw new IllegalStateException("entry not found");
149 public final int getUtf8Index(String s) {
151 if(e == null) throw new IllegalStateException("entry not found");
154 public final int getIndex(Ent ent) {
155 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
159 public final Type.Object getType(int index) { return Type.fromDescriptor(((Utf8Ent)getByIndex(index)).s).asObject(); }
161 public final Ent getByIndex(int index) {
162 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
164 if(index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
165 throw new IllegalStateException("invalid cp index");
169 public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name, descriptor)); }
170 public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
172 public final Ent add(Object o) {
173 if(state == SEALED) throw new IllegalStateException("constant pool is sealed");
177 if(state == OPEN) ent.n++;
181 if(o instanceof Type.Object) {
182 CPRefEnt ce = new CPRefEnt(this, 7);
183 ce.e1 = addUtf8(((Type.Object)o).internalForm());
185 } else if(o instanceof String) {
186 CPRefEnt ce = new CPRefEnt(this, 8);
187 ce.e1 = addUtf8((String)o);
189 } else if(o instanceof Integer) {
190 IntEnt ue = new IntEnt(this, 3);
191 ue.i = ((Integer)o).intValue();
193 } else if(o instanceof Float) {
194 IntEnt ue = new IntEnt(this, 4);
195 ue.i = Float.floatToIntBits(((Float)o).floatValue());
197 } else if(o instanceof Long) {
198 LongEnt le = new LongEnt(this, 5);
199 le.l = ((Long)o).longValue();
201 } else if(o instanceof Double) {
202 LongEnt le = new LongEnt(this, 6);
203 le.l = Double.doubleToLongBits(((Double)o).doubleValue());
205 } else if(o instanceof Utf8Key) {
206 Utf8Ent ue = new Utf8Ent(this);
207 ue.s = ((Utf8Key)o).s;
209 } else if(o instanceof NameAndTypeKey) {
210 CPRefEnt ce = new CPRefEnt(this, 12);
211 NameAndTypeKey key = (NameAndTypeKey) o;
212 ce.e1 = addUtf8(key.name);
213 ce.e2 = addUtf8(key.type);
215 } else if(o instanceof ClassGen.FieldOrMethodRef) {
216 ClassGen.FieldOrMethodRef key = (ClassGen.FieldOrMethodRef) o;
217 int tag = o instanceof FieldRef ? 9 : o instanceof MethodRef ? 10 : o instanceof MethodRef.I ? 11 : 0;
218 if(tag == 0) throw new Error("should never happen");
219 CPRefEnt ce = new CPRefEnt(this, tag);
220 ce.e1 = add(key.klass);
221 ce.e2 = addNameAndType(key.name, key.descriptor);
224 throw new IllegalArgumentException("Unknown type passed to add");
227 int spaces = ent instanceof LongEnt ? 2 : 1;
228 if(usedSlots + spaces > 65536) throw new ClassGen.Exn("constant pool full");
230 ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
238 public int slots() { return usedSlots; }
240 public void seal() { state = SEALED; }
242 private Ent[] asArray() {
243 int count = entries.size();
244 Ent[] ents = new Ent[count];
246 Enumeration e = entries.keys();
247 while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
248 if(i != count) throw new Error("should never happen");
252 private void assignIndex(Ent[] ents) {
254 entriesByIndex = new Ent[ents.length*2];
255 for(int i=0;i<ents.length;i++) {
258 entriesByIndex[index] = ent;
259 index += ent instanceof LongEnt ? 2 : 1;
263 public void stable() {
264 if(state != OPEN) return;
266 assignIndex(asArray());
269 private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
270 public int compare(Object a_, Object b_) {
271 return ((Ent)a_).n - ((Ent)b_).n;
275 private static final Sort.CompareFunc reverseCompareFunc = new Sort.CompareFunc() {
276 public int compare(Object a_, Object b_) {
277 return ((Ent)b_).n - ((Ent)a_).n;
281 public void optimize() {
282 if(state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
283 Ent[] ents = asArray();
284 Sort.sort(ents, reverseCompareFunc);
289 public void unsafeReopen() {
290 if(state == OPEN) return;
291 for(int i=1;i<entriesByIndex.length;i++) {
292 Ent e = entriesByIndex[i];
293 if(e == null) continue;
296 entriesByIndex = null;
300 public void dump(DataOutput o) throws IOException {
301 Ent[] ents = asArray();
302 Sort.sort(ents, compareFunc);
303 o.writeShort(usedSlots);
304 for(int i=0;i<ents.length;i++) {
305 //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
310 CPGen(DataInput in) throws ClassGen.ClassReadExn, IOException {
311 usedSlots = in.readUnsignedShort();
312 if(usedSlots==0) throw new ClassGen.ClassReadExn("invalid used slots");
314 // these are to remember the CPRefEnt e0 and e1s we have to fix up
315 int[] e0s = new int[usedSlots];
316 int[] e1s = new int[usedSlots];
317 int[] e2s = new int[usedSlots];
319 entriesByIndex = new Ent[usedSlots];
321 for(int index=1;index<usedSlots;index++) {
322 byte tag = in.readByte();
325 case 7: // Object Type
328 case 10: // MethodRef
329 case 11: // Instance Method Ref
330 case 12: // NameAndType
332 e = new CPRefEnt(this, tag);
333 e1s[index] = in.readUnsignedShort();;
334 if(tag != 7 && tag != 8) e2s[index] = in.readUnsignedShort();
341 e = ie = new IntEnt(this, tag);
349 e = le = new LongEnt(this, tag);
350 le.l = in.readLong();
357 e = ue = new Utf8Ent(this);
362 throw new ClassGen.ClassReadExn("invalid cp ent tag");
364 entriesByIndex[index] = e;
367 for(int index=1;index<usedSlots;index++) {
369 Ent e = entriesByIndex[index];
370 if(e == null) throw new Error("should never happen");
371 if(e instanceof CPRefEnt) {
372 CPRefEnt ce = (CPRefEnt) e;
373 if(e0s[i] == 0 || e0s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
374 ce.e0 = entriesByIndex[e0s[i]];
375 if(ce.e0 == null) throw new ClassGen.ClassReadExn("invalid cp index");
376 if(ce.tag != 7 && ce.tag != 8) {
377 if(e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
378 ce.e1 = entriesByIndex[e1s[i]];
379 if(ce.e1 == null) throw new ClassGen.ClassReadExn("invalid cp index");
384 if(!(ce.e0 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
389 if(!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
390 throw new ClassGen.ClassReadExn("expected a type ent");
391 if(!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
392 throw new ClassGen.ClassReadExn("expected a name and type ent");
395 if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
396 if(!(ce.e2 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
398 } else if(e instanceof LongEnt) {
401 entries.put(e.key(), e);