KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > ConstantPool


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.util.Collections JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.Vector JavaDoc;
26 import java.io.DataInput JavaDoc;
27 import java.io.DataOutput JavaDoc;
28 import java.io.IOException JavaDoc;
29 import org.cojen.classfile.constant.ConstantClassInfo;
30 import org.cojen.classfile.constant.ConstantDoubleInfo;
31 import org.cojen.classfile.constant.ConstantFieldInfo;
32 import org.cojen.classfile.constant.ConstantFloatInfo;
33 import org.cojen.classfile.constant.ConstantIntegerInfo;
34 import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
35 import org.cojen.classfile.constant.ConstantLongInfo;
36 import org.cojen.classfile.constant.ConstantMethodInfo;
37 import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
38 import org.cojen.classfile.constant.ConstantStringInfo;
39 import org.cojen.classfile.constant.ConstantUTFInfo;
40
41 /**
42  * This class corresponds to the constant_pool structure as defined in
43  * section 4.4 of <i>The Java Virtual Machine Specification</i>.
44  *
45  * <p>ConstantPool entries are not written out in the order in which they were
46  * added to it. Instead, their ordering is changed such that String, Integer
47  * and Float constants are written out first. This provides a slight
48  * optimization for referencing these constants from a code attribute.
49  * It means that Opcode.LDC will more likely be used (one-byte index) than
50  * Opcode.LDC_W (two-byte index).
51  *
52  * @author Brian S O'Neill
53  * @see Opcode
54  */

