totally broken reading support - does not compile
authorbrian <brian@brianweb.net>
Wed, 1 Jun 2005 10:32:37 +0000 (10:32 +0000)
committerbrian <brian@brianweb.net>
Wed, 1 Jun 2005 10:32:37 +0000 (10:32 +0000)
darcs-hash:20050601103237-24bed-7a40ec67b32ab99d56f4545d77db5fc1256d8a4a.gz

src/org/ibex/classgen/CPGen.java
src/org/ibex/classgen/ClassGen.java
src/org/ibex/classgen/Type.java

index 6f390a9..6527816 100644 (file)
@@ -7,6 +7,8 @@ import org.ibex.classgen.util.*;
 
 class CPGen {
     private final Hashtable entries = new Hashtable();
+    private Ent[] entriesByIndex; // only valid when stable
+    
     private int usedSlots = 1; // 0 is reserved
     private int state = OPEN;
     private static final int OPEN = 0;
@@ -18,46 +20,89 @@ class CPGen {
     /*
      * Entries 
      */
-    abstract static class Ent {
+    public abstract static class Ent {
+        CPGen owner; // don't need this yet, but we will to implement ref() and unref()
         int n; // this is the refcount if state == OPEN, index if >= STABLE
         int tag;
         
-        Ent(int tag) { this.tag = tag; }
+        Ent(CPGen owner, int tag) { this.owner = owner; 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 ClassGen.ClassReadExn; // be careful using this, it drags in a bunch of code
     }
     
+    // INVARIANTS: tag == 3 || tag == 4
     static class IntEnt extends Ent {
         int i;
-        IntEnt(int tag) { super(tag); }
+        IntEnt(CPGen owner, int tag) { super(owner,tag); }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i);  }
+        Object key() {
+            switch(tag) {
+                case 3: return new Integer(i);
+                case 4: return new Float(Float.intBitsToFloat(i));
+                default: throw new Error("should never happen");
+            }
+        }
     }
     
+    // INVARIANTS: tag == 5 || tag == 6
     static class LongEnt extends Ent {
         long l;
-        LongEnt(int tag) { super(tag); }
+        LongEnt(CPGen owner, int tag) { super(owner,tag); }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
+        Object key() {
+            switch(tag) {
+                case 5: return new Long(l);
+                case 6: return new Double(Double.longBitsToDouble(l));
+                default: throw new Error("should never happen");
+            }
+        }
     }
     
+    /* 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
+        }
+    */
     static class CPRefEnt extends Ent {
         Ent e1;
         Ent e2;
-        CPRefEnt(int tag) { super(tag); }
+        CPRefEnt(CPGen owner, int tag) { super(owner,tag); }
         
         String debugToString() { return "[" + e1.n + ":" + e1.debugToString() + (e2 == null ? "" : " + " + e2.n + ":" + e2.debugToString()) + "]"; }
         
         void dump(DataOutput o) throws IOException {
             super.dump(o);
-            if(e1.n == 6 || (e2!=null && e2.n == 6)) System.err.println(debugToString() + " refs 6");
             o.writeShort(e1.n);
             if(e2 != null) o.writeShort(e2.n);
         }
+        
+        Object key() throws ClassGen.ClassReadExn {
+            switch(tag) {
+                case 7: return new Type.Object(((Utf8Ent)e0).s);
+                case 8: return (((Utf8Ent)e1).s);
+                case 9:
+                    NameAndTypeKey nt = (NameAndTypeKey) e2.key();
+                    Type t = Type.fromDescriptor(nt.type);
+                    if(t == null) throw new ClassGen.ClassReadExn("invalid type descriptor");
+                    return FieldRef((Type.Object)e1.key(), nt.name, t);
+                case 10:
+                    NameAndTypeKey nt = (NameAndTypeKey) e2.key();
+                    return MethodRef((Type.Object)e1.key(),throw new Error("fixme"));
+            }
+        }
     }
         
     static class Utf8Ent extends Ent {
         String s;
-        Utf8Ent() { super(1); }
+        Utf8Ent(CPGen owner) { super(owner,1); }
         String debugToString() { return s; }
         void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
     }
@@ -65,14 +110,14 @@ class CPGen {
     /*
      * Cache Keys
      */
-    static class Utf8Key {
+    public 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(); }
     }
         
-    static class NameAndTypeKey {
+    public static class NameAndTypeKey {
         String name;
         String type;
         NameAndTypeKey(String name, String type) { this.name = name; this.type = type; }
@@ -104,6 +149,14 @@ class CPGen {
         if(state < STABLE) throw new IllegalStateException("constant pool is not stable");
         return ent.n;
     }
+
+    public final 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");
+        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)); }
@@ -118,35 +171,35 @@ class CPGen {
         }
         
         if(o instanceof Type.Object) {
-            CPRefEnt ce = new CPRefEnt(7);
+            CPRefEnt ce = new CPRefEnt(this,7);
             ce.e1 = addUtf8(((Type.Object)o).internalForm());
             ent = ce;
         } else if(o instanceof String) {
-            CPRefEnt ce = new CPRefEnt(8);
+            CPRefEnt ce = new CPRefEnt(this,8);
             ce.e1 = addUtf8((String)o);
             ent = ce;
         } else if(o instanceof Integer) {
-            IntEnt ue = new IntEnt(3);
+            IntEnt ue = new IntEnt(this,3);
             ue.i = ((Integer)o).intValue();
             ent = ue;
         } else if(o instanceof Float) {
-            IntEnt ue = new IntEnt(4);
+            IntEnt ue = new IntEnt(this,4);
             ue.i = Float.floatToIntBits(((Float)o).floatValue());
             ent = ue;
         } else if(o instanceof Long) {
-            LongEnt le = new LongEnt(5);
+            LongEnt le = new LongEnt(this,5);
             le.l = ((Long)o).longValue();
             ent = le;
         } else if(o instanceof Double) {
-            LongEnt le = new LongEnt(6);
+            LongEnt le = new LongEnt(this,6);
             le.l = Double.doubleToLongBits(((Double)o).doubleValue());
             ent = le;
         } else if(o instanceof Utf8Key) {
-            Utf8Ent ue = new Utf8Ent();
+            Utf8Ent ue = new Utf8Ent(this);
             ue.s = ((Utf8Key)o).s;
             ent = ue;
         } else if(o instanceof NameAndTypeKey) {
-            CPRefEnt ce = new CPRefEnt(12);
+            CPRefEnt ce = new CPRefEnt(this,12);
             NameAndTypeKey key = (NameAndTypeKey) o;
             ce.e1 = addUtf8(key.name);
             ce.e2 = addUtf8(key.type);
@@ -155,7 +208,7 @@ class CPGen {
             ClassGen.FieldOrMethodRef key = (ClassGen.FieldOrMethodRef) o;
             int tag = o instanceof FieldRef ? 9 : o instanceof MethodRef ? 10 : o instanceof MethodRef.I ? 11 : 0;
             if(tag == 0) throw new Error("should never happen");
-            CPRefEnt ce = new CPRefEnt(tag);
+            CPRefEnt ce = new CPRefEnt(this,tag);
             ce.e1 = add(key.klass);
             ce.e2 = addNameAndType(key.name,key.descriptor);
             ent = ce;
@@ -188,11 +241,13 @@ class CPGen {
         return ents;
     }
     
-    private static void assignIndex(Ent[] ents) {
+    private void assignIndex(Ent[] ents) {
         int index = 1;
+        entriesByIndex = new Ent[ents.length*2];
         for(int i=0;i<ents.length;i++) {
             Ent ent = ents[i];
             ent.n = index;
+            entriesByIndex[index] = ent;
             index += ent instanceof LongEnt ? 2 : 1;
         }
     }
@@ -223,12 +278,118 @@ class CPGen {
         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 {
         Ent[] ents = asArray();
         Sort.sort(ents,compareFunc);
+        o.writeShort(usedSlots);
         for(int i=0;i<ents.length;i++) {
             //System.err.println("" + ents[i].n + ": " + ents[i].debugToString());
             ents[i].dump(o);
         }
     }
+    
+    CPGen(DataInput in) throws ClassGen.ClassReadExn {
+        usedSlots = i.readUnsignedShort();
+        if(usedSlots==0) throw new ClassGen.ClassReadExn("invalid used slots");
+        
+        // these are to remember the CPRefEnt e0 and e1s 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++) {
+            byte tag = i.readByte();
+            Ent e;
+            switch(tag) {
+                case 7: // Object Type
+                case 8: // String
+                case 9: // FieldRef
+                case 10: // MethodRef
+                case 11: // Instance Method Ref
+                case 12: // NameAndType
+                {
+                    e = new CPRefEnt(this,tag);
+                    e1s[index] = i.readUnsignedShort();;
+                    if(tag != 7 && tag != 8) e2s[index] = i.readUnsignedShort();
+                    break;
+                }
+                case 3: // Integer
+                case 4: // Float
+                {
+                    IntEnt ie;
+                    e = ie = new IntEnt(this,tag);
+                    ie.i = i.readInt();
+                    break;
+                }
+                case 5: // Long
+                case 6: // Double
+                {
+                    LongEnt le;
+                    e = le = new LongEnt(this,tag);
+                    le.l = i.readLong();
+                    index++;
+                    break;
+                }
+                case 1: // Utf8
+                {
+                    Utf8Ent ue;
+                    e = ue = new Utf8Ent(this);
+                    ue.s = i.readUTF();
+                    break;
+                }
+                default:
+                    throw new ClassGen.ClassReadExn("invalid cp ent tag");
+            }
+            entriesByIndex[index] = e;
+        }
+        
+        for(int index=1;index<usedSlots;index++) {
+            Ent e = entriesByIndex[index];
+            if(e == null) throw new Error("should never happen");
+            if(e instanceof CPRefEnt) {
+                CPRefEnt ce = (CPRefEnt) e;
+                if(e0s[i] == 0 || e0s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
+                ce.e0 = entriesByIndex[e0s[i]];
+                if(ce.e0 == null)  throw new ClassGen.ClassReadExn("invalid cp index");
+                if(ce.tag != 7 && ce.tag != 8) {
+                    if(e1s[i] == 0 || e1s[i] >= usedSlots) throw new ClassGen.ClassReadExn("invalid cp index");
+                    ce.e1 = entriesByIndex[e1s[i]];
+                    if(ce.e1 == null)  throw new ClassGen.ClassReadExn("invalid cp index");
+                }
+                switch(ce.tag) {
+                    case 7:
+                    case 8:
+                        if(!(ce.e0 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
+                        break;
+                    case 9:
+                    case 10:
+                    case 11:
+                        if(!(ce.e1 instanceof CPRefEnt) || ((CPRefEnt)ce.e1).tag != 7)
+                            throw new ClassGen.ClassReadExn("expected a type ent");
+                        if(!(ce.e2 instanceof CPRefEnt) || ((CPRefEnt)ce.e2).tag != 12)
+                            throw new ClassGen.ClassReadExn("expected a name and type ent");
+                        break;
+                    case 12:
+                        if(!(ce.e1 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
+                        if(!(ce.e2 instanceof Utf8Ent)) throw new ClassGen.ClassReadExn("expected a utf8 ent");
+                }
+            } else if(e instanceof LongEnt) {
+                index++;
+            }
+            entries.put(e.key(),e);
+        }
+        state = STABLE;
+    }
 }
index ddbf8a1..451bb74 100644 (file)
@@ -101,7 +101,9 @@ public class ClassGen implements CGConst {
             }
             f = new File(f,a[i] + ".class");
         }
-        dump(new FileOutputStream(f));
+        OutputStream os = new FileOutputStream(f);
+        dump(os);
+        os.close();
     }
    
     /** Writes the classfile data to the outputstream specified
@@ -134,7 +136,6 @@ public class ClassGen implements CGConst {
         o.writeShort(3); // minor_version
         o.writeShort(45); // major_version
         
-        o.writeShort(cp.slots()); // constant_pool_count
         cp.dump(o); // constant_pool
         
         o.writeShort(flags);
@@ -154,12 +155,35 @@ public class ClassGen implements CGConst {
         attributes.dump(o); // attributes        
     }
     
+    public ClassGen read(File f) throws ClassReadExn {
+        InputStream is = new FileInputStream(f);
+        ClassGen ret = read(is);
+        is.close();
+        return ret;
+    }
+    
+    public ClassGen read(InputStream is) throws ClassReadExn {
+        return new ClassGen(new DataInputStream(new BufferedInputStream(is)));
+    }
+
+    ClassGen(DataInput i) throws ClassReadExn {
+        if(i.readInt() != 0xcadebabe) throw new ClassReadExn("invalid magic");
+        short minor = i.readInt();
+        if(minor != 3) throw new ClassReadExn("invalid minor version: " + minor);
+        if(i.readInt() != 45) throw new ClassReadExn("invalid major version");
+        cp = new CPGen(i);
+    }
+    
     /** Thrown when class generation fails for a reason not under the control of the user
         (IllegalStateExceptions are thrown in those cases */
     public static class Exn extends RuntimeException {
         public Exn(String s) { super(s); }
     }
     
+    public static class ClassReadExn extends IOException {
+        public ClassReadExn(String s) { super(s); }
+    }
+    
     /** A class representing a field or method reference. This is used as an argument to the INVOKE*, GET*, and PUT* bytecodes
         @see MethodRef
         @see FieldRef
index ec6d834..ec5a30a 100644 (file)
@@ -27,6 +27,20 @@ public class Type {
     
     Type(String descriptor) { this.descriptor = descriptor; }
     
+    public static Type fromDescriptor(String descriptor) {
+        if(descriptor.equals("V")) return VOID;
+        if(descriptor.equals("I")) return INT;
+        if(descriptor.equals("J")) return LONG;
+        if(descriptor.equals("Z")) return BOOLEAN;
+        if(descriptor.equals("D")) return DOUBLE;
+        if(descriptor.equals("F")) return FLOAT;
+        if(descriptor.equals("B")) return BYTE;
+        if(descriptor.equals("C")) return CHAR;
+        if(descriptor.equals("S")) return SHORT;
+        if(Type.Object.validDescriptorString(descriptor)) return new Type.Object(descriptor);
+        return null;
+    }
+        
     /** Returns the Java descriptor string for this object ("I", or "Ljava/lang/String", "[[J", etc */
     public final String getDescriptor() { return descriptor; }
     public int hashCode() { return descriptor.hashCode(); }
@@ -71,7 +85,6 @@ public class Type {
         
         String internalForm() { return descriptor.substring(1,descriptor.length()-1); }
         
-        // FEATURE: Do a proper check here (invalid chars, etc)
         static boolean validDescriptorString(String s) {
             return s.startsWith("L") && s.endsWith(";");
         }