comparison src/com/go/trove/classfile/ConstantPool.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /* ====================================================================
2 * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3 * ====================================================================
4 * The Tea Software License, Version 1.1
5 *
6 * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Walt Disney Internet Group (http://opensource.go.com/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact opensource@dig.com.
31 *
32 * 5. Products derived from this software may not be called "Tea",
33 * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34 * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35 * written permission of the Walt Disney Internet Group.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * For more information about Tea, please see http://opensource.go.com/.
51 */
52
53 package com.go.trove.classfile;
54
55 import java.util.*;
56 import java.io.*;
57
58 /******************************************************************************
59 * This class corresponds to the constant_pool structure as defined in
60 * section 4.4 of <i>The Java Virtual Machine Specification</i>.
61 *
62 * <p>ConstantPool entries are not written out in the order in which they were
63 * added to it. Instead, their ordering is changed such that String, Integer
64 * and Float constants are written out first. This provides a slight
65 * optimization for referencing these constants from a code attribute.
66 * It means that Opcode.LDC will more likely be used (one-byte index) than
67 * Opcode.LDC_W (two-byte index).
68 *
69 * @author Brian S O'Neill
70 * @version
71 * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 9/07/00 <!-- $-->
72 * @see CodeAttr
73 * @see Opcode
74 */
75 public class ConstantPool {
76 // A set of ConstantInfo objects.
77 private Map mConstants = new HashMap();
78 // Indexed list of constants.
79 private Vector mIndexedConstants;
80 private int mEntries;
81
82 // Preserve the order only if the constant pool was read in.
83 private boolean mPreserveOrder;
84
85 ConstantPool() {
86 }
87
88 private ConstantPool(Vector indexedConstants) {
89 mIndexedConstants = indexedConstants;
90
91 int size = indexedConstants.size();
92 for (int i=1; i<size; i++) {
93 ConstantInfo ci = (ConstantInfo)indexedConstants.get(i);
94 if (ci != null) {
95 mConstants.put(ci, ci);
96 mEntries += ci.getEntryCount();
97 }
98 }
99
100 mPreserveOrder = true;
101 }
102
103 /**
104 * Returns a constant from the pool by index, or throws an exception if not
105 * found. If this constant pool has not yet been written or was not created
106 * by the read method, indexes are not assigned.
107 *
108 * @throws ArrayIndexOutOfBoundsException if index is out of range.
109 */
110 public ConstantInfo getConstant(int index) {
111 if (mIndexedConstants == null) {
112 throw new ArrayIndexOutOfBoundsException
113 ("Constant pool indexes have not been assigned");
114 }
115
116 return (ConstantInfo)mIndexedConstants.get(index);
117 }
118
119 /**
120 * Returns all the constants in the pool, in no particular order.
121 */
122 public Set getAllConstants() {
123 return Collections.unmodifiableSet(mConstants.keySet());
124 }
125
126 /**
127 * Returns the number of constants in the pool.
128 */
129 public int getSize() {
130 return mEntries;
131 }
132
133 /**
134 * Get or create a constant from the constant pool representing a class.
135 */
136 public ConstantClassInfo addConstantClass(String className) {
137 return ConstantClassInfo.make(this, className);
138 }
139
140 /**
141 * Get or create a constant from the constant pool representing an array
142 * class.
143 *
144 * @param dim Number of array dimensions.
145 */
146 public ConstantClassInfo addConstantClass(String className, int dim) {
147 return ConstantClassInfo.make(this, className, dim);
148 }
149
150 /**
151 * Get or create a constant from the constant pool representing a class.
152 */
153 public ConstantClassInfo addConstantClass(TypeDescriptor type) {
154 return ConstantClassInfo.make(this, type);
155 }
156
157 /**
158 * Get or create a constant from the constant pool representing a field in
159 * any class.
160 */
161 public ConstantFieldInfo addConstantField(String className,
162 String fieldName,
163 TypeDescriptor type) {
164 return ConstantFieldInfo.make
165 (this,
166 ConstantClassInfo.make(this, className),
167 ConstantNameAndTypeInfo.make(this, fieldName, type));
168 }
169
170 /**
171 * Get or create a constant from the constant pool representing a method
172 * in any class. If the method returns void, set ret to null.
173 */
174 public ConstantMethodInfo addConstantMethod(String className,
175 String methodName,
176 TypeDescriptor ret,
177 TypeDescriptor[] params) {
178
179 MethodDescriptor md = new MethodDescriptor(ret, params);
180
181 return ConstantMethodInfo.make
182 (this,
183 ConstantClassInfo.make(this, className),
184 ConstantNameAndTypeInfo.make(this, methodName, md));
185 }
186
187 /**
188 * Get or create a constant from the constant pool representing an
189 * interface method in any interface.
190 */
191 public ConstantInterfaceMethodInfo addConstantInterfaceMethod
192 (String className,
193 String methodName,
194 TypeDescriptor ret,
195 TypeDescriptor[] params) {
196
197 MethodDescriptor md = new MethodDescriptor(ret, params);
198
199 return ConstantInterfaceMethodInfo.make
200 (this,
201 ConstantClassInfo.make(this, className),
202 ConstantNameAndTypeInfo.make(this, methodName, md));
203 }
204
205 /**
206 * Get or create a constant from the constant pool representing a
207 * constructor in any class.
208 */
209 public ConstantMethodInfo addConstantConstructor(String className,
210 TypeDescriptor[] params) {
211 return addConstantMethod(className, "<init>", null, params);
212 }
213
214 /**
215 * Get or create a constant integer from the constant pool.
216 */
217 public ConstantIntegerInfo addConstantInteger(int value) {
218 return ConstantIntegerInfo.make(this, value);
219 }
220
221 /**
222 * Get or create a constant long from the constant pool.
223 */
224 public ConstantLongInfo addConstantLong(long value) {
225 return ConstantLongInfo.make(this, value);
226 }
227
228 /**
229 * Get or create a constant float from the constant pool.
230 */
231 public ConstantFloatInfo addConstantFloat(float value) {
232 return ConstantFloatInfo.make(this, value);
233 }
234
235 /**
236 * Get or create a constant double from the constant pool.
237 */
238 public ConstantDoubleInfo addConstantDouble(double value) {
239 return ConstantDoubleInfo.make(this, value);
240 }
241
242 /**
243 * Get or create a constant string from the constant pool.
244 */
245 public ConstantStringInfo addConstantString(String str) {
246 return ConstantStringInfo.make(this, str);
247 }
248
249 /**
250 * Get or create a constant UTF string from the constant pool.
251 */
252 public ConstantUTFInfo addConstantUTF(String str) {
253 return ConstantUTFInfo.make(this, str);
254 }
255
256 /**
257 * Get or create a constant name and type structure from the constant pool.
258 */
259 public ConstantNameAndTypeInfo addConstantNameAndType(String name,
260 Descriptor type) {
261 return ConstantNameAndTypeInfo.make(this, name, type);
262 }
263
264 /**
265 * Will only insert into the pool if the constant is not already in the
266 * pool.
267 *
268 * @return The actual constant in the pool.
269 */
270 public ConstantInfo addConstant(ConstantInfo constant) {
271 ConstantInfo info = (ConstantInfo)mConstants.get(constant);
272 if (info != null) {
273 return info;
274 }
275
276 int entryCount = constant.getEntryCount();
277
278 if (mIndexedConstants != null && mPreserveOrder) {
279 int size = mIndexedConstants.size();
280 mIndexedConstants.setSize(size + entryCount);
281 mIndexedConstants.set(size, constant);
282 }
283
284 mConstants.put(constant, constant);
285 mEntries += entryCount;
286
287 return constant;
288 }
289
290 public void writeTo(DataOutput dout) throws IOException {
291 // Write out the size (number of entries) of the constant pool.
292
293 int size = getSize() + 1; // add one because constant 0 is reserved
294 if (size >= 65535) {
295 throw new RuntimeException
296 ("Constant pool entry count cannot exceed 65535: " + size);
297 }
298 dout.writeShort(size);
299
300 if (mIndexedConstants == null || !mPreserveOrder) {
301 mIndexedConstants = new Vector(size);
302 mIndexedConstants.setSize(size);
303 int index = 1; // one-based constant pool index
304
305 // First write constants of higher priority -- String, Integer,
306 // Float.
307 // This is a slight optimization. It means that Opcode.LDC will
308 // more likely be used (one-byte index) than Opcode.LDC_W (two-byte
309 // index).
310
311 Iterator it = mConstants.keySet().iterator();
312 while (it.hasNext()) {
313 ConstantInfo constant = (ConstantInfo)it.next();
314 if (constant.hasPriority()) {
315 constant.mIndex = index;
316 mIndexedConstants.set(index, constant);
317 index += constant.getEntryCount();
318 }
319 }
320
321 // Now write all non-priority constants.
322
323 it = mConstants.keySet().iterator();
324 while (it.hasNext()) {
325 ConstantInfo constant = (ConstantInfo)it.next();
326 if (!constant.hasPriority()) {
327 constant.mIndex = index;
328 mIndexedConstants.set(index, constant);
329 index += constant.getEntryCount();
330 }
331 }
332 }
333
334 // Now actually write out the constants since the indexes have been
335 // resolved.
336
337 for (int i=1; i<size; i++) {
338 Object obj = mIndexedConstants.get(i);
339 if (obj != null) {
340 ((ConstantInfo)obj).writeTo(dout);
341 }
342 }
343 }
344
345 public static ConstantPool readFrom(DataInput din) throws IOException {
346 int size = din.readUnsignedShort();
347 Vector constants = new Vector(size);
348 constants.setSize(size);
349
350 int index = 1;
351 while (index < size) {
352 int tag = din.readByte();
353 int entryCount = 1;
354 Object constant;
355
356 switch (tag) {
357 case ConstantInfo.TAG_UTF8:
358 constant = new ConstantUTFInfo(din.readUTF());
359 break;
360 case ConstantInfo.TAG_INTEGER:
361 constant = new ConstantIntegerInfo(din.readInt());
362 break;
363 case ConstantInfo.TAG_FLOAT:
364 constant = new ConstantFloatInfo(din.readFloat());
365 break;
366 case ConstantInfo.TAG_LONG:
367 constant = new ConstantLongInfo(din.readLong());
368 entryCount++;
369 break;
370 case ConstantInfo.TAG_DOUBLE:
371 constant = new ConstantDoubleInfo(din.readDouble());
372 entryCount++;
373 break;
374
375 case ConstantInfo.TAG_CLASS:
376 case ConstantInfo.TAG_STRING:
377 constant = new TempEntry(tag, din.readUnsignedShort());
378 break;
379
380 case ConstantInfo.TAG_FIELD:
381 case ConstantInfo.TAG_METHOD:
382 case ConstantInfo.TAG_INTERFACE_METHOD:
383 case ConstantInfo.TAG_NAME_AND_TYPE:
384 constant = new TempEntry
385 (tag, (din.readShort() << 16) | (din.readUnsignedShort()));
386 break;
387
388 default:
389 throw new IOException("Invalid constant pool tag: " + tag);
390 }
391
392 if (constant instanceof ConstantInfo) {
393 ((ConstantInfo)constant).mIndex = index;
394 }
395
396 constants.set(index, constant);
397 index += entryCount;
398 }
399
400 for (index = 1; index < size; index++) {
401 resolve(constants, index);
402 }
403
404 return new ConstantPool(constants);
405 }
406
407 private static ConstantInfo resolve(List constants, int index) {
408 Object constant = constants.get(index);
409 if (constant == null) {
410 return null;
411 }
412
413 if (constant instanceof ConstantInfo) {
414 return (ConstantInfo)constant;
415 }
416
417 TempEntry entry = (TempEntry)constant;
418 int data = entry.mData;
419 int index1 = data & 0xffff;
420
421 ConstantInfo ci1;
422 Object constant1 = constants.get(index1);
423
424 if (constant1 instanceof ConstantInfo) {
425 ci1 = (ConstantInfo)constant1;
426 }
427 else {
428 ci1 = resolve(constants, index1);
429 }
430
431 ConstantInfo ci = null;
432
433 switch (entry.mTag) {
434 case ConstantInfo.TAG_CLASS:
435 ci = new ConstantClassInfo((ConstantUTFInfo)ci1);
436 break;
437 case ConstantInfo.TAG_STRING:
438 ci = new ConstantStringInfo((ConstantUTFInfo)ci1);
439 break;
440
441 case ConstantInfo.TAG_FIELD:
442 case ConstantInfo.TAG_METHOD:
443 case ConstantInfo.TAG_INTERFACE_METHOD:
444 case ConstantInfo.TAG_NAME_AND_TYPE:
445 int index2 = data >> 16;
446
447 ConstantInfo ci2;
448 Object constant2 = constants.get(index2);
449
450 if (constant2 instanceof ConstantInfo) {
451 ci2 = (ConstantInfo)constant2;
452 }
453 else {
454 ci2 = resolve(constants, index2);
455 }
456
457 switch (entry.mTag) {
458 case ConstantInfo.TAG_FIELD:
459 ci = new ConstantFieldInfo
460 ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1);
461 break;
462 case ConstantInfo.TAG_METHOD:
463 ci = new ConstantMethodInfo
464 ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1);
465 break;
466 case ConstantInfo.TAG_INTERFACE_METHOD:
467 ci = new ConstantInterfaceMethodInfo
468 ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1);
469 break;
470 case ConstantInfo.TAG_NAME_AND_TYPE:
471 ci = new ConstantNameAndTypeInfo
472 ((ConstantUTFInfo)ci2, (ConstantUTFInfo)ci1);
473 break;
474 }
475
476 break;
477 }
478
479 ci.mIndex = index;
480 constants.set(index, ci);
481
482 return ci;
483 }
484
485 private static class TempEntry {
486 public int mTag;
487 public int mData;
488
489 public TempEntry(int tag, int data) {
490 mTag = tag;
491 mData = data;
492 }
493 }
494 }