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
28 Ent(CPGen owner, int tag) { this.owner = owner; this.tag = tag; }
30 void dump(DataOutput o) throws IOException { o.writeByte(tag); }
31 String debugToString() { return toString(); } // so we can remove this method when not debugging
32 abstract Object key() throws ClassGen.ClassReadExn; // be careful using this, it drags in a bunch of code
35 // INVARIANTS: tag == 3 || tag == 4
36 static class IntEnt extends Ent {
38 IntEnt(CPGen owner, int tag) { super(owner,tag); }
39 void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i); }
42 case 3: return new Integer(i);
43 case 4: return new Float(Float.intBitsToFloat(i));
44 default: throw new Error("should never happen");
49 // INVARIANTS: tag == 5 || tag == 6
50 static class LongEnt extends Ent {
52 LongEnt(CPGen owner, int tag) { super(owner,tag); }
53 void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
56 case 5: return new Long(l);
57 case 6: return new Double(Double.longBitsToDouble(l));
58 default: throw new Error("should never happen");
65 if(tag == 7 || tag == 8) e0 instanceof Utf8Ent
66 if(tag == 9 || tag == 10 || tag == 11) {
67 e0 instanceof CPRefEnt && e0.tag == 7
68 e1 instanceof CPRefEnt && e0.tag == 12
74 static class CPRefEnt extends Ent {
77 CPRefEnt(CPGen owner, int tag) { super(owner,tag); }
79 String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
81 void dump(DataOutput o) throws IOException {
84 if(e2 != null) o.writeShort(e2.n);
87 Object key() throws ClassGen.ClassReadExn {
89 case 7: return new Type.Object(((Utf8Ent)e0).s);
90 case 8: return (((Utf8Ent)e1).s);
92 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
93 Type t = Type.fromDescriptor(nt.type);
94 if(t == null) throw new ClassGen.ClassReadExn("invalid type descriptor");
95 return FieldRef((Type.Object)e1.key(), nt.name, t);
97 NameAndTypeKey nt = (NameAndTypeKey) e2.key();
98 return MethodRef((Type.Object)e1.key(),throw new Error("fixme"));
103 static class Utf8Ent extends Ent {
105 Utf8Ent(CPGen owner) { super(owner,1); }
106 String debugToString() { return s; }
107 void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
113 public static class Utf8Key {
115 public Utf8Key(String s) { this.s = s; }
116 public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
117 public int hashCode() { return ~s.hashCode(); }
120 public static class NameAndTypeKey {
123 NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
124 public boolean equals(Object o_) {
125 if(!(o_ instanceof NameAndTypeKey)) return false;
126 NameAndTypeKey o = (NameAndTypeKey) o_;
127 return o.name.equals(name) && o.type.equals(type);
129 public int hashCode() { return name.hashCode() ^ type.hashCode(); }
136 public final Ent get(Object o) { return (Ent) entries.get(o); }
137 public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
138 public final int getIndex(Object o) {
140 if(e == null) throw new IllegalStateException("entry not found");
143 public final int getUtf8Index(String s) {
145 if(e == null) throw new IllegalStateException("entry not found");
148 public final int getIndex(Ent ent) {
149 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
153 public final Ent getByIndex(int index) {
154 if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
156 if(index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null)
157 throw new IllegalStateException("invalid cp index");
161 public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name,descriptor)); }
162 public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
164 public final Ent add(Object o) {
165 if(state == SEALED) throw new IllegalStateException("constant pool is sealed");
169 if(state == OPEN) ent.n++;
173 if(o instanceof Type.Object) {
174 CPRefEnt ce = new CPRefEnt(this,7);
175 ce.e1 = addUtf8(((Type.Object)o).internalForm());
177 } else if(o instanceof String) {
178 CPRefEnt ce = new CPRefEnt(this,8);
179 ce.e1 = addUtf8((String)o);
181 } else if(o instanceof Integer) {
182 IntEnt ue = new IntEnt(this,3);
183 ue.i = ((Integer)o).intValue();
185 } else if(o instanceof Float) {
186 IntEnt ue = new IntEnt(this,4);
187 ue.i = Float.floatToIntBits(((Float)o).floatValue());
189 } else if(o instanceof Long) {
190 LongEnt le = new LongEnt(this,5);
191 le.l = ((Long)o).longValue();
193 } else if(o instanceof Double) {
194 LongEnt le = new LongEnt(this,6);
195 le.l = Double.doubleToLongBits(((Double)o).doubleValue());
197 } else if(o instanceof Utf8Key) {
198 Utf8Ent ue = new Utf8Ent(this);
199 ue.s = ((Utf8Key)o).s;
201 } else if(o instanceof NameAndTypeKey) {
202 CPRefEnt ce = new CPRefEnt(this,12);
203 NameAndTypeKey key = (NameAndTypeKey) o;
204 ce.e1 = addUtf8(key.name);
205 ce.e2 = addUtf8(key.type);
207 } else if(o instanceof ClassGen.FieldOrMethodRef) {
208 ClassGen.FieldOrMethodRef key = (ClassGen.FieldOrMethodRef) o;
209 int tag = o instanceof FieldRef ? 9 : o instanceof MethodRef ? 10 : o instanceof MethodRef.I ? 11 : 0;
210 if(tag == 0) throw new Error("should never happen");
211 CPRefEnt ce = new CPRefEnt(this,tag);
212 ce.e1 = add(key.klass);
213 ce.e2 = addNameAndType(key.name,key.descriptor);
216 throw new IllegalArgumentException("Unknown type passed to add");
219 int spaces = ent instanceof LongEnt ? 2 : 1;
220 if(usedSlots + spaces > 65536) throw new ClassGen.Exn("constant pool full");
222 ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
230 public int slots() { return usedSlots; }
232 public void seal() { state = SEALED; }
234 private Ent[] asArray() {
235 int count = entries.size();
236 Ent[] ents = new Ent[count];
238 Enumeration e = entries.keys();
239 while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
240 if(i != count) throw new Error("should never happen");
244 private void assignIndex(Ent[] ents) {
246 entriesByIndex = new Ent[ents.length*2];
247 for(int i=0;i<ents.length;i++) {
250 entriesByIndex[index] = ent;
251 index += ent instanceof LongEnt ? 2 : 1;
255 public void stable() {
256 if(state != OPEN) return;
258 assignIndex(asArray());
261 private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
262 public int compare(Object a_, Object b_) {
263 return ((Ent)a_).n - ((Ent)b_).n;
267 private static final Sort.CompareFunc reverseCompareFunc = new Sort.CompareFunc() {
268 public int compare(Object a_, Object b_) {
269 return ((Ent)b_).n - ((Ent)a_).n;
273 public void optimize() {
274 if(state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
275 Ent[] ents = asArray();
276 Sort.sort(ents,reverseCompareFunc);
281 public void unsafeReopen() {
282 if(state == OPEN) return;
283 for(int i=1;i<entriesByIndex.length;i++) {
284 Ent e = entriesByIndex[i];
285 if(e == null) continue;
288 entriesByIndex = null;
292 public void dump(DataOutput o) throws IOException {
293 Ent[] ents = asArray();
294 Sort.sort(ents,compareFunc);
295 o.writeShort(usedSlots);
296 for(int i=0;i<ents.length;i++) {
297 //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
302 CPGen(DataInput in) throws ClassGen.ClassReadExn {
303 usedSlots = i.readUnsignedShort();
304 if(usedSlots==0) throw new ClassGen.ClassReadExn("invalid used slots");
306 // these are to remember the CPRefEnt e0 and e1s we have to fix up
307 int[] e1s = new int[usedSlots];
308 int[] e2s = new int[usedSlots];
310 entriesByIndex = new Ent[usedSlots];
312 for(int index=1;index<usedSlots;index++) {
313 byte tag = i.readByte();
316 case 7: // Object Type
319 case 10: // MethodRef
320 case 11: // Instance Method Ref
321 case 12: // NameAndType
323 e = new CPRefEnt(this,tag);
324 e1s[index] = i.readUnsignedShort();;
325 if(tag != 7 && tag != 8) e2s[index] = i.readUnsignedShort();
332 e = ie = new IntEnt(this,tag);
340 e = le = new LongEnt(this,tag);
348 e = ue = new Utf8Ent(this);
353 throw new ClassGen.ClassReadExn("invalid cp ent tag");
355 entriesByIndex[index] = e;
358 for(int index=1;index<usedSlots;index++) {
359 Ent e = entriesByIndex[index];
360 if(e == null) throw new Error("should never happen");
361 if(e instanceof CPRefEnt) {
362 CPRefEnt ce = (CPRefEnt) e;
363 if(e0s[i] == 0 || e0s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
364 ce.e0 = entriesByIndex[e0s[i]];
365 if(ce.e0 == null) throw new ClassGen.ClassReadExn("invalid cp index");
366 if(ce.tag != 7 && ce.tag != 8) {
367 if(e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
368 ce.e1 = entriesByIndex[e1s[i]];
369 if(ce.e1 == null) throw new ClassGen.ClassReadExn("invalid cp index");
374 if(!(ce.e0 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
379 if(!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
380 throw new ClassGen.ClassReadExn("expected a type ent");
381 if(!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
382 throw new ClassGen.ClassReadExn("expected a name and type ent");
385 if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
386 if(!(ce.e2 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
388 } else if(e instanceof LongEnt) {
391 entries.put(e.key(),e);