001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.utils.bytecode;
022
023import java.util.*;
024import java.io.*;
025
026/**
027 * Build a Java class file constant pool.
028 *
029 * @author Thomas Down
030 * @author Matthew Pocock
031 */
032
033public class ConstantPool {
034    private static final byte CONSTANT_Class = 7;
035    private static final byte CONSTANT_Fieldref = 9;
036    private static final byte CONSTANT_Methodref = 10;
037    private static final byte CONSTANT_InterfaceMethodref = 11;
038    private static final byte CONSTANT_String = 8;
039    private static final byte CONSTANT_Integer = 3;
040    private static final byte CONSTANT_Float = 4;
041    private static final byte CONSTANT_Long = 5;
042    private static final byte CONSTANT_Double = 6;
043    private static final byte CONSTANT_NameAndType = 12;
044    private static final byte CONSTANT_Utf8 = 1;
045
046    private List constants;
047
048    {
049        constants = new ArrayList();
050        constants.add(null); // Initial padder.
051    }
052   
053    // Publically visible constant types
054
055    public int resolveClass(CodeClass c) {
056        return resolve(new CPTypedStringEntry(CONSTANT_Class, resolveUtf8(c.getJName())));
057    }
058
059    public int resolveField(CodeField f) {
060      try {
061        return resolve(new CPRefEntry(CONSTANT_Fieldref, resolveClass(f.getContainingClass()), resolveNameAndType(f.getName(), f.getType().getDescriptor())));
062      } catch (NullPointerException npe) {
063        throw new Error("Can't resolve filed " + f);
064      }
065    }
066
067    public int resolveMethod(CodeMethod m) {
068        return resolve(new CPRefEntry(CONSTANT_Methodref, resolveClass(m.getContainingClass()), resolveNameAndType(m.getName(), m.getDescriptor())));
069    }
070
071    public int resolveInterfaceMethod(CodeMethod m) {
072        return resolve(new CPRefEntry(CONSTANT_InterfaceMethodref, resolveClass(m.getContainingClass()), resolveNameAndType(m.getName(), m.getDescriptor())));
073    }
074
075    public int resolveString(String s) {
076        return resolve(new CPTypedStringEntry(CONSTANT_String, resolveUtf8(s)));
077    }
078
079    public int resolveInt(int i) {
080        return resolve(new CPIntEntry(i));
081    }
082
083    public int resolveFloat(float f) {
084        return resolve(new CPFloatEntry(f));
085    }
086
087    public int resolveLong(long l) {
088        return resolve(new CPLongEntry(l));
089    }
090
091    public int resolveDouble(double d) {
092        return resolve(new CPDoubleEntry(d));
093    }
094
095    // internal resolvers
096
097    public int resolveUtf8(String s) {
098        return resolve(new CPUtf8Entry(s));
099    }
100
101    public int resolveNameAndType(String name, String desc) {
102        return resolve(new CPNameAndTypeEntry(resolveUtf8(name), resolveUtf8(desc)));
103    }
104
105    // The master resolver
106
107    private int resolve(CPEntry e) {
108        for (int i = 1; i < constants.size(); ++i) {
109            CPEntry e2 = (CPEntry) constants.get(i);
110            if (e2 != null && e.equals(e2))
111                return i;
112        }
113        int i = constants.size();
114        constants.add(e);
115        for (int k = 1; k < e.needSlots(); ++k)
116            constants.add(null);
117        return i;
118    }
119
120    // Output again
121
122    public int constantPoolSize() {
123        return constants.size();
124    }
125
126  public void writeConstantPool(DataOutput d) throws IOException {
127//    int count = 1;
128    for (Iterator i = constants.iterator(); i.hasNext(); ) {
129            CPEntry e = (CPEntry) i.next();
130            if (e != null) {
131//        System.out.println("Writing constant " + count + " " + e);
132//        count += e.needSlots();
133        e.write(d);
134      }
135    }
136  }
137  
138    // Types for storing the cpool
139
140    private static interface CPEntry {
141        public void write(DataOutput d) throws IOException;
142        public int needSlots();
143    }
144
145    private static class CPTypedStringEntry implements CPEntry {
146        byte tag;
147        int name;
148
149        CPTypedStringEntry(byte tag, int name) {
150            this.tag = tag;
151            this.name = name;
152        }
153
154        public boolean equals(Object o) {
155            if (! (o instanceof CPTypedStringEntry))
156                return false;
157
158            CPTypedStringEntry cte = (CPTypedStringEntry) o;
159            return (cte.name == name && cte.tag == tag);
160        }
161
162        public void write(DataOutput d) throws IOException {
163            d.writeByte(tag);
164            d.writeShort(name);
165        }
166
167        public int needSlots() {
168            return 1;
169        }
170  
171  public String toString() {
172    return "CPTypedStringEntry tag=" + tag + " name=" + name;
173  }
174    }
175
176    private static class CPRefEntry implements CPEntry {
177        byte tag;
178        int clazz;
179        int name;
180
181        CPRefEntry(byte tag, int clazz, int name) {
182            this.tag = tag;
183            this.clazz = clazz;
184            this.name = name;
185        }
186
187        public boolean equals(Object o) {
188            if (! (o instanceof CPRefEntry))
189                return false;
190
191            CPRefEntry cte = (CPRefEntry) o;
192            return (cte.clazz == clazz && cte.name == name && cte.tag == tag);
193        }
194
195        public void write(DataOutput d) throws IOException {
196            d.writeByte(tag);
197            d.writeShort(clazz);
198            d.writeShort(name);
199        }
200
201        public int needSlots() {
202            return 1;
203        }
204  
205  public String toString() {
206    return "CPRefEntry tag=" + tag + " class=" + clazz + " name=" + name;
207  }
208    }
209
210    private static class CPIntEntry implements CPEntry {
211        int val;
212
213        CPIntEntry(int val) {
214            this.val = val;
215        }
216
217        public boolean equals(Object o) {
218            if (! (o instanceof CPIntEntry))
219                return false;
220
221            return (((CPIntEntry) o).val == val);
222        }
223
224        public void write(DataOutput d) throws IOException {
225            d.writeByte(CONSTANT_Integer);
226            d.writeInt(val);
227        }
228
229        public int needSlots() {
230            return 1;
231        }
232  
233  public String toString() {
234    return "CPIntEntry val=" + val;
235  }
236    }
237
238    private static class CPLongEntry implements CPEntry {
239        long val;
240
241        CPLongEntry(long val) {
242            this.val = val;
243        }
244
245        public boolean equals(Object o) {
246            if (! (o instanceof CPLongEntry))
247                return false;
248
249            return (((CPLongEntry) o).val == val);
250        }
251
252        public void write(DataOutput d) throws IOException {
253            d.writeByte(CONSTANT_Long);
254            d.writeLong(val);
255        }
256
257        public int needSlots() {
258            return 2;
259        }
260  
261  public String toString() {
262    return "CPLongEntry val=" + val;
263  }
264    }
265
266    private static class CPFloatEntry implements CPEntry {
267        float val;
268
269        CPFloatEntry(float val) {
270            this.val = val;
271        }
272
273        public boolean equals(Object o) {
274            if (! (o instanceof CPFloatEntry))
275                return false;
276
277            return
278        (((CPFloatEntry) o).val == val) ||
279        (Float.isNaN(((CPFloatEntry) o).val) && Float.isNaN(val));
280        }
281
282        public void write(DataOutput d) throws IOException {
283            d.writeByte(CONSTANT_Float);
284            d.writeFloat(val);
285        }
286
287        public int needSlots() {
288            return 1;
289        }
290  
291  public String toString() {
292    return "CPFloatEntry val=" + val;
293  }
294    }
295
296    private static class CPDoubleEntry implements CPEntry {
297        double val;
298
299        CPDoubleEntry(double val) {
300            this.val = val;
301        }
302
303        public boolean equals(Object o) {
304            if (! (o instanceof CPDoubleEntry))
305                return false;
306
307            return
308        (((CPDoubleEntry) o).val == val) ||
309        (Double.isNaN(((CPDoubleEntry) o).val) && Double.isNaN(val));
310        }
311
312        public void write(DataOutput d) throws IOException {
313            d.writeByte(CONSTANT_Double);
314            d.writeDouble(val);
315        }
316
317        public int needSlots() {
318            return 2;
319        }
320  
321  public String toString() {
322    return "CPDoubleEntry val=" + val;
323  }
324    }
325
326    private static class CPUtf8Entry implements CPEntry {
327        String val;
328
329        CPUtf8Entry(String val) {
330            this.val = val;
331        }
332
333        public boolean equals(Object o) {
334            if (! (o instanceof CPUtf8Entry))
335                return false;
336
337            return (((CPUtf8Entry) o).val.equals(val));
338        }
339
340        public void write(DataOutput d) throws IOException {
341            d.writeByte(CONSTANT_Utf8);
342            d.writeUTF(val);
343        }
344
345        public int needSlots() {
346            return 1;
347        }
348  
349  public String toString() {
350    return "CPUtf8Entry val=" + val;
351  }
352    }
353
354    private static class CPNameAndTypeEntry implements CPEntry {
355        int name;
356        int desc;
357
358        CPNameAndTypeEntry(int name, int desc) {
359            this.name = name;
360            this.desc = desc;
361        }
362
363        public boolean equals(Object o) {
364            if (! (o instanceof CPNameAndTypeEntry))
365                return false;
366
367            CPNameAndTypeEntry cpnte = (CPNameAndTypeEntry) o;
368            return (cpnte.desc == desc && cpnte.name == name);
369        }
370
371        public void write(DataOutput d) throws IOException {
372            d.writeByte(CONSTANT_NameAndType);
373            d.writeShort(name);
374            d.writeShort(desc);
375        }
376
377        public int needSlots() {
378            return 1;
379        }
380  
381  public String toString() {
382    return "CPNameAndTypeEntry name=" + name + " desc=" + desc;
383  }
384    }
385}