All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.javaflow.spi.ClassHeaderReader Maven / Gradle / Ivy

There is a newer version: 2.7.8
Show newest version
// ASM: a very small and fast Java bytecode manipulation framework
// Copyright (c) 2000-2011 INRIA, France Telecom
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
//    contributors may be used to endorse or promote products derived from
//    this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
package org.apache.commons.javaflow.spi;

/**
 * Class header reader -- like class name, superclass, interfaces. Based on an
 * OW2 ASM ClassReadercthat reads class structure, as defined in the Java
 * Virtual Machine Specification (JVMS). encountered.
 *
 * @see JVMS
 *      4
 * @author Eric Bruneton
 * @author Eugene Kuleshov
 */
class ClassHeaderReader {
    /**
     * A byte array containing the JVMS ClassFile structure to be parsed. The
     * content of this array must not be modified. This field is intended for
     * Attribute sub classes, and is normally not needed by class
     * visitors.
     *
     * 

* NOTE: the ClassFile structure can start at any offset within this array, i.e. * it does not necessarily start at offset 0. Use {@link #getItem} and * {@link #header} to get correct ClassFile element offsets within this byte * array. */ // DontCheck(MemberName): can't be renamed (for backward binary compatibility). private final byte[] b; /** * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's * constant_pool array, plus one. In other words, the offset of constant * pool entry i is given by cpInfoOffsets[i] - 1, i.e. its cp_info's tag field * is given by b[cpInfoOffsets[i] - 1]. */ private final int[] cpInfoOffsets; /** * The String objects corresponding to the CONSTANT_Utf8 constant pool items. * This cache avoids multiple parsing of a given CONSTANT_Utf8 constant pool * item. */ private final String[] constantUtf8Values; /** * A conservative estimate of the maximum length of the strings contained in the * constant pool of the class. */ private final int maxStringLength; /** * The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. */ private final int header; // ----------------------------------------------------------------------------------------------- // Constructors // ----------------------------------------------------------------------------------------------- /** * Constructs a new {@link ClassHeaderReader} object. * * @param classFile * the JVMS ClassFile structure to be read. */ ClassHeaderReader(final byte[] classFile) { this(classFile, 0); } /** * Constructs a new {@link ClassHeaderReader} object. This internal constructor * must not be exposed as a public API. * * @param classFileBuffer * a byte array containing the JVMS ClassFile structure to be read. * @param classFileOffset * the offset in byteBuffer of the first byte of the ClassFile to be * read. * @param checkClassVersion * whether to check the class version or not. */ private ClassHeaderReader(final byte[] classFileBuffer, final int classFileOffset) { b = classFileBuffer; /* int V18 = 0 << 16 | 62; // Check the class' major_version. This field is after the magic and // minor_version fields, which // use 4 and 2 bytes respectively. if (checkClassVersion && readShort(classFileOffset + 6) > V18) { throw new IllegalArgumentException( "Unsupported class file major version " + readShort(classFileOffset + 6)); } */ // Create the constant pool arrays. The constant_pool_count field is after the // magic, // minor_version and major_version fields, which use 4, 2 and 2 bytes // respectively. int constantPoolCount = readUnsignedShort(classFileOffset + 8); cpInfoOffsets = new int[constantPoolCount]; constantUtf8Values = new String[constantPoolCount]; // Compute the offset of each constant pool entry, as well as a conservative // estimate of the // maximum length of the constant pool strings. The first constant pool entry is // after the // magic, minor_version, major_version and constant_pool_count fields, which use // 4, 2, 2 and 2 // bytes respectively. int currentCpInfoIndex = 1; int currentCpInfoOffset = classFileOffset + 10; int currentMaxStringLength = 0; @SuppressWarnings("unused") boolean hasConstantDynamic = false; // The offset of the other entries depend on the total size of all the // previous entries. @SuppressWarnings("unused") boolean hasBootstrapMethods = false; while (currentCpInfoIndex < constantPoolCount) { cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; int cpInfoSize; switch (classFileBuffer[currentCpInfoOffset]) { case Symbol.CONSTANT_FIELDREF_TAG: case Symbol.CONSTANT_METHODREF_TAG: case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: case Symbol.CONSTANT_INTEGER_TAG: case Symbol.CONSTANT_FLOAT_TAG: case Symbol.CONSTANT_NAME_AND_TYPE_TAG: cpInfoSize = 5; break; case Symbol.CONSTANT_DYNAMIC_TAG: cpInfoSize = 5; hasBootstrapMethods = true; hasConstantDynamic = true; break; case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: cpInfoSize = 5; hasBootstrapMethods = true; break; case Symbol.CONSTANT_LONG_TAG: case Symbol.CONSTANT_DOUBLE_TAG: cpInfoSize = 9; currentCpInfoIndex++; break; case Symbol.CONSTANT_UTF8_TAG: cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); if (cpInfoSize > currentMaxStringLength) { // The size in bytes of this CONSTANT_Utf8 structure provides a conservative // estimate // of the length in characters of the corresponding string, and is much cheaper // to // compute than this exact length. currentMaxStringLength = cpInfoSize; } break; case Symbol.CONSTANT_METHOD_HANDLE_TAG: cpInfoSize = 4; break; case Symbol.CONSTANT_CLASS_TAG: case Symbol.CONSTANT_STRING_TAG: case Symbol.CONSTANT_METHOD_TYPE_TAG: case Symbol.CONSTANT_PACKAGE_TAG: case Symbol.CONSTANT_MODULE_TAG: cpInfoSize = 3; break; default: throw new IllegalArgumentException(); } currentCpInfoOffset += cpInfoSize; } maxStringLength = currentMaxStringLength; // The Classfile's access_flags field is just after the last constant pool // entry. header = currentCpInfoOffset; } // ----------------------------------------------------------------------------------------------- // Accessors // ----------------------------------------------------------------------------------------------- /** * Returns the internal name of the class. * * @return the internal class name. */ String getClassName() { // this_class is just after the access_flags field (using 2 bytes). return readClass(header + 2, new char[maxStringLength]); } /** * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For * interfaces, the super class is {@link Object}. * * @return the internal name of the super class, or {@literal null} for {@link Object} class. * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ String getSuperName() { // super_class is after the access_flags and this_class fields (2 bytes each). return readClass(header + 4, new char[maxStringLength]); } /** * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). * * @return the internal names of the directly implemented interfaces. Inherited implemented * interfaces are not returned. * @see ClassVisitor#visit(int, int, String, String, String, String[]) */ String[] getInterfaces() { // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). int currentOffset = header + 6; int interfacesCount = readUnsignedShort(currentOffset); String[] interfaces = new String[interfacesCount]; if (interfacesCount > 0) { char[] charBuffer = new char[maxStringLength]; for (int i = 0; i < interfacesCount; ++i) { currentOffset += 2; interfaces[i] = readClass(currentOffset, charBuffer); } } return interfaces; } // ----------------------------------------------------------------------------------------------- // Public methods // ----------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------- // Utility methods: low level parsing // ----------------------------------------------------------------------------------------------- /** * Reads an unsigned short value in {@link #b}. This method is intended for * Attribute sub classes, and is normally not needed by class generators * or adapters. * * @param offset * the start index of the value to be read in {@link #b}. * @return the read value. */ private int readUnsignedShort(final int offset) { byte[] classFileBuffer = b; return ((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF); } /** * Reads a signed short value in {@link #b}. This method is intended for * Attribute sub classes, and is normally not needed by class generators * or adapters. * * @param offset * the start offset of the value to be read in {@link #b}. * @return the read value. */ @SuppressWarnings("unused") private short readShort(final int offset) { byte[] classFileBuffer = b; return (short) (((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF)); } /** * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. This method is * intended for Attribute sub classes, and is normally not needed by * class generators or adapters. * * @param offset * the start offset of an unsigned short value in {@link #b}, whose * value is the index of a CONSTANT_Utf8 entry in the class's * constant pool table. * @param charBuffer * the buffer to be used to read the string. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified CONSTANT_Utf8 entry. */ // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary // compatibility). private String readUTF8(final int offset, final char[] charBuffer) { int constantPoolEntryIndex = readUnsignedShort(offset); if (offset == 0 || constantPoolEntryIndex == 0) { return null; } return readUtf(constantPoolEntryIndex, charBuffer); } /** * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. * * @param constantPoolEntryIndex * the index of a CONSTANT_Utf8 entry in the class's constant pool * table. * @param charBuffer * the buffer to be used to read the string. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified CONSTANT_Utf8 entry. */ final private String readUtf(final int constantPoolEntryIndex, final char[] charBuffer) { String value = constantUtf8Values[constantPoolEntryIndex]; if (value != null) { return value; } int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; return constantUtf8Values[constantPoolEntryIndex] = readUtf(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); } /** * Reads an UTF8 string in {@link #b}. * * @param utfOffset * the start offset of the UTF8 string to be read. * @param utfLength * the length of the UTF8 string to be read. * @param charBuffer * the buffer to be used to read the string. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified UTF8 string. */ private String readUtf(final int utfOffset, final int utfLength, final char[] charBuffer) { int currentOffset = utfOffset; int endOffset = currentOffset + utfLength; int strLength = 0; byte[] classFileBuffer = b; while (currentOffset < endOffset) { int currentByte = classFileBuffer[currentOffset++]; if ((currentByte & 0x80) == 0) { charBuffer[strLength++] = (char) (currentByte & 0x7F); } else if ((currentByte & 0xE0) == 0xC0) { charBuffer[strLength++] = (char) (((currentByte & 0x1F) << 6) + (classFileBuffer[currentOffset++] & 0x3F)); } else { charBuffer[strLength++] = (char) (((currentByte & 0xF) << 12) + ((classFileBuffer[currentOffset++] & 0x3F) << 6) + (classFileBuffer[currentOffset++] & 0x3F)); } } return new String(charBuffer, 0, strLength); } /** * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module * or CONSTANT_Package constant pool entry in {@link #b}. This method is * intended for Attribute sub classes, and is normally not needed by * class generators or adapters. * * @param offset * the start offset of an unsigned short value in {@link #b}, whose * value is the index of a CONSTANT_Class, CONSTANT_String, * CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package entry in * class's constant pool table. * @param charBuffer * the buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified constant pool entry. */ private String readStringish(final int offset, final char[] charBuffer) { // Get the start offset of the cp_info structure (plus one), and read the // CONSTANT_Utf8 entry // designated by the first two bytes of this cp_info. return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); } /** * Reads a CONSTANT_Class constant pool entry in {@link #b}. This method is * intended for Attribute sub classes, and is normally not needed by * class generators or adapters. * * @param offset * the start offset of an unsigned short value in {@link #b}, whose * value is the index of a CONSTANT_Class entry in class's constant * pool table. * @param charBuffer * the buffer to be used to read the item. This buffer must be * sufficiently large. It is not automatically resized. * @return the String corresponding to the specified CONSTANT_Class entry. */ private String readClass(final int offset, final char[] charBuffer) { return readStringish(offset, charBuffer); } private static class Symbol { // Tag values for the constant pool entries (using the same order as in the // JVMS). /** The tag value of CONSTANT_Class_info JVMS structures. */ static final int CONSTANT_CLASS_TAG = 7; /** The tag value of CONSTANT_Fieldref_info JVMS structures. */ static final int CONSTANT_FIELDREF_TAG = 9; /** The tag value of CONSTANT_Methodref_info JVMS structures. */ static final int CONSTANT_METHODREF_TAG = 10; /** The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. */ static final int CONSTANT_INTERFACE_METHODREF_TAG = 11; /** The tag value of CONSTANT_String_info JVMS structures. */ static final int CONSTANT_STRING_TAG = 8; /** The tag value of CONSTANT_Integer_info JVMS structures. */ static final int CONSTANT_INTEGER_TAG = 3; /** The tag value of CONSTANT_Float_info JVMS structures. */ static final int CONSTANT_FLOAT_TAG = 4; /** The tag value of CONSTANT_Long_info JVMS structures. */ static final int CONSTANT_LONG_TAG = 5; /** The tag value of CONSTANT_Double_info JVMS structures. */ static final int CONSTANT_DOUBLE_TAG = 6; /** The tag value of CONSTANT_NameAndType_info JVMS structures. */ static final int CONSTANT_NAME_AND_TYPE_TAG = 12; /** The tag value of CONSTANT_Utf8_info JVMS structures. */ static final int CONSTANT_UTF8_TAG = 1; /** The tag value of CONSTANT_MethodHandle_info JVMS structures. */ static final int CONSTANT_METHOD_HANDLE_TAG = 15; /** The tag value of CONSTANT_MethodType_info JVMS structures. */ static final int CONSTANT_METHOD_TYPE_TAG = 16; /** The tag value of CONSTANT_Dynamic_info JVMS structures. */ static final int CONSTANT_DYNAMIC_TAG = 17; /** The tag value of CONSTANT_InvokeDynamic_info JVMS structures. */ static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18; /** The tag value of CONSTANT_Module_info JVMS structures. */ static final int CONSTANT_MODULE_TAG = 19; /** The tag value of CONSTANT_Package_info JVMS structures. */ static final int CONSTANT_PACKAGE_TAG = 20; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy