tons more stuff
[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 // FEATURE: Add a "hit count" to each entry and optimize the table
9
10 class CPGen {
11     private Hashtable entries = new Hashtable();
12     private int nextIndex = 1; // 0 is reserved
13     private int count;
14     private boolean sealed;
15     
16     CPGen() { }
17     
18     /*
19      * Entries 
20      */
21     abstract static class Ent {
22         int index;
23         int tag;
24         
25         Ent(int tag) { this.tag = tag; }
26         
27         int getIndex() { return index; }
28         
29         void dump(DataOutput o) throws IOException { o.writeByte(tag); }
30     }
31     
32     static class OneU4Ent extends Ent {
33         int i;
34         OneU4Ent(int tag) { super(tag); }
35         void dump(DataOutput o) throws IOException { super.dump(o); o.writeInt(i);  }
36     }
37     
38     static class LongEnt extends Ent {
39         long l;
40         LongEnt(int tag) { super(tag); }
41         void dump(DataOutput o) throws IOException { super.dump(o); o.writeLong(l); }
42     }
43     
44     static class CPRefEnt extends Ent {
45         Ent e1;
46         Ent e2;
47         CPRefEnt(int tag) { super(tag); }
48         void dump(DataOutput o) throws IOException {
49             super.dump(o);
50             o.writeShort(e1.index);
51             if(e2 != null) o.writeShort(e2.index);
52         }
53     }
54         
55     static class Utf8Ent extends Ent {
56         String s;
57         Utf8Ent() { super(1); }
58         void dump(DataOutput o) throws IOException { super.dump(o); o.writeUTF(s); }
59     }
60     
61     /*
62      * Cache Keys
63      */
64     static class Utf8Key {
65         String s;
66         public Utf8Key(String s) { this.s = s; }
67         public boolean equals(Object o) { return o instanceof Utf8Key && ((Utf8Key)o).s.equals(s); }
68         public int hashCode() { return ~s.hashCode(); }
69     }
70         
71     /*
72      * Methods
73      */
74     public void seal() { sealed = true; }
75     
76     public final Ent get(Object o) { return (Ent) entries.get(o); }
77     public final Ent getUtf8(String s) { return get(new Utf8Key(s)); }
78     public final int getIndex(Object o) {
79         Ent e = get(o);
80         if(e == null) throw new IllegalStateException("entry not found");
81         return e.getIndex();
82     }
83     public final int getUtf8Index(String s) {
84         Ent e = getUtf8(s);
85         if(e == null) throw new IllegalStateException("entry not found");
86         return e.getIndex();
87     }
88     
89     public final Ent addNameAndType(String name, String descriptor) { return add(new ClassGen.NameAndType(name,descriptor)); }
90     public final Ent addUtf8(String s) { return add(new Utf8Key(s)); }
91     
92     // FEATURE: Don't resolve indexes until dump (for optimize) 
93     public final Ent add(Object o) {
94         if(sealed) throw new IllegalStateException("constant pool is sealed");
95             
96         Ent ent = get(o);
97         if(ent != null) return ent;
98         
99         if(nextIndex == 65536) throw new ClassGen.Exn("constant pool full");
100         
101         if(o instanceof Type.Object) {
102             CPRefEnt ce = new CPRefEnt(7);
103             ce.e1 = addUtf8(((Type.Object)o).internalForm());
104             ent = ce;
105         } else if(o instanceof String) {
106             CPRefEnt ce = new CPRefEnt(8);
107             ce.e1 = addUtf8((String)o);
108             ent = ce;
109         } else if(o instanceof Integer) {
110             OneU4Ent ue = new OneU4Ent(3);
111             ue.i = ((Integer)o).intValue();
112             ent = ue;
113         } else if(o instanceof Float) {
114             OneU4Ent ue = new OneU4Ent(4);
115             ue.i = Float.floatToIntBits(((Float)o).floatValue());
116             ent = ue;
117         } else if(o instanceof Long) {
118             LongEnt le = new LongEnt(5);
119             le.l = ((Long)o).longValue();
120             ent = le;
121         } else if(o instanceof Double) {
122             LongEnt le = new LongEnt(6);
123             le.l = Double.doubleToLongBits(((Double)o).doubleValue());
124             ent = le;
125         } else if(o instanceof Utf8Key) {
126             Utf8Ent ue = new Utf8Ent();
127             ue.s = ((Utf8Key)o).s;
128             ent = ue;
129         } else if(o instanceof ClassGen.NameAndType) {
130             CPRefEnt ce = new CPRefEnt(12);
131             ClassGen.NameAndType key = (ClassGen.NameAndType) o;
132             ce.e1 = addUtf8(key.name);
133             ce.e2 = addUtf8(key.type);
134             ent = ce;
135         } else if(o instanceof ClassGen.FieldMethodRef) {
136             ClassGen.FieldMethodRef key = (ClassGen.FieldMethodRef) o;
137             int tag = o instanceof FieldRef ? 9 : o instanceof MethodRef ? 10 : o instanceof ClassGen.InterfaceMethodRef ? 11 : 0;
138             if(tag == 0) throw new Error("should never happen");
139             CPRefEnt ce = new CPRefEnt(tag);
140             ce.e1 = add(key.klass);
141             ce.e2 = add(key.nameAndType);
142             ent = ce;
143         } else {
144             throw new IllegalArgumentException("Unknown type passed to add");
145         }
146         
147         ent.index = nextIndex++;
148         if(ent instanceof LongEnt) nextIndex++;
149         count++;
150
151         entries.put(o,ent);
152         return ent;
153     }
154     
155     public int size() { return nextIndex; }
156     
157     private static final Sort.CompareFunc compareFunc = new Sort.CompareFunc() {
158         public int compare(Object a_, Object b_) {
159             return ((Ent)a_).index - ((Ent)b_).index;
160         }
161     };
162     public void dump(DataOutput o) throws IOException {
163         Ent[] ents = new Ent[count];
164         int i=0;
165         Enumeration e = entries.keys();
166         while(e.hasMoreElements()) ents[i++] = (Ent) entries.get(e.nextElement());
167         if(i != count) throw new Error("should never happen");
168         Sort.sort(ents,compareFunc);
169         for(i=0;i<ents.length;i++) {
170             //System.err.println("" + (i+1) + ": " + ents[i]);
171             ents[i].dump(o);
172         }
173     }
174 }