jjg@46: /* ksrini@826: * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. jjg@46: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jjg@46: * jjg@46: * This code is free software; you can redistribute it and/or modify it jjg@46: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this jjg@46: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. jjg@46: * jjg@46: * This code is distributed in the hope that it will be useful, but WITHOUT jjg@46: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jjg@46: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jjg@46: * version 2 for more details (a copy is included in the LICENSE file that jjg@46: * accompanied this code). jjg@46: * jjg@46: * You should have received a copy of the GNU General Public License version jjg@46: * 2 along with this work; if not, write to the Free Software Foundation, jjg@46: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jjg@46: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. jjg@46: */ jjg@46: jjg@46: package com.sun.tools.classfile; jjg@46: jjg@345: import java.io.DataOutputStream; jjg@46: import java.io.IOException; jjg@345: import java.io.OutputStream; jjg@282: import java.util.Iterator; jjg@46: jjg@46: /** jjh@972: * See JVMS, section 4.5. jjg@46: * jjg@581: *

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