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