Mercurial > hg > blitz_stable
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/go/trove/classfile/ConstantPool.java Sat Mar 21 11:00:06 2009 +0000 @@ -0,0 +1,494 @@ +/* ==================================================================== + * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group + * ==================================================================== + * The Tea Software License, Version 1.1 + * + * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Walt Disney Internet Group (http://opensource.go.com/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact opensource@dig.com. + * + * 5. Products derived from this software may not be called "Tea", + * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet", + * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior + * written permission of the Walt Disney Internet Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * For more information about Tea, please see http://opensource.go.com/. + */ + +package com.go.trove.classfile; + +import java.util.*; +import java.io.*; + +/****************************************************************************** + * This class corresponds to the constant_pool structure as defined in + * section 4.4 of <i>The Java Virtual Machine Specification</i>. + * + * <p>ConstantPool entries are not written out in the order in which they were + * added to it. Instead, their ordering is changed such that String, Integer + * and Float constants are written out first. This provides a slight + * optimization for referencing these constants from a code attribute. + * It means that Opcode.LDC will more likely be used (one-byte index) than + * Opcode.LDC_W (two-byte index). + * + * @author Brian S O'Neill + * @version + * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 9/07/00 <!-- $--> + * @see CodeAttr + * @see Opcode + */ +public class ConstantPool { + // A set of ConstantInfo objects. + private Map mConstants = new HashMap(); + // Indexed list of constants. + private Vector mIndexedConstants; + private int mEntries; + + // Preserve the order only if the constant pool was read in. + private boolean mPreserveOrder; + + ConstantPool() { + } + + private ConstantPool(Vector indexedConstants) { + mIndexedConstants = indexedConstants; + + int size = indexedConstants.size(); + for (int i=1; i<size; i++) { + ConstantInfo ci = (ConstantInfo)indexedConstants.get(i); + if (ci != null) { + mConstants.put(ci, ci); + mEntries += ci.getEntryCount(); + } + } + + mPreserveOrder = true; + } + + /** + * Returns a constant from the pool by index, or throws an exception if not + * found. If this constant pool has not yet been written or was not created + * by the read method, indexes are not assigned. + * + * @throws ArrayIndexOutOfBoundsException if index is out of range. + */ + public ConstantInfo getConstant(int index) { + if (mIndexedConstants == null) { + throw new ArrayIndexOutOfBoundsException + ("Constant pool indexes have not been assigned"); + } + + return (ConstantInfo)mIndexedConstants.get(index); + } + + /** + * Returns all the constants in the pool, in no particular order. + */ + public Set getAllConstants() { + return Collections.unmodifiableSet(mConstants.keySet()); + } + + /** + * Returns the number of constants in the pool. + */ + public int getSize() { + return mEntries; + } + + /** + * Get or create a constant from the constant pool representing a class. + */ + public ConstantClassInfo addConstantClass(String className) { + return ConstantClassInfo.make(this, className); + } + + /** + * Get or create a constant from the constant pool representing an array + * class. + * + * @param dim Number of array dimensions. + */ + public ConstantClassInfo addConstantClass(String className, int dim) { + return ConstantClassInfo.make(this, className, dim); + } + + /** + * Get or create a constant from the constant pool representing a class. + */ + public ConstantClassInfo addConstantClass(TypeDescriptor type) { + return ConstantClassInfo.make(this, type); + } + + /** + * Get or create a constant from the constant pool representing a field in + * any class. + */ + public ConstantFieldInfo addConstantField(String className, + String fieldName, + TypeDescriptor type) { + return ConstantFieldInfo.make + (this, + ConstantClassInfo.make(this, className), + ConstantNameAndTypeInfo.make(this, fieldName, type)); + } + + /** + * Get or create a constant from the constant pool representing a method + * in any class. If the method returns void, set ret to null. + */ + public ConstantMethodInfo addConstantMethod(String className, + String methodName, + TypeDescriptor ret, + TypeDescriptor[] params) { + + MethodDescriptor md = new MethodDescriptor(ret, params); + + return ConstantMethodInfo.make + (this, + ConstantClassInfo.make(this, className), + ConstantNameAndTypeInfo.make(this, methodName, md)); + } + + /** + * Get or create a constant from the constant pool representing an + * interface method in any interface. + */ + public ConstantInterfaceMethodInfo addConstantInterfaceMethod + (String className, + String methodName, + TypeDescriptor ret, + TypeDescriptor[] params) { + + MethodDescriptor md = new MethodDescriptor(ret, params); + + return ConstantInterfaceMethodInfo.make + (this, + ConstantClassInfo.make(this, className), + ConstantNameAndTypeInfo.make(this, methodName, md)); + } + + /** + * Get or create a constant from the constant pool representing a + * constructor in any class. + */ + public ConstantMethodInfo addConstantConstructor(String className, + TypeDescriptor[] params) { + return addConstantMethod(className, "<init>", null, params); + } + + /** + * Get or create a constant integer from the constant pool. + */ + public ConstantIntegerInfo addConstantInteger(int value) { + return ConstantIntegerInfo.make(this, value); + } + + /** + * Get or create a constant long from the constant pool. + */ + public ConstantLongInfo addConstantLong(long value) { + return ConstantLongInfo.make(this, value); + } + + /** + * Get or create a constant float from the constant pool. + */ + public ConstantFloatInfo addConstantFloat(float value) { + return ConstantFloatInfo.make(this, value); + } + + /** + * Get or create a constant double from the constant pool. + */ + public ConstantDoubleInfo addConstantDouble(double value) { + return ConstantDoubleInfo.make(this, value); + } + + /** + * Get or create a constant string from the constant pool. + */ + public ConstantStringInfo addConstantString(String str) { + return ConstantStringInfo.make(this, str); + } + + /** + * Get or create a constant UTF string from the constant pool. + */ + public ConstantUTFInfo addConstantUTF(String str) { + return ConstantUTFInfo.make(this, str); + } + + /** + * Get or create a constant name and type structure from the constant pool. + */ + public ConstantNameAndTypeInfo addConstantNameAndType(String name, + Descriptor type) { + return ConstantNameAndTypeInfo.make(this, name, type); + } + + /** + * Will only insert into the pool if the constant is not already in the + * pool. + * + * @return The actual constant in the pool. + */ + public ConstantInfo addConstant(ConstantInfo constant) { + ConstantInfo info = (ConstantInfo)mConstants.get(constant); + if (info != null) { + return info; + } + + int entryCount = constant.getEntryCount(); + + if (mIndexedConstants != null && mPreserveOrder) { + int size = mIndexedConstants.size(); + mIndexedConstants.setSize(size + entryCount); + mIndexedConstants.set(size, constant); + } + + mConstants.put(constant, constant); + mEntries += entryCount; + + return constant; + } + + public void writeTo(DataOutput dout) throws IOException { + // Write out the size (number of entries) of the constant pool. + + int size = getSize() + 1; // add one because constant 0 is reserved + if (size >= 65535) { + throw new RuntimeException + ("Constant pool entry count cannot exceed 65535: " + size); + } + dout.writeShort(size); + + if (mIndexedConstants == null || !mPreserveOrder) { + mIndexedConstants = new Vector(size); + mIndexedConstants.setSize(size); + int index = 1; // one-based constant pool index + + // First write constants of higher priority -- String, Integer, + // Float. + // This is a slight optimization. It means that Opcode.LDC will + // more likely be used (one-byte index) than Opcode.LDC_W (two-byte + // index). + + Iterator it = mConstants.keySet().iterator(); + while (it.hasNext()) { + ConstantInfo constant = (ConstantInfo)it.next(); + if (constant.hasPriority()) { + constant.mIndex = index; + mIndexedConstants.set(index, constant); + index += constant.getEntryCount(); + } + } + + // Now write all non-priority constants. + + it = mConstants.keySet().iterator(); + while (it.hasNext()) { + ConstantInfo constant = (ConstantInfo)it.next(); + if (!constant.hasPriority()) { + constant.mIndex = index; + mIndexedConstants.set(index, constant); + index += constant.getEntryCount(); + } + } + } + + // Now actually write out the constants since the indexes have been + // resolved. + + for (int i=1; i<size; i++) { + Object obj = mIndexedConstants.get(i); + if (obj != null) { + ((ConstantInfo)obj).writeTo(dout); + } + } + } + + public static ConstantPool readFrom(DataInput din) throws IOException { + int size = din.readUnsignedShort(); + Vector constants = new Vector(size); + constants.setSize(size); + + int index = 1; + while (index < size) { + int tag = din.readByte(); + int entryCount = 1; + Object constant; + + switch (tag) { + case ConstantInfo.TAG_UTF8: + constant = new ConstantUTFInfo(din.readUTF()); + break; + case ConstantInfo.TAG_INTEGER: + constant = new ConstantIntegerInfo(din.readInt()); + break; + case ConstantInfo.TAG_FLOAT: + constant = new ConstantFloatInfo(din.readFloat()); + break; + case ConstantInfo.TAG_LONG: + constant = new ConstantLongInfo(din.readLong()); + entryCount++; + break; + case ConstantInfo.TAG_DOUBLE: + constant = new ConstantDoubleInfo(din.readDouble()); + entryCount++; + break; + + case ConstantInfo.TAG_CLASS: + case ConstantInfo.TAG_STRING: + constant = new TempEntry(tag, din.readUnsignedShort()); + break; + + case ConstantInfo.TAG_FIELD: + case ConstantInfo.TAG_METHOD: + case ConstantInfo.TAG_INTERFACE_METHOD: + case ConstantInfo.TAG_NAME_AND_TYPE: + constant = new TempEntry + (tag, (din.readShort() << 16) | (din.readUnsignedShort())); + break; + + default: + throw new IOException("Invalid constant pool tag: " + tag); + } + + if (constant instanceof ConstantInfo) { + ((ConstantInfo)constant).mIndex = index; + } + + constants.set(index, constant); + index += entryCount; + } + + for (index = 1; index < size; index++) { + resolve(constants, index); + } + + return new ConstantPool(constants); + } + + private static ConstantInfo resolve(List constants, int index) { + Object constant = constants.get(index); + if (constant == null) { + return null; + } + + if (constant instanceof ConstantInfo) { + return (ConstantInfo)constant; + } + + TempEntry entry = (TempEntry)constant; + int data = entry.mData; + int index1 = data & 0xffff; + + ConstantInfo ci1; + Object constant1 = constants.get(index1); + + if (constant1 instanceof ConstantInfo) { + ci1 = (ConstantInfo)constant1; + } + else { + ci1 = resolve(constants, index1); + } + + ConstantInfo ci = null; + + switch (entry.mTag) { + case ConstantInfo.TAG_CLASS: + ci = new ConstantClassInfo((ConstantUTFInfo)ci1); + break; + case ConstantInfo.TAG_STRING: + ci = new ConstantStringInfo((ConstantUTFInfo)ci1); + break; + + case ConstantInfo.TAG_FIELD: + case ConstantInfo.TAG_METHOD: + case ConstantInfo.TAG_INTERFACE_METHOD: + case ConstantInfo.TAG_NAME_AND_TYPE: + int index2 = data >> 16; + + ConstantInfo ci2; + Object constant2 = constants.get(index2); + + if (constant2 instanceof ConstantInfo) { + ci2 = (ConstantInfo)constant2; + } + else { + ci2 = resolve(constants, index2); + } + + switch (entry.mTag) { + case ConstantInfo.TAG_FIELD: + ci = new ConstantFieldInfo + ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1); + break; + case ConstantInfo.TAG_METHOD: + ci = new ConstantMethodInfo + ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1); + break; + case ConstantInfo.TAG_INTERFACE_METHOD: + ci = new ConstantInterfaceMethodInfo + ((ConstantClassInfo)ci2, (ConstantNameAndTypeInfo)ci1); + break; + case ConstantInfo.TAG_NAME_AND_TYPE: + ci = new ConstantNameAndTypeInfo + ((ConstantUTFInfo)ci2, (ConstantUTFInfo)ci1); + break; + } + + break; + } + + ci.mIndex = index; + constants.set(index, ci); + + return ci; + } + + private static class TempEntry { + public int mTag; + public int mData; + + public TempEntry(int tag, int data) { + mTag = tag; + mData = data; + } + } +}