/* * Copyright (c) 2007, 2012, 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. * * 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.max.vm.classfile.constant; import static com.sun.max.vm.classfile.ErrorContext.*; import static com.sun.max.vm.classfile.constant.ConstantPool.Tag.*; import java.io.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.classfile.constant.ConstantPool.Tag; import com.sun.max.vm.type.*; /** * Constant pool constants, see #4.4. * * Each constant type defined by one of the {@linkplain Tag tags} in <a * href="http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#87125">Table 4.3</a> is represented * by a subclass of {@code PoolConstant}. There is exactly one subclass representing the final or resolved version of a * constant type. For some constant types, there are one or more additional subclasses representing unresolved * version(s) of the constant. The process of resolving a constant will always result with relevant constant pool slot * being updated with the resolved version. That is, the constant pool will never be * {@linkplain ConstantPool#updateAt(int, ResolvableConstant) updated} with an unresolved version of a constant. */ public interface PoolConstant<PoolConstant_Type extends PoolConstant<PoolConstant_Type>> { Tag tag(); PoolConstantKey<PoolConstant_Type> key(ConstantPool pool); /** * Gets a string description of this constant that uses a given pool reference to construct a more human readable * form of constants that cross-reference other pool constants. */ String toString(ConstantPool pool); /** * Gets a string description of the value denoted by this constant that uses a given pool reference to construct a * more human readable form of values for constants that cross-reference other pool constants. * * @param pool * a constant pool that can be used to get human readable strings for other pool constants * referenced by this constant. This parameter may be null. */ String valueString(ConstantPool pool); /** * Gets a string description of this constant. This version may not be so human * readable in the case of a constant that refers to other constants via unresolved * constant pool indexes. * * @see #toString(ConstantPool) */ String toString(); public static final class Static { private Static() { } public static String toString(PoolConstant poolConstant, ConstantPool pool) { String name = poolConstant.getClass().getName(); name = name.substring(name.lastIndexOf('.') + 1); // strip the package name return "<" + name + "[" + poolConstant.valueString(pool) + "]>"; } /** * Gets the constant pool index of a method or field's holder. * * @param memberRef a field or method reference * @return the index of {@code memberRef}'s holder entry in the same constant pool * or -1 if the index is not available */ public static int holderIndex(MemberRefConstant memberRef) { if (memberRef instanceof UnresolvedRefIndices) { UnresolvedRefIndices indices = (UnresolvedRefIndices) memberRef; return indices.classIndex; } return -1; } } /** * Writes myself to a class file stream. * This may cause extra entries to be added to the pool. * * @param stream stream to write to * @param editor constant pool editor currently writing * @param index index of ourselves in the editors pool */ void writeOn(DataOutputStream stream, ConstantPoolEditor editor, int index) throws IOException; } //The rest of this file contains package-private abstract classes that provide most of the implementation //for the pool constant interfaces. /** * An abstract class that implements some of the functionality of a method or field entry in a constant pool * that is in a completely unresolved state. That is, the references to the holder, name and signature of * the field or method are indices to other constant pool entries. */ abstract class UnresolvedRefIndices<PoolConstant_Type extends PoolConstant<PoolConstant_Type>> extends AbstractMemberRefConstant<PoolConstant_Type> { public final int classIndex; public final int nameAndTypeIndex; UnresolvedRefIndices(int classIndex, int nameAndTypeIndex, Tag[] tags) { this.classIndex = classIndex; this.nameAndTypeIndex = nameAndTypeIndex; if (tags[classIndex] != CLASS) { throw ConstantPool.unexpectedEntry(classIndex, tags[classIndex], "defining class of field/method", CLASS); } if (tags[nameAndTypeIndex] != NAME_AND_TYPE) { throw ConstantPool.unexpectedEntry(nameAndTypeIndex, tags[nameAndTypeIndex], "field/method name and type", NAME_AND_TYPE); } } public final TypeDescriptor holder(ConstantPool pool) { final ClassConstant classRef = pool.classAt(classIndex); return classRef.typeDescriptor(); } public final Utf8Constant name(ConstantPool pool) { return nameAndType(pool).name(); } public final Descriptor descriptor(ConstantPool pool) { return nameAndType(pool).descriptor(); } public final SignatureDescriptor signature(ConstantPool pool) { return nameAndType(pool).signature(); } public final TypeDescriptor type(ConstantPool pool) { return nameAndType(pool).type(); } public boolean isResolved() { return false; } @Override public final boolean isResolvableWithoutClassLoading(ConstantPool pool) { if (!pool.classAt(classIndex).isResolvableWithoutClassLoading(pool)) { return false; } if (isFieldConstant()) { return type(pool).isResolvableWithoutClassLoading(pool.classLoader()); } else { SignatureDescriptor signature = signature(pool); for (int i = 0; i < signature.numberOfParameters(); i++) { if (!signature.parameterDescriptorAt(i).isResolvableWithoutClassLoading(pool.classLoader())) { return false; } } return signature.resultDescriptor().isResolvableWithoutClassLoading(pool.classLoader()); } } final NameAndTypeConstant nameAndType(ConstantPool pool) { return pool.nameAndTypeAt(nameAndTypeIndex); } abstract boolean isFieldConstant(); public final String valueString(ConstantPool pool) { if (pool == null) { return "classIndex=" + classIndex + ",nameAndTypeIndex=" + nameAndTypeIndex; } if (isFieldConstant()) { return holder(pool).toJavaString(true) + '.' + name(pool) + ':' + type(pool).toJavaString(false); } final SignatureDescriptor signature = signature(pool); return holder(pool).toJavaString(true) + "." + name(pool) + signature.toJavaString(false, false) + ":" + signature.resultDescriptor().toJavaString(false); } } abstract class RefKey { final TypeDescriptor holder; final Utf8Constant name; RefKey(ConstantPool pool, UnresolvedRefIndices unresolvedRef) { holder = unresolvedRef.holder(pool); name = unresolvedRef.name(pool); } public final TypeDescriptor holder() { return holder; } public final Utf8Constant name() { return name; } @Override public abstract boolean equals(Object other); @Override public abstract int hashCode(); } /** * An abstract class that implements some of the functionality of a method or field entry in a constant pool that is in * a partially resolved state. That is, the references to the holder, name and signature of the field or method are * objects of type {@link ClassActor}, {@link Utf8Constant} and {@link Descriptor} respectively. That is, they are not * indices to other constant pool entries and as such, this class (and it subclasses) are useful for constructing pool * constants that don't rely on the existence of extra pool constants. */ abstract class UnresolvedRef<PoolConstant_Type extends PoolConstant<PoolConstant_Type>> extends AbstractMemberRefConstant<PoolConstant_Type> { final ClassActor holder; final Utf8Constant name; final Descriptor descriptor; public UnresolvedRef(ClassActor holder, Utf8Constant name, Descriptor descriptor) { this.holder = holder; this.name = name; this.descriptor = descriptor; } public final TypeDescriptor holder(ConstantPool pool) { return holder(); } public final Utf8Constant name(ConstantPool pool) { return name(); } public final Descriptor descriptor(ConstantPool pool) { return descriptor; } public TypeDescriptor holder() { return holder.typeDescriptor; } public Utf8Constant name() { return name; } public final boolean isResolvableWithoutClassLoading(ConstantPool pool) { return true; } public final boolean isResolved() { return false; } public final SignatureDescriptor signature(ConstantPool pool) { return signature(); } public final SignatureDescriptor signature() { try { return (SignatureDescriptor) descriptor; } catch (ClassCastException e) { throw classFormatError(descriptor + " is not a valid method signature descriptor"); } } public final TypeDescriptor type(ConstantPool pool) { return type(); } public final TypeDescriptor type() { try { return (TypeDescriptor) descriptor; } catch (ClassCastException e) { throw classFormatError(descriptor + " is not a valid field type descriptor"); } } abstract boolean isFieldConstant(); public final String valueString(ConstantPool pool) { if (isFieldConstant()) { return holder().toJavaString(true) + '.' + name() + ':' + type().toJavaString(false); } return holder().toJavaString(true) + '.' + name() + signature().toJavaString(false, false) + '.' + signature().resultDescriptor().toJavaString(false); } }