sort of working
[org.ibex.classgen.git] / src / org / ibex / classgen / CPGen.java
1 package org.ibex.classgen;
2
3 import java.util.*;
4 import java.io.*;
5
6 import org.ibex.classgen.util.*;
7
8 public class CPGen {
9     private Hashtable entries = new Hashtable();
10     private int nextIndex = 1; // 0 is reserved
11     private boolean sealed;
12     
13     CPGen() { }
14     
15     /*
16      * Entries 
17      */
18     abstract static class Ent implements Sort.Comparable {
19         int index;
20         public abstract int tag();
21         public void dump(DataOutput o) throws IOException { o.writeByte(tag()); }
22         public int compareTo(Object o) {
23             if(!(o instanceof Ent)) return 1;
24             int oi = ((Ent)o).index;
25             if(index < oi) return -1;
26             if(index > oi) return 1;
27             return 0;
28         }
29     }
30     
31     abstract static class OneU2Ent extends Ent      { int i;  public void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(i);  } }
32     abstract static class OneU4Ent extends Ent      { int i;  public void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i);    } }
33     abstract static class TwoU2Ent extends OneU2Ent { int i2; public void dump(DataOutput o) throws IOException { super.dump(o); o.writeShort(i2); } }
34     abstract static class TwoU4Ent extends OneU4Ent { int i2; public void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i2);   } }
35     
36     static class IntEnt         extends OneU4Ent { public int tag() { return 3;  } } // word1: bytes
37     static class FloatEnt       extends OneU4Ent { public int tag() { return 4;  } } // word1: bytes
38     static class LongEnt        extends TwoU4Ent { public int tag() { return 5;  } } // word1/2: bytes
39     static class DoubleEnt      extends TwoU4Ent { public int tag() { return 6;  } } // word1/2: bytes
40     static class ClassEnt       extends OneU2Ent { public int tag() { return 7;  } } // word1: name_index
41     static class StringEnt      extends OneU2Ent { public int tag() { return 8;  } } // word1: string_index
42     static class FieldRefEnt    extends TwoU2Ent { public int tag() { return 9;  } } // word1: class_index word2: name_and_type_index
43     static class MethodRefEnt   extends TwoU2Ent { public int tag() { return 10; } } // word1: class_index word2: name_and_type_index
44     static class IMethodRefEnt  extends TwoU2Ent { public int tag() { return 11; } } // word1: class_index word2: name_and_type_index
45     static class NameAndTypeEnt extends TwoU2Ent { public int tag() { return 12; } } // word1: name_index  word2: descriptor_index
46     
47     static class Utf8Ent extends Ent {
48         String s;
49         public int tag() { return 1; }
50         public void dump(DataOutput o) throws IOException {
51             super.dump(o);
52             o.writeUTF(s);
53         }
54         public String toString() { return "Utf8: " + s; }
55     }
56     
57     /*
58      * Cache Keys
59      */
60     static class Utf8Key {
61         String s;
62         public Utf8Key(String s) { this.s = s; }
63         public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
64         public int hashCode() { return ~s.hashCode(); }
65     }
66     
67     public static class NameAndType {
68         String name;
69         String type;
70         public NameAndType(String name, String type) { this.name = name; this.type = type; }
71         public boolean equals(Object o_) {
72             if(!(o_ instanceof NameAndType)) return false;
73             NameAndType o = (NameAndType) o_;
74             return o.name.equals(name) && o.type.equals(type);
75         }
76         public int hashCode() { return name.hashCode() ^ type.hashCode(); }
77     }
78     
79     static abstract class FieldMethodRef {
80         Type.Object klass;
81         NameAndType nameAndType;
82         public FieldMethodRef(Type.Object klass, NameAndType nameAndType) { this.klass = klass; this.nameAndType = nameAndType; }
83         public boolean equals(Object o_) {
84             if(!(o_ instanceof FieldMethodRef)) return false;
85             FieldMethodRef o = (FieldMethodRef) o_;
86             return o.klass.equals(klass) && o.nameAndType.equals(nameAndType);
87         }
88     }
89     
90     public static class FieldRef   extends FieldMethodRef { public FieldRef  (Type.Object c, NameAndType t) { super(c,t); } }
91     public static class MethodRef  extends FieldMethodRef { public MethodRef (Type.Object c, NameAndType t) { super(c,t); } }
92     public static class IMethodRef extends FieldMethodRef { public IMethodRef(Type.Object c, NameAndType t) { super(c,t); } }
93     
94     /*
95      * Methods
96      */
97     public void seal() { sealed = true; }
98     
99     public final Ent get(Object o) { return (Ent) entries.get(o); }
100     public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
101     
102     public final Ent addNameAndType(String name, String descriptor) { return add(new NameAndType(name,descriptor)); }
103     public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
104     
105     public final Ent add(Object o) {
106         if(sealed) throw new IllegalStateException("constant pool is sealed");
107             
108         Ent ent = get(o);
109         if(ent != null) return ent;
110         
111         if(nextIndex == 65536) throw new ClassGen.Exn("constant pool full");
112         
113         if(o instanceof Type.Object) {
114             ClassEnt ce = new ClassEnt();
115             ce.i = addUtf8(((Type.Object)o).internalForm()).index;
116             ent = ce;
117         } else if(o instanceof String) {
118             StringEnt se = new StringEnt();
119             se.i = addUtf8((String)o).index;
120             ent = se;
121         } else if(o instanceof Integer) {
122             IntEnt ie = new IntEnt();
123             ie.i = ((Integer)o).intValue();
124             ent = ie;
125         } else if(o instanceof Float) {
126             FloatEnt fe = new FloatEnt();
127             fe.i = Float.floatToIntBits(((Float)o).floatValue());
128             ent = fe;
129         } else if(o instanceof Long) {
130             LongEnt le = new LongEnt();
131             long l = ((Long)o).longValue();
132             le.i = (int)(l>>>32);
133             le.i2 = (int)l;
134             ent = le;
135         } else if(o instanceof Double) {
136             DoubleEnt de = new DoubleEnt();
137             long l = Double.doubleToLongBits(((Double)o).doubleValue());
138             de.i = (int)(l>>>32);
139             de.i2 = (int)l;
140             ent = de;
141         } else if(o instanceof Utf8Key) {
142             Utf8Ent ue = new Utf8Ent();
143             ue.s = ((Utf8Key)o).s;
144             ent = ue;
145         } else if(o instanceof NameAndType) {
146             NameAndTypeEnt ne = new NameAndTypeEnt();
147             NameAndType key = (NameAndType) o;
148             ne.i = addUtf8(key.name).index;
149             ne.i2 = addUtf8(key.type).index;
150             ent = ne;
151         } else if(o instanceof FieldMethodRef) {
152             FieldMethodRef key = (FieldMethodRef) o;
153             TwoU2Ent fme;
154             if(o instanceof MethodRef) fme = new MethodRefEnt();
155             else if(o instanceof IMethodRef) fme = new IMethodRefEnt();
156             else if(o instanceof FieldRef) fme = new FieldRefEnt();
157             else throw new Error("should never happen");
158             fme.i = add(key.klass).index;
159             fme.i2 = add(key.nameAndType).index;
160             ent = fme;
161         } else {
162             throw new IllegalArgumentException("Unknown type passed to add");
163         }
164         
165         ent.index = nextIndex++;
166         entries.put(o,ent);
167         return ent;
168     }
169     
170     public int size() { return nextIndex; }
171     
172     public void dump(DataOutput o) throws IOException {
173         Ent[] ents = new Ent[nextIndex-1];
174         int i=0;
175         Enumeration e = entries.keys();
176         while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
177         Sort.sort(ents);
178         for(i=0;i<ents.length;i++) {
179             //System.err.println("" + (i+1) + ": " + ents[i]);
180             ents[i].dump(o);
181         }
182     }
183 }