KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sli > kim > classfile > ConstPool


1 package sli.kim.classfile;
2
3 import java.util.*;
4 import java.io.*;
5
6 /**
7 * This class encapsulates constant pool management. Classfiles use
8 * constant pools to store information such as class names, method
9 * names, type signatures, and literals like "Hello World" or 123. When
10 * the information is needed (like for a method declaration), an index
11 * into the constant pool is given instead of the actual information.
12 * This can reduce the size of a classfile dramatically if the same
13 * information is used frequently.
14 *
15 * <p>ClassFileReaders and ClassFileWriters usually try to convert
16 * constant pool indexes into meaningful data (eg ClassInfo.setName()
17 * takes a String instead of a constant pool index). So you probably
18 * won't need to use this class unless you need to work with attributes
19 * that the ClassFileReader/Writer doesn't understand, such as
20 * bytecodes.
21 *
22 * <p>The constant pool is a 0-based array of entries. The entry at
23 * index 0 is never used. That is,
24 *
25 * <pre>constPool.getEntryAtIndex(0).isUnused() == true;</pre>
26 *
27 * Another quirk of the constant pool is that LONG and DOUBLE
28 * entries take up "two" indexes. That is,
29 *
30 * <pre>short longIndex = constPool.addEntry(new ConstPoolEntry().setLong(0));
31 * constPool.getEntryAtIndex(longIndex+1).isUnused() == true;</pre>
32 *
33 * @see ConstPoolEntry
34 * @see Signature
35 */

36 public class ConstPool {
37     private Vector cp = new Vector();
38     // for efficiency, addEntry() caches elements in a hashtable, which is
39
// used by getEntryAtIndex(). Caching reduces the time required to
40
// read ClassFileWriter.class from ~10s to ~7.5s.
41
private Hashtable cpHash = new Hashtable();
42
43     /**
44     * Get the size of the pool.
45     */

46     public int size() {
47         return cp.size();
48     }
49
50     /**
51     * Add a constant pool entry, whether or not it's already in the pool.
52     * If the entry is a LONG or DOUBLE, a second, unused entry is
53     * also added.
54     * @returns the index of the added entry.
55     */

56     public short addEntry(ConstPoolEntry entry) {
57         cp.addElement(entry);
58         short result = (short)(size() - 1);
59         cpHash.put(entry, new Integer JavaDoc(result));
60         // LONG and DOUBLE entries take up two entries
61
if (entry.typecode() == ConstPoolEntry.LONG
62             || entry.typecode() == ConstPoolEntry.DOUBLE)
63             cp.addElement(new ConstPoolEntry().setUnused());
64         return result;
65     }
66
67     /**
68     * Get the const pool entry at a given index.
69     */

70     public ConstPoolEntry getEntryAtIndex(short index) {
71         return (ConstPoolEntry)cp.elementAt(index);
72     }
73
74     /**
75     * Return the index of a constant pool entry equal to the specified one.
76     * If there is no matching entry in the pool yet, -1 is returned. Comparisons
77     * are by value, not by reference.
78     */

79     public short getIndexOfEntryNoAdd(ConstPoolEntry entry) {
80         Integer JavaDoc i = (Integer JavaDoc)cpHash.get(entry);
81         if (i != null)
82             return (short)i.intValue();
83         return (short)-1;
84     }
85
86     /**
87     * Return the index of a constant pool entry equal to the specified one.
88     * If there is no matching entry in the pool yet, a clone of the specified
89     * entry is added. Comparisons are made by value, not by reference.
90     */

91     public short getIndexOfEntryAdd(ConstPoolEntry entry) {
92         short result = getIndexOfEntryNoAdd(entry);
93         if (result < 0)
94             result = addEntry((ConstPoolEntry)entry.clone());
95         return result;
96     }
97
98     // used for doing searches -- reuse so we don't have to allocate a new
99
// one every time.
100
private ConstPoolEntry searchEntry = new ConstPoolEntry();
101
102     /**
103     * Convenience method to return the index of the UTF const pool entry
104     * equal to the given string. If there is no matching entry in the const pool yet,
105     * a new one is added. Without this method, something like the following code
106     * would be used:
107     * <pre>constPool.getIndexOfEntryAdd(new ConstPoolEntry().setUTF(str));</pre>
108     * This method avoids the overhead of allocating a ConstPoolEntry every time.
109     */

110     public short getIndexOfUTFAdd(String JavaDoc str) {
111         return getIndexOfEntryAdd(searchEntry.setUTF(str));
112     }
113
114     /**
115     * Convenience method to return the index of the CLASS const pool entry
116     * whose classname is equal to the given string. If there is no matching entry in
117     * the const pool yet, a new one is added. Without this method, something like
118     * the following code would be used:
119     * <pre>short nameIndex = constPool.getIndexOfUTFAdd(classname);
120     * constPool.getIndexEntryAdd(new ConstPoolEntry().setClass(nameIndex));</pre>
121     * This method avoids the overhead of allocating a ConstPoolEntry every time.
122     */

123     public short getIndexOfClassAdd(String JavaDoc classname) {
124         searchEntry.setClass(getIndexOfUTFAdd(classname));
125         return getIndexOfEntryAdd(searchEntry);
126     }
127
128     /**
129     * Read in the constant pool from a stream.
130     * @throws ClassFileReadException if the class file is corrupt.
131     * @throws IOException if the DataInput throws an IOException.
132     */

133     public void read(DataInput in) throws IOException, ClassFileParseException {
134         int count = in.readShort();
135
136         if (Debug.readConstPool != null) Debug.println(Debug.readConstPool,
137             "# of entries = " + count);
138
139         // entry 0 is unused
140
addEntry(new ConstPoolEntry().setUnused());
141         // note: start i at 1 because 0 is unused
142
for (int i = 1; i < count; i++) {
143             ConstPoolEntry entry = new ConstPoolEntry();
144             entry.read(in, entry);
145
146             if (Debug.readConstPool != null) Debug.println(Debug.readConstPool,
147                 i + " " + entry.toString());
148
149             addEntry(entry);
150             // LONG and DOUBLE entries take up two slots
151
if (ConstPoolEntry.LONG == entry.typecode()
152                 || ConstPoolEntry.DOUBLE == entry.typecode())
153                 i++;
154         }
155     }
156
157     /**
158     * Write out the constant pool to a stream.
159     * @throws IOException if the DataInput stream throws an IOException.
160     */

161     public void write(DataOutput out) throws IOException {
162         int numEntries = size();
163
164         if (Debug.writeConstPool != null) Debug.println(Debug.writeConstPool,
165             "# of entries = " + numEntries);
166
167         out.writeShort(numEntries);
168         for (short i = 1; i < numEntries; i++) {
169             ConstPoolEntry entry = getEntryAtIndex(i);
170             // blank entries after LONG and DOUBLE entries
171
if (entry.isUnused()) {
172                 if (Debug.writeConstPool != null) Debug.println(Debug.writeConstPool,
173                     "skipping unused entry");
174             }
175             else {
176                 entry.write(out, entry);
177
178                 if (Debug.writeConstPool != null) Debug.println(Debug.writeConstPool,
179                     i + " " + entry.toString());
180             }
181         }
182     }
183 }
184
Popular Tags