fixed HIDEOUS bug in ConstantPool -- was circumventing Type-instance caching (evil...
[org.ibex.classgen.git] / src / org / ibex / classgen / ConstantPool.java
index 6817ff8..5868f62 100644 (file)
@@ -5,7 +5,7 @@ import java.io.*;
 
 import org.ibex.classgen.util.*;
 
-class ConstantPool {
+class ConstantPool implements CGConst {
     private final Hashtable entries = new Hashtable();
     private Ent[] entriesByIndex; // only valid when stable
     
@@ -20,107 +20,132 @@ class ConstantPool {
     public abstract class Ent {
         int n; // this is the refcount if state == OPEN, index if >= STABLE
         int tag;
+        Object key;
         Ent(int tag) { this.tag = tag; }
         void dump(DataOutput o) throws IOException { o.writeByte(tag); }
         String debugToString() { return toString(); } // so we can remove this method when not debugging
-        abstract Object key() throws ClassFile.ClassReadExn; // be careful using this, it drags in a bunch of code
+        abstract Object _key();
+        final Object key() { return key == null ? (key = _key()) : key; }
+        int slots() { return 1; } // number of slots this ent takes up
+        void ref() {
+            if(state != OPEN) throw new IllegalStateException("cp is not open");
+            n++;
+        }
+        void unref() {
+            if(state != OPEN) throw new IllegalStateException("cp is not open");
+            if(--n == 0) entries.remove(key());
+        }
+    }
+    
+    class Utf8Ent extends Ent {
+        String s;
+        Utf8Ent() { super(CONSTANT_UTF8); }
+        Utf8Ent(String s) { this();  this.s = s; }
+        String debugToString() { return s; }
+        void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
+        Object _key() { return new Utf8Key(s); }
     }
     
-    class IntEnt extends Ent {
+    class IntLitEnt extends Ent {
         final int i;
-        IntEnt(int i) { super(3); this.i = i; }
+        IntLitEnt(int i) { super(CONSTANT_INTEGER); this.i = i; }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i);  }
-        Object key() { return new Integer(i); }
+        Object _key() { return new Integer(i); }
     }
-
-    class FloatEnt extends Ent {
+    class FloatLitEnt extends Ent {
         final float f;
-        FloatEnt(float f) { super(4); this.f = f; }
+        FloatLitEnt(float f) { super(CONSTANT_FLOAT); this.f = f; }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeFloat(f);  }
-        Object key() { return new Float(f); }
+        Object _key() { return new Float(f); }
     }
-    class LongEnt extends Ent {
+    class LongLitEnt extends Ent {
         final long l;
-        LongEnt(long l) { super(5); this.l = l; }
+        LongLitEnt(long l) { super(CONSTANT_LONG); this.l = l; }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
-        Object key() { return new Long(l); }
+        Object _key() { return new Long(l); }
+        int slots() { return 2; }
     }
-    class DoubleEnt extends Ent {
+    class DoubleLitEnt extends Ent {
         final double d;
-        DoubleEnt(double d) { super(6); this.d = d; }
+        DoubleLitEnt(double d) { super(CONSTANT_DOUBLE); this.d = d; }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeDouble(d); }
-        Object key() { return new Double(d); }
+        Object _key() { return new Double(d); }
+        int slots() { return 2; }
+    }
+    class StringLitEnt extends Ent {
+        Utf8Ent utf8;
+        StringLitEnt() { super(CONSTANT_STRING); }
+        StringLitEnt(String s) { this(); this.utf8 = (Utf8Ent)addUtf8(s); }
+        void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(utf8.n); }
+        Object _key() { return utf8.s; }
+        void unref() { utf8.unref(); super.unref(); }
+    }
+    class ClassEnt extends Ent {
+        Utf8Ent utf8;
+        ClassEnt() { super(CONSTANT_CLASS); }
+        ClassEnt(String s) { this(); this.utf8 = (Utf8Ent) addUtf8(s); }
+        void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(utf8.n); }
+        Type.Class getTypeClass() { return  (Type.Class) key(); }
+        Object _key() { return Type.Class.instance(utf8.s); }
+        void unref() { utf8.unref(); super.unref(); }
+        String debugToString() { return "[Class: " + utf8.s + "]"; }
     }
     
-    /* INVARIANTS:
-        tag >= 7 && tag <= 12
-        if (tag == 7 || tag == 8) e0 instanceof Utf8Ent
-        if (tag == 9 || tag == 10 || tag == 11) {
-            e0 instanceof CPRefEnt && e0.tag == 7
-            e1 instanceof CPRefEnt && e0.tag == 12
-        }
-        if (tag == 12) {
-            e0 instanceof Utf8Ent
-        }
-    */
-    class CPRefEnt extends Ent {
-        Ent e1;
-        Ent e2;
-        CPRefEnt(int tag) { super(tag); }
+    class NameAndTypeEnt extends Ent {
+        Utf8Ent name;
+        Utf8Ent type;
         
-        String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
+        NameAndTypeEnt() { super(CONSTANT_NAMEANDTYPE); }
+        NameAndTypeEnt(String name, String type) {
+            this();
+            this.name = (Utf8Ent) addUtf8(name);
+            this.type = (Utf8Ent) addUtf8(type);
+        }
+        void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(name.n); o.writeShort(type.n); }
+        Object _key() { return new NameAndTypeKey(name.s, type.s); }
+        void unref() { name.unref(); type.unref(); super.unref(); }
+    }
+    
+    class MemberEnt extends Ent {
+        ClassEnt klass;
+        NameAndTypeEnt member;
         
-        void dump(DataOutput o) throws IOException {
-            super.dump(o);
-            o.writeShort(e1.n);
-            if (e2 != null) o.writeShort(e2.n);
+        MemberEnt(int tag) { super(tag); }
+        MemberEnt(int tag, Type.Class klass, String name, String type) {
+            this(tag);
+            this.klass = (ClassEnt) add(klass); 
+            this.member = addNameAndType(name,type);
         }
         
-        private String fixme() { throw new Error("fixme"); }
-        Object key() throws ClassFile.ClassReadExn {
+        void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(klass.n); o.writeShort(member.n); }
+        
+        Object _key() {
+            if(member.name == null) throw new Error("should never happen");
             switch(tag) {
-                case 7: return Type.instance(((Utf8Ent)e1).s);
-                case 8: return (((Utf8Ent)e1).s);
-                case 9: {
-                    NameAndTypeKey nt = (NameAndTypeKey) e2.key();
-                    Type t = Type.instance(nt.type);
-                    if (t == null) throw new ClassFile.ClassReadExn("invalid type descriptor");
-                    return ((Type.Class)e1.key()).field(nt.name, t);
-                }
-                case 10: case 11: {
-                    NameAndTypeKey nt = (NameAndTypeKey) e2.key();
-                    if (e1.key() == null) throw new Error(e1.tag + " => " + e1.key());
-                    return ((Type.Class)e1.key()).method("methodname", Type.VOID, new Type[0]); // FIXME FIXME
-                }
-                case 12: {
-                    return new NameAndTypeKey(((Utf8Ent)e1).s, ((Utf8Ent)e2).s); 
-                }
+                case CONSTANT_FIELDREF:
+                    return klass.getTypeClass().field(member.name.s, Type.fromDescriptor(member.type.s));
+                case CONSTANT_METHODREF:
+                case CONSTANT_INTERFACEMETHODREF:
+                    Type.Class.Method m = klass.getTypeClass().method(member.name.s,member.type.s);
+                    return tag == CONSTANT_INTERFACEMETHODREF ? (Object) new InterfaceMethodKey(m) : (Object) m;
+                default:
+                    throw new Error("should never happen");
             }
-            throw new Error("FIXME " + tag);
-        }
-    }
-        
-    class Utf8Ent extends Ent {
-        String s;
-        Utf8Ent() { super(1); }
-        String debugToString() { return s; }
-        void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
-        Object key() {
-            return s;
         }
+        void unref() { klass.unref(); member.unref(); super.unref(); }
     }
     
     /*
      * Cache Keys
      */
-    public static class Utf8Key {
+    static class Utf8Key {
         String s;
         public Utf8Key(String s) { this.s = s; }
         public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
         public int hashCode() { return ~s.hashCode(); }
     }
         
-    public static class NameAndTypeKey {
+    static class NameAndTypeKey {
         String name;
         String type;
         NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
@@ -132,92 +157,92 @@ class ConstantPool {
         public int hashCode() { return name.hashCode() ^ type.hashCode(); }
     }
     
+    static class InterfaceMethodKey {
+        Type.Class.Method method;
+        InterfaceMethodKey(Type.Class.Method method) { this.method = method; }
+        public int hashCode() { return ~method.hashCode(); }
+        public boolean equals(Object o) { return o instanceof InterfaceMethodKey && ((InterfaceMethodKey)o).method.equals(method); }
+    }
+    
     /*
      * Methods
      */
     
-    public final Ent get(Object o) { return (Ent) entries.get(o); }
-    public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
-    public final int getIndex(Object o) {
+    Ent get(Object o) { return (Ent) entries.get(o); }
+    Utf8Ent getUtf8(String s) { return (Utf8Ent) get(new Utf8Key(s)); }
+    
+    int getIndex(Object o) {
         Ent e = get(o);
         if (e == null) throw new IllegalStateException("entry not found");
         return getIndex(e);
     }
-    public final String getUtf8ByIndex(int i) {
-        return ((Utf8Ent)getByIndex(i)).s;
-    }
-    public final int getUtf8Index(String s) {
+    int getUtf8Index(String s) {
         Ent e = getUtf8(s);
         if (e == null) throw new IllegalStateException("entry not found");
         return getIndex(e);
     }
-    public final int getIndex(Ent ent) {
+    int getIndex(Ent ent) {
         if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
         return ent.n;
     }
-
-    public final Type getType(int index) throws ClassFile.ClassReadExn {
-        Ent e = getByIndex(index);
-        if (e instanceof Utf8Ent) return Type.instance(((Utf8Ent)e).s);
-        else return (Type)e.key();
-    }
-
-    public final Ent getByIndex(int index) {
+    
+    Ent getByIndex(int index) {
         if (state < STABLE) throw new IllegalStateException("constant pool is not stable");
         Ent e;
         if (index >= 65536 || index >= entriesByIndex.length || (e = entriesByIndex[index]) == null) 
-            throw new IllegalStateException("invalid cp index");
+            throw new IllegalArgumentException("invalid cp index: " + index + "/" + entriesByIndex.length);
         return e;
     }
     
-    public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndTypeKey(name, descriptor)); }
-    public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
+    String getUtf8KeyByIndex(int index) {
+        Ent e = getByIndex(index);
+        if(!(e instanceof Utf8Ent)) throw new IllegalArgumentException("that isn't a utf8 (" + e.debugToString() + ")");
+        return ((Utf8Ent)e).s;
+    }
+    
+    Object getKeyByIndex(int index) {
+        Ent e = getByIndex(index);
+        return e == null ? null : e.key();
+    }
     
-    public final Ent add(Object o) { return add(o, false); }
-    public final Ent add(Object o, boolean invokeInterface) {
+    NameAndTypeEnt addNameAndType(String name, String descriptor) { return (NameAndTypeEnt) add(new NameAndTypeKey(name, descriptor)); }
+    Utf8Ent addUtf8(String s) { return (Utf8Ent) add(new Utf8Key(s)); }
+    
+    Ent add(Object o) {
+        boolean isInterfaceMethod;
         if (state == SEALED) throw new IllegalStateException("constant pool is sealed");
-            
+        
         Ent ent = get(o);
         if (ent != null) {
             if (state == OPEN) ent.n++;
             return ent;
         }
         
-        if (o instanceof Type.Class) {
-            CPRefEnt ce = new CPRefEnt(7);
-            ce.e1 = addUtf8(((Type.Class)o).internalForm());
-            ent = ce;
-        } else if (o instanceof String) {
-            CPRefEnt ce = new CPRefEnt(8);
-            ce.e1 = addUtf8((String)o);
-            ent = ce;
-        } else if (o instanceof Integer) {  ent = new IntEnt(((Integer)o).intValue());
-        } else if (o instanceof Float) {    ent = new FloatEnt(((Float)o).floatValue());
-        } else if (o instanceof Long) {     ent = new LongEnt(((Long)o).longValue());
-        } else if (o instanceof Double) {   ent = new DoubleEnt(((Double)o).doubleValue());
-        } else if (o instanceof Utf8Key) {
-            Utf8Ent ue = new Utf8Ent();
-            ue.s = ((Utf8Key)o).s;
-            ent = ue;
-        } else if (o instanceof NameAndTypeKey) {
-            CPRefEnt ce = new CPRefEnt(12);
+        if (o instanceof Type.Class) { ent = new ClassEnt(((Type.Class)o).internalForm()); }
+        else if (o instanceof String) { ent = new StringLitEnt((String)o); }
+        else if (o instanceof Integer) { ent = new IntLitEnt(((Integer)o).intValue()); }
+        else if (o instanceof Float) { ent = new FloatLitEnt(((Float)o).floatValue()); }
+        else if (o instanceof Long) { ent = new LongLitEnt(((Long)o).longValue()); }
+        else if (o instanceof Double) { ent = new DoubleLitEnt(((Double)o).doubleValue()); }
+        else if (o instanceof Utf8Key) { ent = new Utf8Ent(((Utf8Key)o).s); }
+        else if (o instanceof NameAndTypeKey) {
             NameAndTypeKey key = (NameAndTypeKey) o;
-            ce.e1 = addUtf8(key.name);
-            ce.e2 = addUtf8(key.type);
-            ent = ce;
-        } else if (o instanceof Type.Class.Member) {
-            Type.Class.Member key = (Type.Class.Member) o;
-            int tag = invokeInterface ? 11 : o instanceof Type.Class.Field ? 9 : o instanceof Type.Class.Method ? 10 : 0;
+            ent = new NameAndTypeEnt(key.name,key.type);
+        }
+        else if ((isInterfaceMethod = o instanceof InterfaceMethodKey) || o instanceof Type.Class.Member) {
+            Type.Class.Member m = isInterfaceMethod ? ((InterfaceMethodKey)o).method : (Type.Class.Member) o;
+            int tag = isInterfaceMethod              ? CONSTANT_INTERFACEMETHODREF
+                    : m instanceof Type.Class.Field  ? CONSTANT_FIELDREF 
+                    : m instanceof Type.Class.Method ? CONSTANT_METHODREF
+                    : 0;
             if (tag == 0) throw new Error("should never happen");
-            CPRefEnt ce = new CPRefEnt(tag);
-            ce.e1 = add(key.getDeclaringClass());
-            ce.e2 = addNameAndType(key.name, key.getDescriptor());
-            ent = ce;
-        } else {
+            ent = new MemberEnt(tag, m.getDeclaringClass(), m.name, m.getTypeDescriptor());
+        } 
+        else {
             throw new IllegalArgumentException("Unknown type passed to add");
         }
         
-        int spaces = ent instanceof LongEnt ? 2 : 1;        
+        int spaces = ent.slots();        
         if (usedSlots + spaces > 65536) throw new ClassFile.Exn("constant pool full");
         
         ent.n = state == OPEN ? 1 : usedSlots; // refcount or index
@@ -228,9 +253,9 @@ class ConstantPool {
         return ent;
     }
     
-    public int slots() { return usedSlots; }
+    int slots() { return usedSlots; }
 
-    public void seal() { state = SEALED; }
+    void seal() { state = SEALED; }
     
     private Ent[] asArray() {
         int count = entries.size();
@@ -249,11 +274,11 @@ class ConstantPool {
             Ent ent = ents[i];
             ent.n = index;
             entriesByIndex[index] = ent;
-            index += ent instanceof LongEnt ? 2 : 1;
+            index += ent.slots();
         }
     }
         
-    public void stable() {
+    void stable() {
         if (state != OPEN) return;
         state = STABLE;
         assignIndex(asArray());
@@ -271,7 +296,7 @@ class ConstantPool {
         }
     };
     
-    public void optimize() {
+    void optimize() {
         if (state != OPEN) throw new IllegalStateException("can't optimize a stable constant pool");
         Ent[] ents = asArray();
         Sort.sort(ents, reverseCompareFunc);
@@ -279,18 +304,7 @@ class ConstantPool {
         assignIndex(ents);
     }
     
-    public void unsafeReopen() {
-        if (state == OPEN) return;
-        for(int i=1;i<entriesByIndex.length;i++) {
-            Ent e = entriesByIndex[i];
-            if (e == null) continue;
-            e.n = 0;
-        }
-        entriesByIndex = null;
-        state = OPEN;
-    }
-    
-    public void dump(DataOutput o) throws IOException {
+    void dump(DataOutput o) throws IOException {
         Ent[] ents = asArray();
         Sort.sort(ents, compareFunc);
         o.writeShort(usedSlots);
@@ -304,102 +318,95 @@ class ConstantPool {
         usedSlots = in.readUnsignedShort();
         if (usedSlots==0) throw new ClassFile.ClassReadExn("invalid used slots");
         
-        // these are to remember the CPRefEnt e1 and e2s we have to fix up
+        // these are to remember the descriptor ents we have to fix up
         int[] e1s = new int[usedSlots];
         int[] e2s = new int[usedSlots];
         
         entriesByIndex = new Ent[usedSlots];
         
-        for(int index=1;index<usedSlots;index++) {
+        for(int i=1;i<usedSlots;) {
             byte tag = in.readByte();
             Ent e;
             switch(tag) {
-                case 7: // Object Type
-                case 8: // String
-                case 9: // Type.Class.Field
-                case 10: // Type.Class.Method
-                case 11: // Instance Method Ref
-                case 12: // NameAndType
-                {
-                    e = new CPRefEnt(tag);
-                    e1s[index] = in.readUnsignedShort();
-                    if (tag != 7 && tag != 8) e2s[index] = in.readUnsignedShort();
+                case CONSTANT_CLASS: // Object Type
+                    e = new ClassEnt();
+                    e1s[i] = in.readUnsignedShort();
                     break;
-                }
-                case 3: // Integer
-                {
-                    FloatEnt ie;
-                    e = ie = new FloatEnt(in.readFloat());
+                case CONSTANT_STRING: // String
+                    e = new StringLitEnt();
+                    e1s[i] = in.readUnsignedShort();
                     break;
-                }
-                case 4: // Float
-                {
-                    IntEnt ie;
-                    e = ie = new IntEnt(in.readInt());
+                case CONSTANT_FIELDREF: // Type.Class.Field
+                case CONSTANT_METHODREF: // Type.Class.Method
+                case CONSTANT_INTERFACEMETHODREF: // Instance Method Ref
+                case CONSTANT_NAMEANDTYPE:
+                    e = tag == CONSTANT_NAMEANDTYPE ? (Ent) new NameAndTypeEnt() : (Ent) new MemberEnt(tag);
+                    e1s[i] = in.readUnsignedShort();
+                    e2s[i] = in.readUnsignedShort();
                     break;
-                }
-                case 5: // Long
-                case 6: // Double
-                {
-                    LongEnt le;
-                    e = le = new LongEnt(tag);
-                    le.l = in.readLong();
+                case CONSTANT_INTEGER: // Integer
+                    e = new IntLitEnt(in.readInt());
                     break;
-                }
-                case 1: // Utf8
-                {
-                    Utf8Ent ue;
-                    e = ue = new Utf8Ent();
-                    ue.s = in.readUTF();
+                case CONSTANT_FLOAT: // Float
+                    e = new FloatLitEnt(in.readFloat());
+                    break;
+                case CONSTANT_LONG: // Long
+                    e = new LongLitEnt(in.readLong());
+                    break;
+                case CONSTANT_DOUBLE: // Double
+                    e = new DoubleLitEnt(in.readDouble());
+                    break;
+                case CONSTANT_UTF8: // Utf8
+                    e = new Utf8Ent(in.readUTF());
                     break;
-                }
                 default:
-                    throw new ClassFile.ClassReadExn("invalid cp ent tag");
+                    throw new ClassFile.ClassReadExn("invalid cp ent tag: " + tag + " (slot " + i + ")");
             }
-            entriesByIndex[index] = e;
-            if (e instanceof LongEnt) index++;
+            entriesByIndex[i] = e;
+            i += e.slots();
         }
         
-        for(int i=1;i<usedSlots;i++) {
+        for(int i=1;i<usedSlots;) {
             Ent e = entriesByIndex[i];
             if (e == null) throw new Error("should never happen: " + i + "/"+usedSlots);
-            if (e instanceof LongEnt) {
-                i++;
-                continue;
-            }
-            if (!(e instanceof CPRefEnt)) continue;
-            CPRefEnt ce = (CPRefEnt) e;
-            if (e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp i");
-            ce.e1 = entriesByIndex[e1s[i]];
-            if (ce.e1 == null)  throw new ClassFile.ClassReadExn("invalid cp i");
-            if (ce.tag != 7 && ce.tag != 8) {
-                if (e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp i");
-                ce.e2 = entriesByIndex[e2s[i]];
-                if (ce.e2 == null)  throw new ClassFile.ClassReadExn("invalid cp i");
-            }
-            switch(ce.tag) {
-                case 7:
-                case 8:
-                    if (!(ce.e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
-                    break;
-                case 9:
-                case 10:
-                case 11:
-                    if (!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
-                        throw new ClassFile.ClassReadExn("expected a type ent");
-                    if (!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
-                        throw new ClassFile.ClassReadExn("expected a name and type ent");
-                    break;
-                case 12:
-                    if (!(ce.e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
-                    if (!(ce.e2 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a utf8 ent");
-                    break;
+            boolean isMem = e instanceof MemberEnt;
+            boolean isString = e instanceof StringLitEnt;
+            boolean isClass =  e instanceof ClassEnt;
+            boolean isNameAndType = e instanceof NameAndTypeEnt;
+            if (isMem || isClass || isString || isNameAndType) {
+                if (e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp index");
+                Ent e1 = entriesByIndex[e1s[i]];
+                if(e1 == null) throw new ClassFile.ClassReadExn("invalid cp index");
+                if(isClass) {
+                    if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+                    ((ClassEnt)e).utf8 = (Utf8Ent) e1;
+                } else if(isString) {
+                    if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+                    ((StringLitEnt)e).utf8 = (Utf8Ent) e1;
+                } else if(isMem || isNameAndType) {
+                    if (e2s[i] == 0 || e2s[i] >= usedSlots) throw new ClassFile.ClassReadExn("invalid cp index");
+                    Ent e2 = entriesByIndex[e2s[i]];
+                    if(isMem) {
+                        if(!(e1 instanceof ClassEnt)) throw new ClassFile.ClassReadExn("expected a classent");
+                        if(!(e2 instanceof NameAndTypeEnt)) throw new ClassFile.ClassReadExn("expected a nameandtypeent, not " + e2);
+                        MemberEnt me = (MemberEnt) e;
+                        me.klass = (ClassEnt) e1;
+                        me.member = (NameAndTypeEnt) e2;
+                    } else if(isNameAndType) {
+                        if(!(e1 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+                        if(!(e2 instanceof Utf8Ent)) throw new ClassFile.ClassReadExn("expected a uft8ent");
+                        NameAndTypeEnt nte = (NameAndTypeEnt) e;
+                        nte.name = (Utf8Ent) e1;
+                        nte.type = (Utf8Ent) e2;
+                    }
+                }
             }
+            i += e.slots();
         }
-        for(int i=1; i<usedSlots; i++) {
+        for(int i=1; i<usedSlots;) {
             Ent e = entriesByIndex[i];
             entries.put(e.key(), e);
-            if (e instanceof LongEnt) i++;
+            i += e.slots();
         }
         state = STABLE;
     }