2009 lines · 77.6 KB · Java
RawDownload
     * section 3.6.1.     *     * Note that the original version of the JVMS contained a definition of     * this abstract notion of a "word" in section 3.4, but that definition     * was removed for the second edition.     */    private static int getWordsPerType(Class type) {        if (type == long.class || type == double.class) {            return 2;        } else {            return 1;        }    }     /**     * Add to the given list all of the types in the "from" array that     * are not already contained in the list and are assignable to at     * least one of the types in the "with" array.     *     * This method is useful for computing the greatest common set of     * declared exceptions from duplicate methods inherited from     * different interfaces.     */    private static void collectCompatibleTypes(Class<?>[] from,                                               Class<?>[] with,                                               List<Class<?>> list)    {        for (int i = 0; i < from.length; i++) {            if (!list.contains(from[i])) {                for (int j = 0; j < with.length; j++) {                    if (with[j].isAssignableFrom(from[i])) {                        list.add(from[i]);                        break;                    }                }            }        }    }     /**     * Given the exceptions declared in the throws clause of a proxy method,     * compute the exceptions that need to be caught from the invocation     * handler's invoke method and rethrown intact in the method's     * implementation before catching other Throwables and wrapping them     * in UndeclaredThrowableExceptions.     *     * The exceptions to be caught are returned in a List object.  Each     * exception in the returned list is guaranteed to not be a subclass of     * any of the other exceptions in the list, so the catch blocks for     * these exceptions may be generated in any order relative to each other.     *     * Error and RuntimeException are each always contained by the returned     * list (if none of their superclasses are contained), since those     * unchecked exceptions should always be rethrown intact, and thus their     * subclasses will never appear in the returned list.     *     * The returned List will be empty if java.lang.Throwable is in the     * given list of declared exceptions, indicating that no exceptions     * need to be caught.     */    private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {        List<Class<?>> uniqueList = new ArrayList<Class<?>>();                                                // unique exceptions to catch         uniqueList.add(Error.class);            // always catch/rethrow these        uniqueList.add(RuntimeException.class);     nextException:        for (int i = 0; i < exceptions.length; i++) {            Class<?> ex = exceptions[i];            if (ex.isAssignableFrom(Throwable.class)) {                /*                 * If Throwable is declared to be thrown by the proxy method,                 * then no catch blocks are necessary, because the invoke                 * can, at most, throw Throwable anyway.                 */                uniqueList.clear();                break;            } else if (!Throwable.class.isAssignableFrom(ex)) {                /*                 * Ignore types that cannot be thrown by the invoke method.                 */                continue;            }            /*             * Compare this exception against the current list of             * exceptions that need to be caught:             */            for (int j = 0; j < uniqueList.size();) {                Class<?> ex2 = uniqueList.get(j);                if (ex2.isAssignableFrom(ex)) {                    /*                     * if a superclass of this exception is already on                     * the list to catch, then ignore this one and continue;                     */                    continue nextException;                } else if (ex.isAssignableFrom(ex2)) {                    /*                     * if a subclass of this exception is on the list                     * to catch, then remove it;                     */                    uniqueList.remove(j);                } else {                    j++;        // else continue comparing.                }            }            // This exception is unique (so far): add it to the list to catch.            uniqueList.add(ex);        }        return uniqueList;    }     /**     * A PrimitiveTypeInfo object contains assorted information about     * a primitive type in its public fields.  The struct for a particular     * primitive type can be obtained using the static "get" method.     */    private static class PrimitiveTypeInfo {         /** "base type" used in various descriptors (see JVMS section 4.3.2) */        public String baseTypeString;         /** name of corresponding wrapper class */        public String wrapperClassName;         /** method descriptor for wrapper class "valueOf" factory method */        public String wrapperValueOfDesc;         /** name of wrapper class method for retrieving primitive value */        public String unwrapMethodName;         /** descriptor of same method */        public String unwrapMethodDesc;         private static Map<Class,PrimitiveTypeInfo> table =            new HashMap<Class,PrimitiveTypeInfo>();        static {            add(byte.class, Byte.class);            add(char.class, Character.class);            add(double.class, Double.class);            add(float.class, Float.class);            add(int.class, Integer.class);            add(long.class, Long.class);            add(short.class, Short.class);            add(boolean.class, Boolean.class);        }         private static void add(Class primitiveClass, Class wrapperClass) {            table.put(primitiveClass,                      new PrimitiveTypeInfo(primitiveClass, wrapperClass));        }         private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {            assert primitiveClass.isPrimitive();             baseTypeString =                Array.newInstance(primitiveClass, 0)                .getClass().getName().substring(1);            wrapperClassName = dotToSlash(wrapperClass.getName());            wrapperValueOfDesc =                "(" + baseTypeString + ")L" + wrapperClassName + ";";            unwrapMethodName = primitiveClass.getName() + "Value";            unwrapMethodDesc = "()" + baseTypeString;        }         public static PrimitiveTypeInfo get(Class cl) {            return table.get(cl);        }    }      /**     * A ConstantPool object represents the constant pool of a class file     * being generated.  This representation of a constant pool is designed     * specifically for use by ProxyGenerator; in particular, it assumes     * that constant pool entries will not need to be resorted (for example,     * by their type, as the Java compiler does), so that the final index     * value can be assigned and used when an entry is first created.     *     * Note that new entries cannot be created after the constant pool has     * been written to a class file.  To prevent such logic errors, a     * ConstantPool instance can be marked "read only", so that further     * attempts to add new entries will fail with a runtime exception.     *     * See JVMS section 4.4 for more information about the constant pool     * of a class file.     */    private static class ConstantPool {         /**         * list of constant pool entries, in constant pool index order.         *         * This list is used when writing the constant pool to a stream         * and for assigning the next index value.  Note that element 0         * of this list corresponds to constant pool index 1.         */        private List<Entry> pool = new ArrayList<Entry>(32);         /**         * maps constant pool data of all types to constant pool indexes.         *         * This map is used to look up the index of an existing entry for         * values of all types.         */        private Map<Object,Short> map = new HashMap<Object,Short>(16);         /** true if no new constant pool entries may be added */        private boolean readOnly = false;         /**         * Get or assign the index for a CONSTANT_Utf8 entry.         */        public short getUtf8(String s) {            if (s == null) {                throw new NullPointerException();            }            return getValue(s);        }         /**         * Get or assign the index for a CONSTANT_Integer entry.         */        public short getInteger(int i) {            return getValue(new Integer(i));        }         /**         * Get or assign the index for a CONSTANT_Float entry.         */        public short getFloat(float f) {            return getValue(new Float(f));        }         /**         * Get or assign the index for a CONSTANT_Class entry.         */        public short getClass(String name) {            short utf8Index = getUtf8(name);            return getIndirect(new IndirectEntry(                CONSTANT_CLASS, utf8Index));        }         /**         * Get or assign the index for a CONSTANT_String entry.         */        public short getString(String s) {            short utf8Index = getUtf8(s);            return getIndirect(new IndirectEntry(                CONSTANT_STRING, utf8Index));        }         /**         * Get or assign the index for a CONSTANT_FieldRef entry.         */        public short getFieldRef(String className,                                 String name, String descriptor)        {            short classIndex = getClass(className);            short nameAndTypeIndex = getNameAndType(name, descriptor);            return getIndirect(new IndirectEntry(                CONSTANT_FIELD, classIndex, nameAndTypeIndex));        }         /**         * Get or assign the index for a CONSTANT_MethodRef entry.         */        public short getMethodRef(String className,                                  String name, String descriptor)        {            short classIndex = getClass(className);            short nameAndTypeIndex = getNameAndType(name, descriptor);            return getIndirect(new IndirectEntry(                CONSTANT_METHOD, classIndex, nameAndTypeIndex));        }         /**         * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.         */        public short getInterfaceMethodRef(String className, String name,                                           String descriptor)        {            short classIndex = getClass(className);            short nameAndTypeIndex = getNameAndType(name, descriptor);            return getIndirect(new IndirectEntry(                CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));        }         /**         * Get or assign the index for a CONSTANT_NameAndType entry.         */        public short getNameAndType(String name, String descriptor) {            short nameIndex = getUtf8(name);            short descriptorIndex = getUtf8(descriptor);            return getIndirect(new IndirectEntry(                CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));        }         /**         * Set this ConstantPool instance to be "read only".         *         * After this method has been called, further requests to get         * an index for a non-existent entry will cause an InternalError         * to be thrown instead of creating of the entry.         */        public void setReadOnly() {            readOnly = true;        }         /**         * Write this constant pool to a stream as part of         * the class file format.         *         * This consists of writing the "constant_pool_count" and         * "constant_pool[]" items of the "ClassFile" structure, as         * described in JVMS section 4.1.         */        public void write(OutputStream out) throws IOException {            DataOutputStream dataOut = new DataOutputStream(out);             // constant_pool_count: number of entries plus one            dataOut.writeShort(pool.size() + 1);             for (Entry e : pool) {                e.write(dataOut);            }        }         /**         * Add a new constant pool entry and return its index.         */        private short addEntry(Entry entry) {            pool.add(entry);            /*             * Note that this way of determining the index of the             * added entry is wrong if this pool supports             * CONSTANT_Long or CONSTANT_Double entries.             */            if (pool.size() >= 65535) {                throw new IllegalArgumentException(                    "constant pool size limit exceeded");            }            return (short) pool.size();        }         /**         * Get or assign the index for an entry of a type that contains         * a direct value.  The type of the given object determines the         * type of the desired entry as follows:         *         *      java.lang.String        CONSTANT_Utf8         *      java.lang.Integer       CONSTANT_Integer         *      java.lang.Float         CONSTANT_Float         *      java.lang.Long          CONSTANT_Long         *      java.lang.Double        CONSTANT_DOUBLE         */        private short getValue(Object key) {            Short index = map.get(key);            if (index != null) {                return index.shortValue();            } else {                if (readOnly) {                    throw new InternalError(                        "late constant pool addition: " + key);                }                short i = addEntry(new ValueEntry(key));                map.put(key, new Short(i));                return i;            }        }         /**         * Get or assign the index for an entry of a type that contains         * references to other constant pool entries.         */        private short getIndirect(IndirectEntry e) {            Short index = map.get(e);            if (index != null) {                return index.shortValue();            } else {                if (readOnly) {                    throw new InternalError("late constant pool addition");                }                short i = addEntry(e);                map.put(e, new Short(i));                return i;            }        }         /**         * Entry is the abstact superclass of all constant pool entry types         * that can be stored in the "pool" list; its purpose is to define a         * common method for writing constant pool entries to a class file.         */        private static abstract class Entry {            public abstract void write(DataOutputStream out)                throws IOException;        }         /**         * ValueEntry represents a constant pool entry of a type that         * contains a direct value (see the comments for the "getValue"         * method for a list of such types).         *         * ValueEntry objects are not used as keys for their entries in the         * Map "map", so no useful hashCode or equals methods are defined.         */        private static class ValueEntry extends Entry {            private Object value;             public ValueEntry(Object value) {                this.value = value;            }             public void write(DataOutputStream out) throws IOException {                if (value instanceof String) {                    out.writeByte(CONSTANT_UTF8);                    out.writeUTF((String) value);                } else if (value instanceof Integer) {                    out.writeByte(CONSTANT_INTEGER);                    out.writeInt(((Integer) value).intValue());                } else if (value instanceof Float) {                    out.writeByte(CONSTANT_FLOAT);                    out.writeFloat(((Float) value).floatValue());                } else if (value instanceof Long) {                    out.writeByte(CONSTANT_LONG);                    out.writeLong(((Long) value).longValue());                } else if (value instanceof Double) {                    out.writeDouble(CONSTANT_DOUBLE);                    out.writeDouble(((Double) value).doubleValue());                } else {                    throw new InternalError("bogus value entry: " + value);                }            }        }         /**         * IndirectEntry represents a constant pool entry of a type that         * references other constant pool entries, i.e., the following types:         *         *      CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,         *      CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and         *      CONSTANT_NameAndType.         *         * Each of these entry types contains either one or two indexes of         * other constant pool entries.         *         * IndirectEntry objects are used as the keys for their entries in         * the Map "map", so the hashCode and equals methods are overridden         * to allow matching.         */        private static class IndirectEntry extends Entry {            private int tag;            private short index0;            private short index1;             /**             * Construct an IndirectEntry for a constant pool entry type             * that contains one index of another entry.             */            public IndirectEntry(int tag, short index) {                this.tag = tag;                this.index0 = index;                this.index1 = 0;            }             /**             * Construct an IndirectEntry for a constant pool entry type             * that contains two indexes for other entries.             */            public IndirectEntry(int tag, short index0, short index1) {                this.tag = tag;                this.index0 = index0;                this.index1 = index1;            }             public void write(DataOutputStream out) throws IOException {                out.writeByte(tag);                out.writeShort(index0);                /*                 * If this entry type contains two indexes, write                 * out the second, too.                 */                if (tag == CONSTANT_FIELD ||                    tag == CONSTANT_METHOD ||                    tag == CONSTANT_INTERFACEMETHOD ||                    tag == CONSTANT_NAMEANDTYPE)                {                    out.writeShort(index1);                }            }             public int hashCode() {                return tag + index0 + index1;            }             public boolean equals(Object obj) {                if (obj instanceof IndirectEntry) {                    IndirectEntry other = (IndirectEntry) obj;                    if (tag == other.tag &&                        index0 == other.index0 && index1 == other.index1)

Lines 1501–2000 of 2009. Previous lines