jjg@46: /* xdono@229: * Copyright 2007-2009 Sun Microsystems, Inc. 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 jjg@46: * published by the Free Software Foundation. Sun designates this jjg@46: * particular file as subject to the "Classpath" exception as provided jjg@46: * by Sun 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: * jjg@46: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, jjg@46: * CA 95054 USA or visit www.sun.com if you need additional information or jjg@46: * have any questions. jjg@46: */ jjg@46: jjg@46: package com.sun.tools.classfile; jjg@46: jjg@46: import java.io.IOException; jjg@282: import java.util.Iterator; jjg@46: jjg@46: /** jjg@46: * See JVMS3, section 4.5. jjg@46: * jjg@46: *

This is NOT part of any API supported by Sun Microsystems. If jjg@46: * 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@46: public 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@46: public 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@46: public 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@46: public 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; 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: jjg@46: case CONSTANT_Long: jjg@46: pool[i] = new CONSTANT_Long_info(cr); jjg@46: i++; jjg@46: break; jjg@46: 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@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); 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); 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@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@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@46: public String getName() throws ConstantPoolException { jjg@46: return cp.getUTF8Value(name_index); jjg@46: } jjg@46: jjg@281: public String getBaseName() throws ConstantPoolException { jjg@281: String name = getName(); jjg@281: int index = name.indexOf("[L") + 1; jjg@281: return name.substring(index); 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@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@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@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: 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@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: 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@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@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@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@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@46: @Override jjg@46: public String toString() { jjg@46: return "CONSTANT_Utf8_info[value: " + value + "]"; 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: jjg@46: }