55 public class ConstantPool {
56     // A set of ConstantInfo objects.
57
private Map JavaDoc mConstants = new HashMap JavaDoc();
58     // Indexed list of constants.
59
private Vector JavaDoc mIndexedConstants;
60     private int mEntries;
61
62     // Preserve the order only if the constant pool was read in.
63
private boolean mPreserveOrder;
64
65     ConstantPool() {
66     }
67
68     private ConstantPool(Vector JavaDoc indexedConstants) {
69         mIndexedConstants = indexedConstants;
70
71         int size = indexedConstants.size();
72         for (int i=1; i<size; i++) {
73             ConstantInfo ci = (ConstantInfo)indexedConstants.get(i);
74             if (ci != null) {
75                 mConstants.put(ci, ci);
76                 mEntries += ci.getEntryCount();
77             }
78         }
79
80         mPreserveOrder = true;
81     }
82
83     /**
84      * Returns a constant from the pool by index, or null if not found. If this
85      * constant pool has not yet been written or was not created by the read
86      * method, indexes are not assigned, and an IllegalStateException is
87      * thrown.
88      *
89      * @throws ArrayIndexOutOfBoundsException if index is out of range.
90      * @throws IllegalStateException if indexes are not assigned
91      */

92     public ConstantInfo getConstant(int index) {
93         if (mIndexedConstants == null) {
94             throw new IllegalStateException JavaDoc
95                 ("Constant pool indexes have not been assigned");
96         }
97
98         return (ConstantInfo)mIndexedConstants.get(index);
99     }
100
101     /**
102      * Returns all the constants in the pool, in no particular order.
103      */

104     public Set JavaDoc getAllConstants() {
105         return Collections.unmodifiableSet(mConstants.keySet());
106     }
107
108     /**
109      * Returns the number of constants in the pool.
110      */

111     public int getSize() {
112         return mEntries;
113     }
114
115     /**
116      * Get or create a constant from the constant pool representing a class.
117      */

118     public ConstantClassInfo addConstantClass(String JavaDoc className) {
119         return (ConstantClassInfo)addConstant(new ConstantClassInfo(this, className));
120     }
121
122     /**
123      * Get or create a constant from the constant pool representing an array
124      * class.
125      *
126      * @param dim Number of array dimensions.
127      */

128     public ConstantClassInfo addConstantClass(String JavaDoc className, int dim) {
129         return (ConstantClassInfo)addConstant(new ConstantClassInfo(this, className, dim));
130     }
131     
132     /**
133      * Get or create a constant from the constant pool representing a class.
134      */

135     public ConstantClassInfo addConstantClass(TypeDesc type) {
136         return (ConstantClassInfo)addConstant(new ConstantClassInfo(this, type));
137     }
138
139     /**
140      * Get or create a constant from the constant pool representing a field in
141      * any class.
142      */

143     public ConstantFieldInfo addConstantField(String JavaDoc className,
144                                               String JavaDoc fieldName,
145                                               TypeDesc type) {
146         ConstantInfo ci = new ConstantFieldInfo
147             (addConstantClass(className), addConstantNameAndType(fieldName, type));
148         return (ConstantFieldInfo)addConstant(ci);
149     }
150
151     /**
152      * Get or create a constant from the constant pool representing a method
153      * in any class. If the method returns void, set ret to null.
154      */

155     public ConstantMethodInfo addConstantMethod(String JavaDoc className,
156                                                 String JavaDoc methodName,
157                                                 TypeDesc ret,
158                                                 TypeDesc[] params) {
159         
160         MethodDesc md = MethodDesc.forArguments(ret, params);
161         ConstantInfo ci = new ConstantMethodInfo
162             (addConstantClass(className), addConstantNameAndType(methodName, md));
163         return (ConstantMethodInfo)addConstant(ci);
164     }
165     
166     /**
167      * Get or create a constant from the constant pool representing an
168      * interface method in any interface.
169      */

170     public ConstantInterfaceMethodInfo addConstantInterfaceMethod(String JavaDoc className,
171                                                                   String JavaDoc methodName,
172                                                                   TypeDesc ret,
173                                                                   TypeDesc[] params) {
174         
175         MethodDesc md = MethodDesc.forArguments(ret, params);
176         ConstantInfo ci = new ConstantInterfaceMethodInfo
177             (addConstantClass(className), addConstantNameAndType(methodName, md));
178         return (ConstantInterfaceMethodInfo)addConstant(ci);
179     }
180
181     /**
182      * Get or create a constant from the constant pool representing a
183      * constructor in any class.
184      */

185     public ConstantMethodInfo addConstantConstructor(String JavaDoc className,
186                                                      TypeDesc[] params) {
187         return addConstantMethod(className, "<init>", null, params);
188     }
189
190     /**
191      * Get or create a constant integer from the constant pool.
192      */

193     public ConstantIntegerInfo addConstantInteger(int value) {
194         return (ConstantIntegerInfo)addConstant(new ConstantIntegerInfo(value));
195     }
196
197     /**
198      * Get or create a constant long from the constant pool.
199      */

200     public ConstantLongInfo addConstantLong(long value) {
201         return (ConstantLongInfo)addConstant(new ConstantLongInfo(value));
202     }
203
204     /**
205      * Get or create a constant float from the constant pool.
206      */

207     public ConstantFloatInfo addConstantFloat(float value) {
208         return (ConstantFloatInfo)addConstant(new ConstantFloatInfo(value));
209     }
210
211     /**
212      * Get or create a constant double from the constant pool.
213      */

214     public ConstantDoubleInfo addConstantDouble(double value) {
215         return (ConstantDoubleInfo)addConstant(new ConstantDoubleInfo(value));
216     }
217
218     /**
219      * Get or create a constant string from the constant pool.
220      */

221     public ConstantStringInfo addConstantString(String JavaDoc str) {
222         return (ConstantStringInfo)addConstant(new ConstantStringInfo(this, str));
223     }
224
225     /**
226      * Get or create a constant UTF string from the constant pool.
227      */

228     public ConstantUTFInfo addConstantUTF(String JavaDoc str) {
229         return (ConstantUTFInfo)addConstant(new ConstantUTFInfo(str));
230     }
231
232     /**
233      * Get or create a constant name and type structure from the constant pool.
234      */

235     public ConstantNameAndTypeInfo addConstantNameAndType(String JavaDoc name,
236                                                           Descriptor type) {
237         return (ConstantNameAndTypeInfo)addConstant(new ConstantNameAndTypeInfo(this, name, type));
238     }
239
240     /**
241      * Get or create a constant name and type structure from the constant pool.
242      */

243     public ConstantNameAndTypeInfo addConstantNameAndType(ConstantUTFInfo nameConstant,
244                                                           ConstantUTFInfo descConstant) {
245         return (ConstantNameAndTypeInfo)addConstant
246             (new ConstantNameAndTypeInfo(nameConstant, descConstant));
247     }
248
249
250     /**
251      * Will only insert into the pool if the constant is not already in the
252      * pool.
253      *
254      * @return The actual constant in the pool.
255      */

256     public ConstantInfo addConstant(ConstantInfo constant) {
257         ConstantInfo info = (ConstantInfo)mConstants.get(constant);
258         if (info != null) {
259             return info;
260         }
261         
262         int entryCount = constant.getEntryCount();
263
264         if (mIndexedConstants != null && mPreserveOrder) {
265             int size = mIndexedConstants.size();
266             mIndexedConstants.setSize(size + entryCount);
267             mIndexedConstants.set(size, constant);
268             constant.mIndex = size;
269         }
270
271         mConstants.put(constant, constant);
272         mEntries += entryCount;
273
274         return constant;
275     }
276
277     public void writeTo(DataOutput JavaDoc dout) throws IOException JavaDoc {
278         // Write out the size (number of entries) of the constant pool.
279

280         int size = getSize() + 1; // add one because constant 0 is reserved
281
if (size >= 65535) {
282             throw new IllegalStateException JavaDoc
283                 ("Constant pool entry count cannot exceed 65535: " + size);
284         }
285         dout.writeShort(size);
286
287         if (mIndexedConstants == null || !mPreserveOrder) {
288             mIndexedConstants = new Vector JavaDoc(size);
289             mIndexedConstants.setSize(size);
290             int index = 1; // one-based constant pool index
291

292             // First write constants of higher priority -- String, Integer,
293
// Float.
294
// This is a slight optimization. It means that Opcode.LDC will
295
// more likely be used (one-byte index) than Opcode.LDC_W (two-byte
296
// index).
297

298             Iterator JavaDoc it = mConstants.keySet().iterator();
299             while (it.hasNext()) {
300                 ConstantInfo constant = (ConstantInfo)it.next();
301                 if (constant.hasPriority()) {
302                     constant.mIndex = index;
303                     mIndexedConstants.set(index, constant);
304                     index += constant.getEntryCount();
305                 }
306             }
307             
308             // Now write all non-priority constants.
309

310             it = mConstants.keySet().iterator();
311             while (it.hasNext()) {
312                 ConstantInfo constant = (ConstantInfo)it.next();
313                 if (!constant.hasPriority()) {
314                     constant.mIndex = index;
315                     mIndexedConstants.set(index, constant);
316                     index += constant.getEntryCount();
317                 }
318             }
319         }
320
321         // Now actually write out the constants since the indexes have been
322
// resolved.
323

324         for (int i=1; i<size; i++) {
325             Object JavaDoc obj = mIndexedConstants.get(i);
326             if (obj != null) {
327                 ((ConstantInfo)obj).writeTo(dout);
328             }
329         }
330     }
331
332     public static ConstantPool readFrom(DataInput JavaDoc din) throws IOException JavaDoc {
333         int size = din.readUnsignedShort();
334         Vector JavaDoc constants = new Vector JavaDoc(size);
335         constants.setSize(size);
336
337         int index = 1;
338         while (index < size) {
339             int tag = din.readByte();
340             int entryCount = 1;
341             Object JavaDoc constant;
342
343             switch (tag) {
344             case ConstantInfo.TAG_UTF8:
345                 constant = new ConstantUTFInfo(din.readUTF());
346                 break;
347             case ConstantInfo.TAG_INTEGER:
348                 constant = new ConstantIntegerInfo(din.readInt());
349                 break;
350             case ConstantInfo.TAG_FLOAT:
351                 constant = new ConstantFloatInfo(din.readFloat());
352                 break;
353             case ConstantInfo.TAG_LONG:
354                 constant = new ConstantLongInfo(din.readLong());
355                 entryCount++;
356                 break;
357             case ConstantInfo.TAG_DOUBLE:
358                 constant = new ConstantDoubleInfo(din.readDouble());
359                 entryCount++;
360                 break;
361
362             case ConstantInfo.TAG_CLASS:
363             case ConstantInfo.TAG_STRING:
364                 constant = new TempEntry(tag, din.readUnsignedShort());
365                 break;
366
367             case ConstantInfo.TAG_FIELD:
368             case ConstantInfo.TAG_METHOD:
369             case ConstantInfo.TAG_INTERFACE_METHOD:
370             case ConstantInfo.TAG_NAME_AND_TYPE:
371                 constant = new TempEntry
372                     (tag, (din.readShort() << 16) | (din.readUnsignedShort()));
373                 break;
374
375             default:
376                 throw new IOException JavaDoc("Invalid constant pool tag: " + tag);
377             }
378
379             if (constant instanceof ConstantInfo) {
380                 ((ConstantInfo)constant).mIndex = index;
381             }
382
383             constants.set(index, constant);
384             index += entryCount;
385         }
386
387         for (index = 1; index < size; index++) {
388             resolve(constants, index);
389         }
390
391         return new ConstantPool(constants);
392     }
393
394     private static ConstantInfo resolve(List JavaDoc constants, int index) {
395         Object JavaDoc constant = constants.get(index);
396         if (constant == null) {
397             return null;
398         }
399         
400         if (constant instanceof ConstantInfo) {
401             return (ConstantInfo)constant;
402         }
403
404         TempEntry entry = (TempEntry)constant;
405         int data = entry.mData;
406         int index1 = data & 0xffff;
407
408         ConstantInfo ci1;
409         Object JavaDoc constant1 = constants.get(index1);
410
411         if (constant1 instanceof ConstantInfo) {
412             ci1 = (ConstantInfo)constant1;
413         } else {
414             ci1 = resolve(constants, index1);
415         }
416
417         ConstantInfo ci = null;
418
419         switch (entry.mTag) {
420         case ConstantInfo.TAG_CLASS:
421             ci = new ConstantClassInfo((ConstantUTFInfo)ci1);
422             break;
423         case ConstantInfo.TAG_STRING:
424             ci = new ConstantStringInfo((ConstantUTFInfo)ci1);
425             break;
426
427         case ConstantInfo.TAG_FIELD:
428         case ConstantInfo.TAG_METHOD:
429         case ConstantInfo.TAG_INTERFACE_METHOD:
430         case ConstantInfo.TAG_NAME_AND_TYPE:
431             int index2 = data >> 16;
432             
433             ConstantInfo ci2;
434             Object JavaDoc constant2 = constants.get(index2);
435             
436             if (constant2 instanceof ConstantInfo) {
437                 ci2 = (ConstantInfo)constant2;
438             } else {
439                 ci2 = resolve(constants, index2);
440             }
441
442             switch (entry.mTag) {
443             case ConstantInfo.TAG_FIELD:
444                 ci = new ConstantFieldInfo
445                     ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1);
446                 break;
447             case ConstantInfo.TAG_METHOD:
448                 ci = new ConstantMethodInfo
449                     ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1);
450                 break;
451             case ConstantInfo.TAG_INTERFACE_METHOD:
452                 ci = new ConstantInterfaceMethodInfo
453                     ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1);
454                 break;
455             case ConstantInfo.TAG_NAME_AND_TYPE:
456                 ci = new ConstantNameAndTypeInfo
457                     ((ConstantUTFInfo)ci2, (ConstantUTFInfo)ci1);
458                 break;
459             }
460
461             break;
462         }
463
464         ci.mIndex = index;
465         constants.set(index, ci);
466
467         return ci;
468     }
469
470     private static class TempEntry {
471         public int mTag;
472         public int mData;
473
474         public TempEntry(int tag, int data) {
475             mTag = tag;
476             mData = data;
477         }
478     }
479 }
480
Popular Tags