327 lines · 10.8 KB · Java
RawDownload
/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.java; import java.io.IOException;import java.io.DataInputStream;import java.io.DataOutputStream;import java.util.Vector;import java.util.Hashtable; /** * This class is used to represent a constant table once * it is read from a class file. * * WARNING: The contents of this source file are not part of any * supported API.  Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */public finalclass BinaryConstantPool implements Constants {    private byte types[];    private Object cpool[];     /**     * Constructor     */    BinaryConstantPool(DataInputStream in) throws IOException {        // JVM 4.1 ClassFile.constant_pool_count        types = new byte[in.readUnsignedShort()];        cpool = new Object[types.length];        for (int i = 1 ; i < cpool.length ; i++) {            int j = i;            // JVM 4.4 cp_info.tag            switch(types[i] = in.readByte()) {              case CONSTANT_UTF8:                cpool[i] = in.readUTF();                break;               case CONSTANT_INTEGER:                cpool[i] = new Integer(in.readInt());                break;              case CONSTANT_FLOAT:                cpool[i] = new Float(in.readFloat());                break;              case CONSTANT_LONG:                cpool[i++] = new Long(in.readLong());                break;              case CONSTANT_DOUBLE:                cpool[i++] = new Double(in.readDouble());                break;               case CONSTANT_CLASS:              case CONSTANT_STRING:                // JVM 4.4.3 CONSTANT_String_info.string_index                // or JVM 4.4.1 CONSTANT_Class_info.name_index                cpool[i] = new Integer(in.readUnsignedShort());                break;               case CONSTANT_FIELD:              case CONSTANT_METHOD:              case CONSTANT_INTERFACEMETHOD:              case CONSTANT_NAMEANDTYPE:                // JVM 4.4.2 CONSTANT_*ref_info.class_index & name_and_type_index                cpool[i] = new Integer((in.readUnsignedShort() << 16) | in.readUnsignedShort());                break;               case 0:              default:                throw new ClassFormatError("invalid constant type: " + (int)types[i]);            }        }    }     /**     * get a integer     */    public int getInteger(int n) {        return (n == 0) ? 0 : ((Number)cpool[n]).intValue();    }     /**     * get a value     */    public Object getValue(int n) {        return (n == 0) ? null : cpool[n];    }     /**     * get a string     */    public String getString(int n) {        return (n == 0) ? null : (String)cpool[n];    }     /**     * get an identifier     */    public Identifier getIdentifier(int n) {        return (n == 0) ? null : Identifier.lookup(getString(n));    }     /**     * get class declaration     */    public ClassDeclaration getDeclarationFromName(Environment env, int n) {        return (n == 0) ? null : env.getClassDeclaration(Identifier.lookup(getString(n).replace('/','.')));    }     /**     * get class declaration     */    public ClassDeclaration getDeclaration(Environment env, int n) {        return (n == 0) ? null : getDeclarationFromName(env, getInteger(n));    }     /**     * get a type from a type signature     */    public Type getType(int n) {        return Type.tType(getString(n));    }     /**     * get the type of constant given an index     */    public int getConstantType(int n) {        return types[n];    }     /**     * get the n-th constant from the constant pool     */    public Object getConstant(int n, Environment env) {        int constant_type = getConstantType(n);        switch (constant_type) {            case CONSTANT_INTEGER:            case CONSTANT_FLOAT:            case CONSTANT_LONG:            case CONSTANT_DOUBLE:                return getValue(n);             case CONSTANT_CLASS:                return getDeclaration(env, n);             case CONSTANT_STRING:                return getString(getInteger(n));             case CONSTANT_FIELD:            case CONSTANT_METHOD:            case CONSTANT_INTERFACEMETHOD:                try {                    int key = getInteger(n);                    ClassDefinition clazz =                        getDeclaration(env, key >> 16).getClassDefinition(env);                    int name_and_type = getInteger(key & 0xFFFF);                    Identifier id = getIdentifier(name_and_type >> 16);                    Type type = getType(name_and_type & 0xFFFF);                     for (MemberDefinition field = clazz.getFirstMatch(id);                         field != null;                         field = field.getNextMatch()) {                        Type field_type = field.getType();                        if ((constant_type == CONSTANT_FIELD)                            ? (field_type == type)                            : (field_type.equalArguments(type)))                            return field;                    }                } catch (ClassNotFound e) {                }                return null;             default:                throw new ClassFormatError("invalid constant type: " +                                              constant_type);        }    }      /**     * Get a list of dependencies, ie: all the classes referenced in this     * constant pool.     */    public Vector getDependencies(Environment env) {        Vector v = new Vector();        for (int i = 1 ; i < cpool.length ; i++) {            switch(types[i]) {              case CONSTANT_CLASS:                v.addElement(getDeclarationFromName(env, getInteger(i)));                break;            }        }        return v;    }     Hashtable indexHashObject, indexHashAscii;    Vector MoreStuff;     /**     * Find the index of an Object in the constant pool     */    public int indexObject(Object obj, Environment env) {        if (indexHashObject == null)            createIndexHash(env);        Integer result = (Integer)indexHashObject.get(obj);        if (result == null)            throw new IndexOutOfBoundsException("Cannot find object " + obj + " of type " +                                obj.getClass() + " in constant pool");        return result.intValue();    }     /**     * Find the index of an ascii string in the constant pool.  If it's not in     * the constant pool, then add it at the end.     */    public int indexString(String string, Environment env) {        if (indexHashObject == null)            createIndexHash(env);        Integer result = (Integer)indexHashAscii.get(string);        if (result == null) {            if (MoreStuff == null) MoreStuff = new Vector();            result = new Integer(cpool.length + MoreStuff.size());            MoreStuff.addElement(string);            indexHashAscii.put(string, result);        }        return result.intValue();    }     /**     * Create a hash table of all the items in the constant pool that could     * possibly be referenced from the outside.     */     public void createIndexHash(Environment env) {        indexHashObject = new Hashtable();        indexHashAscii = new Hashtable();        for (int i = 1; i < cpool.length; i++) {            if (types[i] == CONSTANT_UTF8) {                indexHashAscii.put(cpool[i], new Integer(i));            } else {                try {                    indexHashObject.put(getConstant(i, env), new Integer(i));                } catch (ClassFormatError e) { }            }        }    }      /**     * Write out the contents of the constant pool, including any additions     * that have been added.     */    public void write(DataOutputStream out, Environment env) throws IOException {        int length = cpool.length;        if (MoreStuff != null)            length += MoreStuff.size();        out.writeShort(length);        for (int i = 1 ; i < cpool.length; i++) {            int type = types[i];            Object x = cpool[i];            out.writeByte(type);            switch (type) {                case CONSTANT_UTF8:                    out.writeUTF((String) x);                    break;                case CONSTANT_INTEGER:                    out.writeInt(((Number)x).intValue());                    break;                case CONSTANT_FLOAT:                    out.writeFloat(((Number)x).floatValue());                    break;                case CONSTANT_LONG:                    out.writeLong(((Number)x).longValue());                    i++;                    break;                case CONSTANT_DOUBLE:                    out.writeDouble(((Number)x).doubleValue());                    i++;                    break;                case CONSTANT_CLASS:                case CONSTANT_STRING:                    out.writeShort(((Number)x).intValue());                    break;                case CONSTANT_FIELD:                case CONSTANT_METHOD:                case CONSTANT_INTERFACEMETHOD:                case CONSTANT_NAMEANDTYPE: {                    int value = ((Number)x).intValue();                    out.writeShort(value >> 16);                    out.writeShort(value & 0xFFFF);                    break;                }                default:                     throw new ClassFormatError("invalid constant type: "                                                   + (int)types[i]);            }        }        for (int i = cpool.length; i < length; i++) {            String string = (String)(MoreStuff.elementAt(i - cpool.length));            out.writeByte(CONSTANT_UTF8);            out.writeUTF(string);        }    } }