--- old/langtools/src/jdk.compiler/share/classes/com/sun/tools/classfile/ConstantPool.java 2015-05-26 21:42:19.507832824 -0700 +++ /dev/null 2015-04-26 22:05:36.465433038 -0700 @@ -1,914 +0,0 @@ -/* - * Copyright (c) 2007, 2011, 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 com.sun.tools.classfile; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Iterator; - -/** - * See JVMS, section 4.5. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class ConstantPool { - - public static class InvalidIndex extends ConstantPoolException { - private static final long serialVersionUID = -4350294289300939730L; - InvalidIndex(int index) { - super(index); - } - - @Override - public String getMessage() { - // i18n - return "invalid index #" + index; - } - } - - public static class UnexpectedEntry extends ConstantPoolException { - private static final long serialVersionUID = 6986335935377933211L; - UnexpectedEntry(int index, int expected_tag, int found_tag) { - super(index); - this.expected_tag = expected_tag; - this.found_tag = found_tag; - } - - @Override - public String getMessage() { - // i18n? - return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag; - } - - public final int expected_tag; - public final int found_tag; - } - - public static class InvalidEntry extends ConstantPoolException { - private static final long serialVersionUID = 1000087545585204447L; - InvalidEntry(int index, int tag) { - super(index); - this.tag = tag; - } - - @Override - public String getMessage() { - // i18n? - return "unexpected tag at #" + index + ": " + tag; - } - - public final int tag; - } - - public static class EntryNotFound extends ConstantPoolException { - private static final long serialVersionUID = 2885537606468581850L; - EntryNotFound(Object value) { - super(-1); - this.value = value; - } - - @Override - public String getMessage() { - // i18n? - return "value not found: " + value; - } - - public final Object value; - } - - public static final int CONSTANT_Utf8 = 1; - public static final int CONSTANT_Integer = 3; - public static final int CONSTANT_Float = 4; - public static final int CONSTANT_Long = 5; - public static final int CONSTANT_Double = 6; - public static final int CONSTANT_Class = 7; - public static final int CONSTANT_String = 8; - public static final int CONSTANT_Fieldref = 9; - public static final int CONSTANT_Methodref = 10; - public static final int CONSTANT_InterfaceMethodref = 11; - public static final int CONSTANT_NameAndType = 12; - public static final int CONSTANT_MethodHandle = 15; - public static final int CONSTANT_MethodType = 16; - public static final int CONSTANT_InvokeDynamic = 18; - - public static enum RefKind { - REF_getField(1, "getfield"), - REF_getStatic(2, "getstatic"), - REF_putField(3, "putfield"), - REF_putStatic(4, "putstatic"), - REF_invokeVirtual(5, "invokevirtual"), - REF_invokeStatic(6, "invokestatic"), - REF_invokeSpecial(7, "invokespecial"), - REF_newInvokeSpecial(8, "newinvokespecial"), - REF_invokeInterface(9, "invokeinterface"); - - public final int tag; - public final String name; - - RefKind(int tag, String name) { - this.tag = tag; - this.name = name; - } - - static RefKind getRefkind(int tag) { - switch(tag) { - case 1: - return REF_getField; - case 2: - return REF_getStatic; - case 3: - return REF_putField; - case 4: - return REF_putStatic; - case 5: - return REF_invokeVirtual; - case 6: - return REF_invokeStatic; - case 7: - return REF_invokeSpecial; - case 8: - return REF_newInvokeSpecial; - case 9: - return REF_invokeInterface; - default: - return null; - } - } - } - - ConstantPool(ClassReader cr) throws IOException, InvalidEntry { - int count = cr.readUnsignedShort(); - pool = new CPInfo[count]; - for (int i = 1; i < count; i++) { - int tag = cr.readUnsignedByte(); - switch (tag) { - case CONSTANT_Class: - pool[i] = new CONSTANT_Class_info(this, cr); - break; - - case CONSTANT_Double: - pool[i] = new CONSTANT_Double_info(cr); - i++; - break; - - case CONSTANT_Fieldref: - pool[i] = new CONSTANT_Fieldref_info(this, cr); - break; - - case CONSTANT_Float: - pool[i] = new CONSTANT_Float_info(cr); - break; - - case CONSTANT_Integer: - pool[i] = new CONSTANT_Integer_info(cr); - break; - - case CONSTANT_InterfaceMethodref: - pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr); - break; - - case CONSTANT_InvokeDynamic: - pool[i] = new CONSTANT_InvokeDynamic_info(this, cr); - break; - - case CONSTANT_Long: - pool[i] = new CONSTANT_Long_info(cr); - i++; - break; - - case CONSTANT_MethodHandle: - pool[i] = new CONSTANT_MethodHandle_info(this, cr); - break; - - case CONSTANT_MethodType: - pool[i] = new CONSTANT_MethodType_info(this, cr); - break; - - case CONSTANT_Methodref: - pool[i] = new CONSTANT_Methodref_info(this, cr); - break; - - case CONSTANT_NameAndType: - pool[i] = new CONSTANT_NameAndType_info(this, cr); - break; - - case CONSTANT_String: - pool[i] = new CONSTANT_String_info(this, cr); - break; - - case CONSTANT_Utf8: - pool[i] = new CONSTANT_Utf8_info(cr); - break; - - default: - throw new InvalidEntry(i, tag); - } - } - } - - public ConstantPool(CPInfo[] pool) { - this.pool = pool; - } - - public int size() { - return pool.length; - } - - public int byteLength() { - int length = 2; - for (int i = 1; i < size(); ) { - CPInfo cpInfo = pool[i]; - length += cpInfo.byteLength(); - i += cpInfo.size(); - } - return length; - } - - public CPInfo get(int index) throws InvalidIndex { - if (index <= 0 || index >= pool.length) - throw new InvalidIndex(index); - CPInfo info = pool[index]; - if (info == null) { - // this occurs for indices referencing the "second half" of an - // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long - throw new InvalidIndex(index); - } - return pool[index]; - } - - private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry { - CPInfo info = get(index); - if (info.getTag() != expected_type) - throw new UnexpectedEntry(index, expected_type, info.getTag()); - return info; - } - - public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8)); - } - - public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_Class_info) get(index, CONSTANT_Class)); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry { - return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType)); - } - - public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry { - return getUTF8Info(index).value; - } - - public int getUTF8Index(String value) throws EntryNotFound { - for (int i = 1; i < pool.length; i++) { - CPInfo info = pool[i]; - if (info instanceof CONSTANT_Utf8_info && - ((CONSTANT_Utf8_info) info).value.equals(value)) - return i; - } - throw new EntryNotFound(value); - } - - public Iterable entries() { - return new Iterable() { - public Iterator iterator() { - return new Iterator() { - - public boolean hasNext() { - return next < pool.length; - } - - public CPInfo next() { - current = pool[next]; - switch (current.getTag()) { - case CONSTANT_Double: - case CONSTANT_Long: - next += 2; - break; - default: - next += 1; - } - return current; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - private CPInfo current; - private int next = 1; - - }; - } - }; - } - - private CPInfo[] pool; - - public interface Visitor { - R visitClass(CONSTANT_Class_info info, P p); - R visitDouble(CONSTANT_Double_info info, P p); - R visitFieldref(CONSTANT_Fieldref_info info, P p); - R visitFloat(CONSTANT_Float_info info, P p); - R visitInteger(CONSTANT_Integer_info info, P p); - R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p); - R visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, P p); - R visitLong(CONSTANT_Long_info info, P p); - R visitNameAndType(CONSTANT_NameAndType_info info, P p); - R visitMethodref(CONSTANT_Methodref_info info, P p); - R visitMethodHandle(CONSTANT_MethodHandle_info info, P p); - R visitMethodType(CONSTANT_MethodType_info info, P p); - R visitString(CONSTANT_String_info info, P p); - R visitUtf8(CONSTANT_Utf8_info info, P p); - } - - public static abstract class CPInfo { - CPInfo() { - this.cp = null; - } - - CPInfo(ConstantPool cp) { - this.cp = cp; - } - - public abstract int getTag(); - - /** The number of slots in the constant pool used by this entry. - * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */ - public int size() { - return 1; - } - - public abstract int byteLength(); - - public abstract R accept(Visitor visitor, D data); - - protected final ConstantPool cp; - } - - public static abstract class CPRefInfo extends CPInfo { - protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException { - super(cp); - this.tag = tag; - class_index = cr.readUnsignedShort(); - name_and_type_index = cr.readUnsignedShort(); - } - - protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) { - super(cp); - this.tag = tag; - this.class_index = class_index; - this.name_and_type_index = name_and_type_index; - } - - public int getTag() { - return tag; - } - - public int byteLength() { - return 5; - } - - public CONSTANT_Class_info getClassInfo() throws ConstantPoolException { - return cp.getClassInfo(class_index); - } - - public String getClassName() throws ConstantPoolException { - return cp.getClassInfo(class_index).getName(); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { - return cp.getNameAndTypeInfo(name_and_type_index); - } - - public final int tag; - public final int class_index; - public final int name_and_type_index; - } - - public static class CONSTANT_Class_info extends CPInfo { - CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - name_index = cr.readUnsignedShort(); - } - - public CONSTANT_Class_info(ConstantPool cp, int name_index) { - super(cp); - this.name_index = name_index; - } - - public int getTag() { - return CONSTANT_Class; - } - - public int byteLength() { - return 3; - } - - /** - * Get the raw value of the class referenced by this constant pool entry. - * This will either be the name of the class, in internal form, or a - * descriptor for an array class. - * @return the raw value of the class - */ - public String getName() throws ConstantPoolException { - return cp.getUTF8Value(name_index); - } - - /** - * If this constant pool entry identifies either a class or interface type, - * or a possibly multi-dimensional array of a class of interface type, - * return the name of the class or interface in internal form. Otherwise, - * (i.e. if this is a possibly multi-dimensional array of a primitive type), - * return null. - * @return the base class or interface name - */ - public String getBaseName() throws ConstantPoolException { - String name = getName(); - if (name.startsWith("[")) { - int index = name.indexOf("[L"); - if (index == -1) - return null; - return name.substring(index + 2, name.length() - 1); - } else - return name; - } - - public int getDimensionCount() throws ConstantPoolException { - String name = getName(); - int count = 0; - while (name.charAt(count) == '[') - count++; - return count; - } - - @Override - public String toString() { - return "CONSTANT_Class_info[name_index: " + name_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitClass(this, data); - } - - public final int name_index; - } - - public static class CONSTANT_Double_info extends CPInfo { - CONSTANT_Double_info(ClassReader cr) throws IOException { - value = cr.readDouble(); - } - - public CONSTANT_Double_info(double value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Double; - } - - public int byteLength() { - return 9; - } - - @Override - public int size() { - return 2; - } - - @Override - public String toString() { - return "CONSTANT_Double_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitDouble(this, data); - } - - public final double value; - } - - public static class CONSTANT_Fieldref_info extends CPRefInfo { - CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp, cr, CONSTANT_Fieldref); - } - - public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) { - super(cp, CONSTANT_Fieldref, class_index, name_and_type_index); - } - - @Override - public String toString() { - return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitFieldref(this, data); - } - } - - public static class CONSTANT_Float_info extends CPInfo { - CONSTANT_Float_info(ClassReader cr) throws IOException { - value = cr.readFloat(); - } - - public CONSTANT_Float_info(float value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Float; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_Float_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitFloat(this, data); - } - - public final float value; - } - - public static class CONSTANT_Integer_info extends CPInfo { - CONSTANT_Integer_info(ClassReader cr) throws IOException { - value = cr.readInt(); - } - - public CONSTANT_Integer_info(int value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Integer; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_Integer_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInteger(this, data); - } - - public final int value; - } - - public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo { - CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp, cr, CONSTANT_InterfaceMethodref); - } - - public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) { - super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index); - } - - @Override - public String toString() { - return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInterfaceMethodref(this, data); - } - } - - public static class CONSTANT_InvokeDynamic_info extends CPInfo { - CONSTANT_InvokeDynamic_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - bootstrap_method_attr_index = cr.readUnsignedShort(); - name_and_type_index = cr.readUnsignedShort(); - } - - public CONSTANT_InvokeDynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) { - super(cp); - this.bootstrap_method_attr_index = bootstrap_method_index; - this.name_and_type_index = name_and_type_index; - } - - public int getTag() { - return CONSTANT_InvokeDynamic; - } - - public int byteLength() { - return 5; - } - - @Override - public String toString() { - return "CONSTANT_InvokeDynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitInvokeDynamic(this, data); - } - - public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { - return cp.getNameAndTypeInfo(name_and_type_index); - } - - public final int bootstrap_method_attr_index; - public final int name_and_type_index; - } - - public static class CONSTANT_Long_info extends CPInfo { - CONSTANT_Long_info(ClassReader cr) throws IOException { - value = cr.readLong(); - } - - public CONSTANT_Long_info(long value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Long; - } - - @Override - public int size() { - return 2; - } - - public int byteLength() { - return 9; - } - - @Override - public String toString() { - return "CONSTANT_Long_info[value: " + value + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitLong(this, data); - } - - public final long value; - } - - public static class CONSTANT_MethodHandle_info extends CPInfo { - CONSTANT_MethodHandle_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - reference_kind = RefKind.getRefkind(cr.readUnsignedByte()); - reference_index = cr.readUnsignedShort(); - } - - public CONSTANT_MethodHandle_info(ConstantPool cp, RefKind ref_kind, int member_index) { - super(cp); - this.reference_kind = ref_kind; - this.reference_index = member_index; - } - - public int getTag() { - return CONSTANT_MethodHandle; - } - - public int byteLength() { - return 4; - } - - @Override - public String toString() { - return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodHandle(this, data); - } - - public CPRefInfo getCPRefInfo() throws ConstantPoolException { - int expected = CONSTANT_Methodref; - int actual = cp.get(reference_index).getTag(); - // allow these tag types also: - switch (actual) { - case CONSTANT_Fieldref: - case CONSTANT_InterfaceMethodref: - expected = actual; - } - return (CPRefInfo) cp.get(reference_index, expected); - } - - public final RefKind reference_kind; - public final int reference_index; - } - - public static class CONSTANT_MethodType_info extends CPInfo { - CONSTANT_MethodType_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - descriptor_index = cr.readUnsignedShort(); - } - - public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) { - super(cp); - this.descriptor_index = signature_index; - } - - public int getTag() { - return CONSTANT_MethodType; - } - - public int byteLength() { - return 3; - } - - @Override - public String toString() { - return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodType(this, data); - } - - public String getType() throws ConstantPoolException { - return cp.getUTF8Value(descriptor_index); - } - - public final int descriptor_index; - } - - public static class CONSTANT_Methodref_info extends CPRefInfo { - CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp, cr, CONSTANT_Methodref); - } - - public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) { - super(cp, CONSTANT_Methodref, class_index, name_and_type_index); - } - - @Override - public String toString() { - return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitMethodref(this, data); - } - } - - public static class CONSTANT_NameAndType_info extends CPInfo { - CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - name_index = cr.readUnsignedShort(); - type_index = cr.readUnsignedShort(); - } - - public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) { - super(cp); - this.name_index = name_index; - this.type_index = type_index; - } - - public int getTag() { - return CONSTANT_NameAndType; - } - - public int byteLength() { - return 5; - } - - public String getName() throws ConstantPoolException { - return cp.getUTF8Value(name_index); - } - - public String getType() throws ConstantPoolException { - return cp.getUTF8Value(type_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitNameAndType(this, data); - } - - @Override - public String toString() { - return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]"; - } - - public final int name_index; - public final int type_index; - } - - public static class CONSTANT_String_info extends CPInfo { - CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException { - super(cp); - string_index = cr.readUnsignedShort(); - } - - public CONSTANT_String_info(ConstantPool cp, int string_index) { - super(cp); - this.string_index = string_index; - } - - public int getTag() { - return CONSTANT_String; - } - - public int byteLength() { - return 3; - } - - public String getString() throws ConstantPoolException { - return cp.getUTF8Value(string_index); - } - - public R accept(Visitor visitor, D data) { - return visitor.visitString(this, data); - } - - @Override - public String toString() { - return "CONSTANT_String_info[class_index: " + string_index + "]"; - } - - public final int string_index; - } - - public static class CONSTANT_Utf8_info extends CPInfo { - CONSTANT_Utf8_info(ClassReader cr) throws IOException { - value = cr.readUTF(); - } - - public CONSTANT_Utf8_info(String value) { - this.value = value; - } - - public int getTag() { - return CONSTANT_Utf8; - } - - public int byteLength() { - class SizeOutputStream extends OutputStream { - @Override - public void write(int b) { - size++; - } - int size; - } - SizeOutputStream sizeOut = new SizeOutputStream(); - DataOutputStream out = new DataOutputStream(sizeOut); - try { out.writeUTF(value); } catch (IOException ignore) { } - return 1 + sizeOut.size; - } - - @Override - public String toString() { - if (value.length() < 32 && isPrintableAscii(value)) - return "CONSTANT_Utf8_info[value: \"" + value + "\"]"; - else - return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]"; - } - - static boolean isPrintableAscii(String s) { - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c < 32 || c >= 127) - return false; - } - return true; - } - - public R accept(Visitor visitor, D data) { - return visitor.visitUtf8(this, data); - } - - public final String value; - } - -} --- /dev/null 2015-04-26 22:05:36.465433038 -0700 +++ new/langtools/src/jdk.jdeps/share/classes/com/sun/tools/classfile/ConstantPool.java 2015-05-26 21:42:19.331832822 -0700 @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2007, 2011, 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 com.sun.tools.classfile; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; + +/** + * See JVMS, section 4.5. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class ConstantPool { + + public static class InvalidIndex extends ConstantPoolException { + private static final long serialVersionUID = -4350294289300939730L; + InvalidIndex(int index) { + super(index); + } + + @Override + public String getMessage() { + // i18n + return "invalid index #" + index; + } + } + + public static class UnexpectedEntry extends ConstantPoolException { + private static final long serialVersionUID = 6986335935377933211L; + UnexpectedEntry(int index, int expected_tag, int found_tag) { + super(index); + this.expected_tag = expected_tag; + this.found_tag = found_tag; + } + + @Override + public String getMessage() { + // i18n? + return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag; + } + + public final int expected_tag; + public final int found_tag; + } + + public static class InvalidEntry extends ConstantPoolException { + private static final long serialVersionUID = 1000087545585204447L; + InvalidEntry(int index, int tag) { + super(index); + this.tag = tag; + } + + @Override + public String getMessage() { + // i18n? + return "unexpected tag at #" + index + ": " + tag; + } + + public final int tag; + } + + public static class EntryNotFound extends ConstantPoolException { + private static final long serialVersionUID = 2885537606468581850L; + EntryNotFound(Object value) { + super(-1); + this.value = value; + } + + @Override + public String getMessage() { + // i18n? + return "value not found: " + value; + } + + public final Object value; + } + + public static final int CONSTANT_Utf8 = 1; + public static final int CONSTANT_Integer = 3; + public static final int CONSTANT_Float = 4; + public static final int CONSTANT_Long = 5; + public static final int CONSTANT_Double = 6; + public static final int CONSTANT_Class = 7; + public static final int CONSTANT_String = 8; + public static final int CONSTANT_Fieldref = 9; + public static final int CONSTANT_Methodref = 10; + public static final int CONSTANT_InterfaceMethodref = 11; + public static final int CONSTANT_NameAndType = 12; + public static final int CONSTANT_MethodHandle = 15; + public static final int CONSTANT_MethodType = 16; + public static final int CONSTANT_InvokeDynamic = 18; + + public static enum RefKind { + REF_getField(1, "getfield"), + REF_getStatic(2, "getstatic"), + REF_putField(3, "putfield"), + REF_putStatic(4, "putstatic"), + REF_invokeVirtual(5, "invokevirtual"), + REF_invokeStatic(6, "invokestatic"), + REF_invokeSpecial(7, "invokespecial"), + REF_newInvokeSpecial(8, "newinvokespecial"), + REF_invokeInterface(9, "invokeinterface"); + + public final int tag; + public final String name; + + RefKind(int tag, String name) { + this.tag = tag; + this.name = name; + } + + static RefKind getRefkind(int tag) { + switch(tag) { + case 1: + return REF_getField; + case 2: + return REF_getStatic; + case 3: + return REF_putField; + case 4: + return REF_putStatic; + case 5: + return REF_invokeVirtual; + case 6: + return REF_invokeStatic; + case 7: + return REF_invokeSpecial; + case 8: + return REF_newInvokeSpecial; + case 9: + return REF_invokeInterface; + default: + return null; + } + } + } + + ConstantPool(ClassReader cr) throws IOException, InvalidEntry { + int count = cr.readUnsignedShort(); + pool = new CPInfo[count]; + for (int i = 1; i < count; i++) { + int tag = cr.readUnsignedByte(); + switch (tag) { + case CONSTANT_Class: + pool[i] = new CONSTANT_Class_info(this, cr); + break; + + case CONSTANT_Double: + pool[i] = new CONSTANT_Double_info(cr); + i++; + break; + + case CONSTANT_Fieldref: + pool[i] = new CONSTANT_Fieldref_info(this, cr); + break; + + case CONSTANT_Float: + pool[i] = new CONSTANT_Float_info(cr); + break; + + case CONSTANT_Integer: + pool[i] = new CONSTANT_Integer_info(cr); + break; + + case CONSTANT_InterfaceMethodref: + pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr); + break; + + case CONSTANT_InvokeDynamic: + pool[i] = new CONSTANT_InvokeDynamic_info(this, cr); + break; + + case CONSTANT_Long: + pool[i] = new CONSTANT_Long_info(cr); + i++; + break; + + case CONSTANT_MethodHandle: + pool[i] = new CONSTANT_MethodHandle_info(this, cr); + break; + + case CONSTANT_MethodType: + pool[i] = new CONSTANT_MethodType_info(this, cr); + break; + + case CONSTANT_Methodref: + pool[i] = new CONSTANT_Methodref_info(this, cr); + break; + + case CONSTANT_NameAndType: + pool[i] = new CONSTANT_NameAndType_info(this, cr); + break; + + case CONSTANT_String: + pool[i] = new CONSTANT_String_info(this, cr); + break; + + case CONSTANT_Utf8: + pool[i] = new CONSTANT_Utf8_info(cr); + break; + + default: + throw new InvalidEntry(i, tag); + } + } + } + + public ConstantPool(CPInfo[] pool) { + this.pool = pool; + } + + public int size() { + return pool.length; + } + + public int byteLength() { + int length = 2; + for (int i = 1; i < size(); ) { + CPInfo cpInfo = pool[i]; + length += cpInfo.byteLength(); + i += cpInfo.size(); + } + return length; + } + + public CPInfo get(int index) throws InvalidIndex { + if (index <= 0 || index >= pool.length) + throw new InvalidIndex(index); + CPInfo info = pool[index]; + if (info == null) { + // this occurs for indices referencing the "second half" of an + // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long + throw new InvalidIndex(index); + } + return pool[index]; + } + + private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry { + CPInfo info = get(index); + if (info.getTag() != expected_type) + throw new UnexpectedEntry(index, expected_type, info.getTag()); + return info; + } + + public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry { + return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8)); + } + + public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry { + return ((CONSTANT_Class_info) get(index, CONSTANT_Class)); + } + + public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry { + return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType)); + } + + public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry { + return getUTF8Info(index).value; + } + + public int getUTF8Index(String value) throws EntryNotFound { + for (int i = 1; i < pool.length; i++) { + CPInfo info = pool[i]; + if (info instanceof CONSTANT_Utf8_info && + ((CONSTANT_Utf8_info) info).value.equals(value)) + return i; + } + throw new EntryNotFound(value); + } + + public Iterable entries() { + return new Iterable() { + public Iterator iterator() { + return new Iterator() { + + public boolean hasNext() { + return next < pool.length; + } + + public CPInfo next() { + current = pool[next]; + switch (current.getTag()) { + case CONSTANT_Double: + case CONSTANT_Long: + next += 2; + break; + default: + next += 1; + } + return current; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + private CPInfo current; + private int next = 1; + + }; + } + }; + } + + private CPInfo[] pool; + + public interface Visitor { + R visitClass(CONSTANT_Class_info info, P p); + R visitDouble(CONSTANT_Double_info info, P p); + R visitFieldref(CONSTANT_Fieldref_info info, P p); + R visitFloat(CONSTANT_Float_info info, P p); + R visitInteger(CONSTANT_Integer_info info, P p); + R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p); + R visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, P p); + R visitLong(CONSTANT_Long_info info, P p); + R visitNameAndType(CONSTANT_NameAndType_info info, P p); + R visitMethodref(CONSTANT_Methodref_info info, P p); + R visitMethodHandle(CONSTANT_MethodHandle_info info, P p); + R visitMethodType(CONSTANT_MethodType_info info, P p); + R visitString(CONSTANT_String_info info, P p); + R visitUtf8(CONSTANT_Utf8_info info, P p); + } + + public static abstract class CPInfo { + CPInfo() { + this.cp = null; + } + + CPInfo(ConstantPool cp) { + this.cp = cp; + } + + public abstract int getTag(); + + /** The number of slots in the constant pool used by this entry. + * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */ + public int size() { + return 1; + } + + public abstract int byteLength(); + + public abstract R accept(Visitor visitor, D data); + + protected final ConstantPool cp; + } + + public static abstract class CPRefInfo extends CPInfo { + protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException { + super(cp); + this.tag = tag; + class_index = cr.readUnsignedShort(); + name_and_type_index = cr.readUnsignedShort(); + } + + protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) { + super(cp); + this.tag = tag; + this.class_index = class_index; + this.name_and_type_index = name_and_type_index; + } + + public int getTag() { + return tag; + } + + public int byteLength() { + return 5; + } + + public CONSTANT_Class_info getClassInfo() throws ConstantPoolException { + return cp.getClassInfo(class_index); + } + + public String getClassName() throws ConstantPoolException { + return cp.getClassInfo(class_index).getName(); + } + + public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { + return cp.getNameAndTypeInfo(name_and_type_index); + } + + public final int tag; + public final int class_index; + public final int name_and_type_index; + } + + public static class CONSTANT_Class_info extends CPInfo { + CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + name_index = cr.readUnsignedShort(); + } + + public CONSTANT_Class_info(ConstantPool cp, int name_index) { + super(cp); + this.name_index = name_index; + } + + public int getTag() { + return CONSTANT_Class; + } + + public int byteLength() { + return 3; + } + + /** + * Get the raw value of the class referenced by this constant pool entry. + * This will either be the name of the class, in internal form, or a + * descriptor for an array class. + * @return the raw value of the class + */ + public String getName() throws ConstantPoolException { + return cp.getUTF8Value(name_index); + } + + /** + * If this constant pool entry identifies either a class or interface type, + * or a possibly multi-dimensional array of a class of interface type, + * return the name of the class or interface in internal form. Otherwise, + * (i.e. if this is a possibly multi-dimensional array of a primitive type), + * return null. + * @return the base class or interface name + */ + public String getBaseName() throws ConstantPoolException { + String name = getName(); + if (name.startsWith("[")) { + int index = name.indexOf("[L"); + if (index == -1) + return null; + return name.substring(index + 2, name.length() - 1); + } else + return name; + } + + public int getDimensionCount() throws ConstantPoolException { + String name = getName(); + int count = 0; + while (name.charAt(count) == '[') + count++; + return count; + } + + @Override + public String toString() { + return "CONSTANT_Class_info[name_index: " + name_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitClass(this, data); + } + + public final int name_index; + } + + public static class CONSTANT_Double_info extends CPInfo { + CONSTANT_Double_info(ClassReader cr) throws IOException { + value = cr.readDouble(); + } + + public CONSTANT_Double_info(double value) { + this.value = value; + } + + public int getTag() { + return CONSTANT_Double; + } + + public int byteLength() { + return 9; + } + + @Override + public int size() { + return 2; + } + + @Override + public String toString() { + return "CONSTANT_Double_info[value: " + value + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitDouble(this, data); + } + + public final double value; + } + + public static class CONSTANT_Fieldref_info extends CPRefInfo { + CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp, cr, CONSTANT_Fieldref); + } + + public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) { + super(cp, CONSTANT_Fieldref, class_index, name_and_type_index); + } + + @Override + public String toString() { + return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitFieldref(this, data); + } + } + + public static class CONSTANT_Float_info extends CPInfo { + CONSTANT_Float_info(ClassReader cr) throws IOException { + value = cr.readFloat(); + } + + public CONSTANT_Float_info(float value) { + this.value = value; + } + + public int getTag() { + return CONSTANT_Float; + } + + public int byteLength() { + return 5; + } + + @Override + public String toString() { + return "CONSTANT_Float_info[value: " + value + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitFloat(this, data); + } + + public final float value; + } + + public static class CONSTANT_Integer_info extends CPInfo { + CONSTANT_Integer_info(ClassReader cr) throws IOException { + value = cr.readInt(); + } + + public CONSTANT_Integer_info(int value) { + this.value = value; + } + + public int getTag() { + return CONSTANT_Integer; + } + + public int byteLength() { + return 5; + } + + @Override + public String toString() { + return "CONSTANT_Integer_info[value: " + value + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitInteger(this, data); + } + + public final int value; + } + + public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo { + CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp, cr, CONSTANT_InterfaceMethodref); + } + + public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) { + super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index); + } + + @Override + public String toString() { + return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitInterfaceMethodref(this, data); + } + } + + public static class CONSTANT_InvokeDynamic_info extends CPInfo { + CONSTANT_InvokeDynamic_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + bootstrap_method_attr_index = cr.readUnsignedShort(); + name_and_type_index = cr.readUnsignedShort(); + } + + public CONSTANT_InvokeDynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) { + super(cp); + this.bootstrap_method_attr_index = bootstrap_method_index; + this.name_and_type_index = name_and_type_index; + } + + public int getTag() { + return CONSTANT_InvokeDynamic; + } + + public int byteLength() { + return 5; + } + + @Override + public String toString() { + return "CONSTANT_InvokeDynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitInvokeDynamic(this, data); + } + + public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException { + return cp.getNameAndTypeInfo(name_and_type_index); + } + + public final int bootstrap_method_attr_index; + public final int name_and_type_index; + } + + public static class CONSTANT_Long_info extends CPInfo { + CONSTANT_Long_info(ClassReader cr) throws IOException { + value = cr.readLong(); + } + + public CONSTANT_Long_info(long value) { + this.value = value; + } + + public int getTag() { + return CONSTANT_Long; + } + + @Override + public int size() { + return 2; + } + + public int byteLength() { + return 9; + } + + @Override + public String toString() { + return "CONSTANT_Long_info[value: " + value + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitLong(this, data); + } + + public final long value; + } + + public static class CONSTANT_MethodHandle_info extends CPInfo { + CONSTANT_MethodHandle_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + reference_kind = RefKind.getRefkind(cr.readUnsignedByte()); + reference_index = cr.readUnsignedShort(); + } + + public CONSTANT_MethodHandle_info(ConstantPool cp, RefKind ref_kind, int member_index) { + super(cp); + this.reference_kind = ref_kind; + this.reference_index = member_index; + } + + public int getTag() { + return CONSTANT_MethodHandle; + } + + public int byteLength() { + return 4; + } + + @Override + public String toString() { + return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitMethodHandle(this, data); + } + + public CPRefInfo getCPRefInfo() throws ConstantPoolException { + int expected = CONSTANT_Methodref; + int actual = cp.get(reference_index).getTag(); + // allow these tag types also: + switch (actual) { + case CONSTANT_Fieldref: + case CONSTANT_InterfaceMethodref: + expected = actual; + } + return (CPRefInfo) cp.get(reference_index, expected); + } + + public final RefKind reference_kind; + public final int reference_index; + } + + public static class CONSTANT_MethodType_info extends CPInfo { + CONSTANT_MethodType_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + descriptor_index = cr.readUnsignedShort(); + } + + public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) { + super(cp); + this.descriptor_index = signature_index; + } + + public int getTag() { + return CONSTANT_MethodType; + } + + public int byteLength() { + return 3; + } + + @Override + public String toString() { + return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitMethodType(this, data); + } + + public String getType() throws ConstantPoolException { + return cp.getUTF8Value(descriptor_index); + } + + public final int descriptor_index; + } + + public static class CONSTANT_Methodref_info extends CPRefInfo { + CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp, cr, CONSTANT_Methodref); + } + + public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) { + super(cp, CONSTANT_Methodref, class_index, name_and_type_index); + } + + @Override + public String toString() { + return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]"; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitMethodref(this, data); + } + } + + public static class CONSTANT_NameAndType_info extends CPInfo { + CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + name_index = cr.readUnsignedShort(); + type_index = cr.readUnsignedShort(); + } + + public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) { + super(cp); + this.name_index = name_index; + this.type_index = type_index; + } + + public int getTag() { + return CONSTANT_NameAndType; + } + + public int byteLength() { + return 5; + } + + public String getName() throws ConstantPoolException { + return cp.getUTF8Value(name_index); + } + + public String getType() throws ConstantPoolException { + return cp.getUTF8Value(type_index); + } + + public R accept(Visitor visitor, D data) { + return visitor.visitNameAndType(this, data); + } + + @Override + public String toString() { + return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]"; + } + + public final int name_index; + public final int type_index; + } + + public static class CONSTANT_String_info extends CPInfo { + CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException { + super(cp); + string_index = cr.readUnsignedShort(); + } + + public CONSTANT_String_info(ConstantPool cp, int string_index) { + super(cp); + this.string_index = string_index; + } + + public int getTag() { + return CONSTANT_String; + } + + public int byteLength() { + return 3; + } + + public String getString() throws ConstantPoolException { + return cp.getUTF8Value(string_index); + } + + public R accept(Visitor visitor, D data) { + return visitor.visitString(this, data); + } + + @Override + public String toString() { + return "CONSTANT_String_info[class_index: " + string_index + "]"; + } + + public final int string_index; + } + + public static class CONSTANT_Utf8_info extends CPInfo { + CONSTANT_Utf8_info(ClassReader cr) throws IOException { + value = cr.readUTF(); + } + + public CONSTANT_Utf8_info(String value) { + this.value = value; + } + + public int getTag() { + return CONSTANT_Utf8; + } + + public int byteLength() { + class SizeOutputStream extends OutputStream { + @Override + public void write(int b) { + size++; + } + int size; + } + SizeOutputStream sizeOut = new SizeOutputStream(); + DataOutputStream out = new DataOutputStream(sizeOut); + try { out.writeUTF(value); } catch (IOException ignore) { } + return 1 + sizeOut.size; + } + + @Override + public String toString() { + if (value.length() < 32 && isPrintableAscii(value)) + return "CONSTANT_Utf8_info[value: \"" + value + "\"]"; + else + return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]"; + } + + static boolean isPrintableAscii(String s) { + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c < 32 || c >= 127) + return false; + } + return true; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitUtf8(this, data); + } + + public final String value; + } + +}