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     */
021    package org.biojava.utils.bytecode;
022    
023    import java.util.*;
024    import java.io.*;
025    
026    /**
027     * Build a Java class file constant pool.
028     *
029     * @author Thomas Down
030     * @author Matthew Pocock
031     */
032    
033    public 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    }