Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide whitespace changes
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Text styles
Change appearance
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
appendDecriptor
Created
6 years ago
Diff never expires
Clear
Export
Share
Explain
45 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
678 lines
Copy
39 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
671 lines
Copy
// ASM: a very small and fast Java bytecode manipulation framework
// ASM: a very small and fast Java bytecode manipulation framework
// Copyright (c) 2000-2011 INRIA, France Telecom
// Copyright (c) 2000-2011 INRIA, France Telecom
// All rights reserved.
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// modification, are permitted provided that the following conditions
// are met:
// are met:
// 1. Redistributions of source code must retain the above copyright
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
// 3. Neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// this software without specific prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
// THE POSSIBILITY OF SUCH DAMAGE.
package org.objectweb.asm;
package org.objectweb.asm;
import java.lang.reflect.Constructor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Method;
/**
/**
* A Java field or method type. This class can be used to make it easier to manipulate type and
* A Java field or method type. This class can be used to make it easier to manipulate type and
* method descriptors.
* method descriptors.
*
*
* @author Eric Bruneton
* @author Eric Bruneton
* @author Chris Nokleberg
* @author Chris Nokleberg
*/
*/
public final class Type {
public final class Type {
/** The sort of the {@code void} type. See {@link #getSort}. */
/** The sort of the {@code void} type. See {@link #getSort}. */
public static final int VOID = 0;
public static final int VOID = 0;
/** The sort of the {@code boolean} type. See {@link #getSort}. */
/** The sort of the {@code boolean} type. See {@link #getSort}. */
public static final int BOOLEAN = 1;
public static final int BOOLEAN = 1;
/** The sort of the {@code char} type. See {@link #getSort}. */
/** The sort of the {@code char} type. See {@link #getSort}. */
public static final int CHAR = 2;
public static final int CHAR = 2;
/** The sort of the {@code byte} type. See {@link #getSort}. */
/** The sort of the {@code byte} type. See {@link #getSort}. */
public static final int BYTE = 3;
public static final int BYTE = 3;
/** The sort of the {@code short} type. See {@link #getSort}. */
/** The sort of the {@code short} type. See {@link #getSort}. */
public static final int SHORT = 4;
public static final int SHORT = 4;
/** The sort of the {@code int} type. See {@link #getSort}. */
/** The sort of the {@code int} type. See {@link #getSort}. */
public static final int INT = 5;
public static final int INT = 5;
/** The sort of the {@code float} type. See {@link #getSort}. */
/** The sort of the {@code float} type. See {@link #getSort}. */
public static final int FLOAT = 6;
public static final int FLOAT = 6;
/** The sort of the {@code long} type. See {@link #getSort}. */
/** The sort of the {@code long} type. See {@link #getSort}. */
public static final int LONG = 7;
public static final int LONG = 7;
/** The sort of the {@code double} type. See {@link #getSort}. */
/** The sort of the {@code double} type. See {@link #getSort}. */
public static final int DOUBLE = 8;
public static final int DOUBLE = 8;
/** The sort of array reference types. See {@link #getSort}. */
/** The sort of array reference types. See {@link #getSort}. */
public static final int ARRAY = 9;
public static final int ARRAY = 9;
/** The sort of object reference types. See {@link #getSort}. */
/** The sort of object reference types. See {@link #getSort}. */
public static final int OBJECT = 10;
public static final int OBJECT = 10;
/** The sort of method types. See {@link #getSort}. */
/** The sort of method types. See {@link #getSort}. */
public static final int METHOD = 11;
public static final int METHOD = 11;
/** The (private) sort of object reference types represented with an internal name. */
/** The (private) sort of object reference types represented with an internal name. */
private static final int INTERNAL = 12;
private static final int INTERNAL = 12;
/** The descriptors of the primitive types. */
/** The descriptors of the primitive types. */
private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD";
private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD";
/** The {@code void} type. */
/** The {@code void} type. */
public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1);
public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1);
/** The {@code boolean} type. */
/** The {@code boolean} type. */
public static final Type BOOLEAN_TYPE =
public static final Type BOOLEAN_TYPE =
new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1);
new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1);
/** The {@code char} type. */
/** The {@code char} type. */
public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1);
public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1);
/** The {@code byte} type. */
/** The {@code byte} type. */
public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1);
public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1);
/** The {@code short} type. */
/** The {@code short} type. */
public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1);
public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1);
/** The {@code int} type. */
/** The {@code int} type. */
public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1);
public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1);
/** The {@code float} type. */
/** The {@code float} type. */
public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1);
public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1);
/** The {@code long} type. */
/** The {@code long} type. */
public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1);
public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1);
/** The {@code double} type. */
/** The {@code double} type. */
public static final Type DOUBLE_TYPE =
public static final Type DOUBLE_TYPE =
new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1);
new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1);
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Fields
// Fields
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
/**
* The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE},
* The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE},
* {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY},
* {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY},
* {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}.
* {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}.
*/
*/
private final int sort;
private final int sort;
/**
/**
* A buffer containing the value of this field or method type. This value is an internal name for
* A buffer containing the value of this field or method type. This value is an internal name for
* {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other
* {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other
* cases.
* cases.
*
*
* <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in
* <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in
* [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link
* [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link
* #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor.
* #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor.
*/
*/
private final String valueBuffer;
private final String valueBuffer;
/**
/**
* The beginning index, inclusive, of the value of this Java field or method type in {@link
* The beginning index, inclusive, of the value of this Java field or method type in {@link
* #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
* #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
* and a field or method descriptor in the other cases.
* and a field or method descriptor in the other cases.
*/
*/
private final int valueBegin;
private final int valueBegin;
/**
/**
* The end index, exclusive, of the value of this Java field or method type in {@link
* The end index, exclusive, of the value of this Java field or method type in {@link
* #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
* #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types,
* and a field or method descriptor in the other cases.
* and a field or method descriptor in the other cases.
*/
*/
private final int valueEnd;
private final int valueEnd;
/**
/**
* Constructs a reference type.
* Constructs a reference type.
*
*
* @param sort the sort of this type, see {@link #sort}.
* @param sort the sort of this type, see {@link #sort}.
* @param valueBuffer a buffer containing the value of this field or method type.
* @param valueBuffer a buffer containing the value of this field or method type.
* @param valueBegin the beginning index, inclusive, of the value of this field or method type in
* @param valueBegin the beginning index, inclusive, of the value of this field or method type in
* valueBuffer.
* valueBuffer.
* @param valueEnd the end index, exclusive, of the value of this field or method type in
* @param valueEnd the end index, exclusive, of the value of this field or method type in
* valueBuffer.
* valueBuffer.
*/
*/
private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) {
private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) {
this.sort = sort;
this.sort = sort;
this.valueBuffer = valueBuffer;
this.valueBuffer = valueBuffer;
this.valueBegin = valueBegin;
this.valueBegin = valueBegin;
this.valueEnd = valueEnd;
this.valueEnd = valueEnd;
}
}
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc.
// Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc.
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
/**
* Returns the {@link Type} corresponding to the given type descriptor.
* Returns the {@link Type} corresponding to the given type descriptor.
*
*
* @param typeDescriptor a field or method type descriptor.
* @param typeDescriptor a field or method type descriptor.
* @return the {@link Type} corresponding to the given type descriptor.
* @return the {@link Type} corresponding to the given type descriptor.
*/
*/
public static Type getType(final String typeDescriptor) {
public static Type getType(final String typeDescriptor) {
return getTypeInternal(typeDescriptor, 0, typeDescriptor.length());
return getTypeInternal(typeDescriptor, 0, typeDescriptor.length());
}
}
/**
/**
* Returns the {@link Type} corresponding to the given class.
* Returns the {@link Type} corresponding to the given class.
*
*
* @param clazz a class.
* @param clazz a class.
* @return the {@link Type} corresponding to the given class.
* @return the {@link Type} corresponding to the given class.
*/
*/
public static Type getType(final Class<?> clazz) {
public static Type getType(final Class<?> clazz) {
if (clazz.isPrimitive()) {
if (clazz.isPrimitive()) {
if (clazz == Integer.TYPE) {
if (clazz == Integer.TYPE) {
return INT_TYPE;
return INT_TYPE;
} else if (clazz == Void.TYPE) {
} else if (clazz == Void.TYPE) {
return VOID_TYPE;
return VOID_TYPE;
} else if (clazz == Boolean.TYPE) {
} else if (clazz == Boolean.TYPE) {
return BOOLEAN_TYPE;
return BOOLEAN_TYPE;
} else if (clazz == Byte.TYPE) {
} else if (clazz == Byte.TYPE) {
return BYTE_TYPE;
return BYTE_TYPE;
} else if (clazz == Character.TYPE) {
} else if (clazz == Character.TYPE) {
return CHAR_TYPE;
return CHAR_TYPE;
} else if (clazz == Short.TYPE) {
} else if (clazz == Short.TYPE) {
return SHORT_TYPE;
return SHORT_TYPE;
} else if (clazz == Double.TYPE) {
} else if (clazz == Double.TYPE) {
return DOUBLE_TYPE;
return DOUBLE_TYPE;
} else if (clazz == Float.TYPE) {
} else if (clazz == Float.TYPE) {
return FLOAT_TYPE;
return FLOAT_TYPE;
} else if (clazz == Long.TYPE) {
} else if (clazz == Long.TYPE) {
return LONG_TYPE;
return LONG_TYPE;
} else {
} else {
throw new AssertionError();
throw new AssertionError();
}
}
} else {
} else {
return getType(getDescriptor(clazz));
return getType(getDescriptor(clazz));
}
}
}
}
/**
/**
* Returns the method {@link Type} corresponding to the given constructor.
* Returns the method {@link Type} corresponding to the given constructor.
*
*
* @param constructor a {@link Constructor} object.
* @param constructor a {@link Constructor} object.
* @return the method {@link Type} corresponding to the given constructor.
* @return the method {@link Type} corresponding to the given constructor.
*/
*/
public static Type getType(final Constructor<?> constructor) {
public static Type getType(final Constructor<?> constructor) {
return getType(getConstructorDescriptor(constructor));
return getType(getConstructorDescriptor(constructor));
}
}
/**
/**
* Returns the method {@link Type} corresponding to the given method.
* Returns the method {@link Type} corresponding to the given method.
*
*
* @param method a {@link Method} object.
* @param method a {@link Method} object.
* @return the method {@link Type} corresponding to the given method.
* @return the method {@link Type} corresponding to the given method.
*/
*/
public static Type getType(final Method method) {
public static Type getType(final Method method) {
return getType(getMethodDescriptor(method));
return getType(getMethodDescriptor(method));
}
}
/**
/**
* Returns the type of the elements of this array type. This method should only be used for an
* Returns the type of the elements of this array type. This method should only be used for an
* array type.
* array type.
*
*
* @return Returns the type of the elements of this array type.
* @return Returns the type of the elements of this array type.
*/
*/
public Type getElementType() {
public Type getElementType() {
final int numDimensions = getDimensions();
final int numDimensions = getDimensions();
return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd);
return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd);
}
}
/**
/**
* Returns the {@link Type} corresponding to the given internal name.
* Returns the {@link Type} corresponding to the given internal name.
*
*
* @param internalName an internal name.
* @param internalName an internal name.
* @return the {@link Type} corresponding to the given internal name.
* @return the {@link Type} corresponding to the given internal name.
*/
*/
public static Type getObjectType(final String internalName) {
public static Type getObjectType(final String internalName) {
return new Type(
return new Type(
internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length());
}
}
/**
/**
* Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
* Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code>
* Type.getType(methodDescriptor)</code>.
* Type.getType(methodDescriptor)</code>.
*
*
* @param methodDescriptor a method descriptor.
* @param methodDescriptor a method descriptor.
* @return the {@link Type} corresponding to the given method descriptor.
* @return the {@link Type} corresponding to the given method descriptor.
*/
*/
public static Type getMethodType(final String methodDescriptor) {
public static Type getMethodType(final String methodDescriptor) {
return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length());
}
}
/**
/**
* Returns the method {@link Type} corresponding to the given argument and return types.
* Returns the method {@link Type} corresponding to the given argument and return types.
*
*
* @param returnType the return type of the method.
* @param returnType the return type of the method.
* @param argumentTypes the argument types of the method.
* @param argumentTypes the argument types of the method.
* @return the method {@link Type} corresponding to the given argument and return types.
* @return the method {@link Type} corresponding to the given argument and return types.
*/
*/
public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
return getType(getMethodDescriptor(returnType, argumentTypes));
return getType(getMethodDescriptor(returnType, argumentTypes));
}
}
/**
/**
* Returns the argument types of methods of this type. This method should only be used for method
* Returns the argument types of methods of this type. This method should only be used for method
* types.
* types.
*
*
* @return the argument types of methods of this type.
* @return the argument types of methods of this type.
*/
*/
public Type[] getArgumentTypes() {
public Type[] getArgumentTypes() {
return getArgumentTypes(getDescriptor());
return getArgumentTypes(getDescriptor());
}
}
/**
/**
* Returns the {@link Type} values corresponding to the argument types of the given method
* Returns the {@link Type} values corresponding to the argument types of the given method
* descriptor.
* descriptor.
*
*
* @param methodDescriptor a method descriptor.
* @param methodDescriptor a method descriptor.
* @return the {@link Type} values corresponding to the argument types of the given method
* @return the {@link Type} values corresponding to the argument types of the given method
* descriptor.
* descriptor.
*/
*/
public static Type[] getArgumentTypes(final String methodDescriptor) {
public static Type[] getArgumentTypes(final String methodDescriptor) {
// First step: compute the number of argument types in methodDescriptor.
// First step: compute the number of argument types in methodDescriptor.
int numArgumentTypes = 0;
int numArgumentTypes = 0;
// Skip the first character, which is always a '('.
// Skip the first character, which is always a '('.
int currentOffset = 1;
int currentOffset = 1;
// Parse the argument types, one at a each loop iteration.
// Parse the argument types, one at a each loop iteration.
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) == '[') {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
currentOffset++;
}
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
// Skip the argument descriptor content.
Copy
Copied
Copy
Copied
currentOffset
= methodDescriptor.indexOf(';', currentOffset)
+ 1
;
int semiColumnOffset
= methodDescriptor.indexOf(';', currentOffset)
;
currentOffset = Math.max(currentOffset, semiColumnOffset
+ 1
)
;
}
}
++numArgumentTypes;
++numArgumentTypes;
}
}
// Second step: create a Type instance for each argument type.
// Second step: create a Type instance for each argument type.
Type[] argumentTypes = new Type[numArgumentTypes];
Type[] argumentTypes = new Type[numArgumentTypes];
// Skip the first character, which is always a '('.
// Skip the first character, which is always a '('.
currentOffset = 1;
currentOffset = 1;
// Parse and create the argument types, one at each loop iteration.
// Parse and create the argument types, one at each loop iteration.
int currentArgumentTypeIndex = 0;
int currentArgumentTypeIndex = 0;
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) != ')') {
final int currentArgumentTypeOffset = currentOffset;
final int currentArgumentTypeOffset = currentOffset;
while (methodDescriptor.charAt(currentOffset) == '[') {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
currentOffset++;
}
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
// Skip the argument descriptor content.
Copy
Copied
Copy
Copied
currentOffset
= methodDescriptor.indexOf(';', currentOffset)
+ 1
;
int semiColumnOffset
= methodDescriptor.indexOf(';', currentOffset)
;
currentOffset = Math.max(currentOffset, semiColumnOffset
+ 1
)
;
}
}
argumentTypes[currentArgumentTypeIndex++] =
argumentTypes[currentArgumentTypeIndex++] =
getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
}
}
return argumentTypes;
return argumentTypes;
}
}
/**
/**
* Returns the {@link Type} values corresponding to the argument types of the given method.
* Returns the {@link Type} values corresponding to the argument types of the given method.
*
*
* @param method a method.
* @param method a method.
* @return the {@link Type} values corresponding to the argument types of the given method.
* @return the {@link Type} values corresponding to the argument types of the given method.
*/
*/
public static Type[] getArgumentTypes(final Method method) {
public static Type[] getArgumentTypes(final Method method) {
Class<?>[] classes = method.getParameterTypes();
Class<?>[] classes = method.getParameterTypes();
Type[] types = new Type[classes.length];
Type[] types = new Type[classes.length];
for (int i = classes.length - 1; i >= 0; --i) {
for (int i = classes.length - 1; i >= 0; --i) {
types[i] = getType(classes[i]);
types[i] = getType(classes[i]);
}
}
return types;
return types;
}
}
/**
/**
* Returns the return type of methods of this type. This method should only be used for method
* Returns the return type of methods of this type. This method should only be used for method
* types.
* types.
*
*
* @return the return type of methods of this type.
* @return the return type of methods of this type.
*/
*/
public Type getReturnType() {
public Type getReturnType() {
return getReturnType(getDescriptor());
return getReturnType(getDescriptor());
}
}
/**
/**
* Returns the {@link Type} corresponding to the return type of the given method descriptor.
* Returns the {@link Type} corresponding to the return type of the given method descriptor.
*
*
* @param methodDescriptor a method descriptor.
* @param methodDescriptor a method descriptor.
* @return the {@link Type} corresponding to the return type of the given method descriptor.
* @return the {@link Type} corresponding to the return type of the given method descriptor.
*/
*/
public static Type getReturnType(final String methodDescriptor) {
public static Type getReturnType(final String methodDescriptor) {
Copy
Copied
Copy
Copied
Text moved with changes to lines 389-398 (99.1% similarity)
// Skip the first character, which is always a '('.
return getTypeInternal(
int currentOffset = 1;
methodDescriptor,
getReturnTypeOffset(methodDescriptor)
, methodDescriptor.length());
// Skip the argument types, one at a each loop iteration.
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
}
}
return getTypeInternal(
methodDescriptor,
currentOffset + 1
, methodDescriptor.length());
}
}
/**
/**
* Returns the {@link Type} corresponding to the return type of the given method.
* Returns the {@link Type} corresponding to the return type of the given method.
*
*
* @param method a method.
* @param method a method.
* @return the {@link Type} corresponding to the return type of the given method.
* @return the {@link Type} corresponding to the return type of the given method.
*/
*/
public static Type getReturnType(final Method method) {
public static Type getReturnType(final Method method) {
return getType(method.getReturnType());
return getType(method.getReturnType());
}
}
/**
/**
Copy
Copied
Copy
Copied
* Returns the start index of the return type of the given method descriptor.
*
* @param methodDescriptor a method descriptor.
* @return the start index of the return type of the given method descriptor.
*/
static int getReturnTypeOffset(final String methodDescriptor) {
Text moved with changes from lines 366-375 (99.1% similarity)
// Skip the first character, which is always a '('.
int currentOffset = 1;
// Skip the argument types, one at a each loop iteration.
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
}
Text moved with changes from lines 670-674 (94.1% similarity)
}
return currentOffset + 1;
}
/**
* Returns the {@link Type} corresponding to the given field or method descriptor.
* Returns the {@link Type} corresponding to the given field or method descriptor.
*
*
* @param descriptorBuffer a buffer containing the field or method descriptor.
* @param descriptorBuffer a buffer containing the field or method descriptor.
* @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in
* @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in
* descriptorBuffer.
* descriptorBuffer.
* @param descriptorEnd the end index, exclusive, of the field or method descriptor in
* @param descriptorEnd the end index, exclusive, of the field or method descriptor in
* descriptorBuffer.
* descriptorBuffer.
* @return the {@link Type} corresponding to the given type descriptor.
* @return the {@link Type} corresponding to the given type descriptor.
*/
*/
private static Type getTypeInternal(
private static Type getTypeInternal(
final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) {
final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) {
switch (descriptorBuffer.charAt(descriptorBegin)) {
switch (descriptorBuffer.charAt(descriptorBegin)) {
case 'V':
case 'V':
return VOID_TYPE;
return VOID_TYPE;
case 'Z':
case 'Z':
return BOOLEAN_TYPE;
return BOOLEAN_TYPE;
case 'C':
case 'C':
return CHAR_TYPE;
return CHAR_TYPE;
case 'B':
case 'B':
return BYTE_TYPE;
return BYTE_TYPE;
case 'S':
case 'S':
return SHORT_TYPE;
return SHORT_TYPE;
case 'I':
case 'I':
return INT_TYPE;
return INT_TYPE;
case 'F':
case 'F':
return FLOAT_TYPE;
return FLOAT_TYPE;
case 'J':
case 'J':
return LONG_TYPE;
return LONG_TYPE;
case 'D':
case 'D':
return DOUBLE_TYPE;
return DOUBLE_TYPE;
case '[':
case '[':
return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd);
return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd);
case 'L':
case 'L':
return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1);
return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1);
case '(':
case '(':
return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd);
default:
default:
throw new IllegalArgumentException();
throw new IllegalArgumentException();
}
}
}
}
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Methods to get class names, internal names or descriptors.
// Methods to get class names, internal names or descriptors.
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
/**
* Returns the binary name of the class corresponding to this type. This method must not be used
* Returns the binary name of the class corresponding to this type. This method must not be used
* on method types.
* on method types.
*
*
* @return the binary name of the class corresponding to this type.
* @return the binary name of the class corresponding to this type.
*/
*/
public String getClassName() {
public String getClassName() {
switch (sort) {
switch (sort) {
case VOID:
case VOID:
return "void";
return "void";
case BOOLEAN:
case BOOLEAN:
return "boolean";
return "boolean";
case CHAR:
case CHAR:
return "char";
return "char";
case BYTE:
case BYTE:
return "byte";
return "byte";
case SHORT:
case SHORT:
return "short";
return "short";
case INT:
case INT:
return "int";
return "int";
case FLOAT:
case FLOAT:
return "float";
return "float";
case LONG:
case LONG:
return "long";
return "long";
case DOUBLE:
case DOUBLE:
return "double";
return "double";
case ARRAY:
case ARRAY:
StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName());
StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName());
for (int i = getDimensions(); i > 0; --i) {
for (int i = getDimensions(); i > 0; --i) {
stringBuilder.append("[]");
stringBuilder.append("[]");
}
}
return stringBuilder.toString();
return stringBuilder.toString();
case OBJECT:
case OBJECT:
case INTERNAL:
case INTERNAL:
return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.');
return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.');
default:
default:
throw new AssertionError();
throw new AssertionError();
}
}
}
}
/**
/**
* Returns the internal name of the class corresponding to this object or array type. The internal
* Returns the internal name of the class corresponding to this object or array type. The internal
* name of a class is its fully qualified name (as returned by Class.getName(), where '.' are
* name of a class is its fully qualified name (as returned by Class.getName(), where '.' are
* replaced by '/'). This method should only be used for an object or array type.
* replaced by '/'). This method should only be used for an object or array type.
*
*
* @return the internal name of the class corresponding to this object type.
* @return the internal name of the class corresponding to this object type.
*/
*/
public String getInternalName() {
public String getInternalName() {
return valueBuffer.substring(valueBegin, valueEnd);
return valueBuffer.substring(valueBegin, valueEnd);
}
}
/**
/**
* Returns the internal name of the given class. The internal name of a class is its fully
* Returns the internal name of the given class. The internal name of a class is its fully
* qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
* qualified name, as returned by Class.getName(), where '.' are replaced by '/'.
*
*
* @param clazz an object or array class.
* @param clazz an object or array class.
* @return the internal name of the given class.
* @return the internal name of the given class.
*/
*/
public static String getInternalName(final Class<?> clazz) {
public static String getInternalName(final Class<?> clazz) {
return clazz.getName().replace('.', '/');
return clazz.getName().replace('.', '/');
}
}
/**
/**
* Returns the descriptor corresponding to this type.
* Returns the descriptor corresponding to this type.
*
*
* @return the descriptor corresponding to this type.
* @return the descriptor corresponding to this type.
*/
*/
public String getDescriptor() {
public String getDescriptor() {
if (sort == OBJECT) {
if (sort == OBJECT) {
return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
} else if (sort == INTERNAL) {
} else if (sort == INTERNAL) {
Copy
Copied
Copy
Copied
return
new StringBuilder()
return
'L'
+
valueBuffer
.substring(
valueBegin, valueEnd)
+
';'
;
.append(
'L'
)
.append(
valueBuffer
,
valueBegin, valueEnd)
.append(
';'
)
.toString()
;
} else {
} else {
return valueBuffer.substring(valueBegin, valueEnd);
return valueBuffer.substring(valueBegin, valueEnd);
}
}
}
}
/**
/**
* Returns the descriptor corresponding to the given class.
* Returns the descriptor corresponding to the given class.
*
*
* @param clazz an object class, a primitive class or an array class.
* @param clazz an object class, a primitive class or an array class.
* @return the descriptor corresponding to the given class.
* @return the descriptor corresponding to the given class.
*/
*/
public static String getDescriptor(final Class<?> clazz) {
public static String getDescriptor(final Class<?> clazz) {
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder();
appendDescriptor(clazz, stringBuilder);
appendDescriptor(clazz, stringBuilder);
return stringBuilder.toString();
return stringBuilder.toString();
}
}
/**
/**
* Returns the descriptor corresponding to the given constructor.
* Returns the descriptor corresponding to the given constructor.
*
*
* @param constructor a {@link Constructor} object.
* @param constructor a {@link Constructor} object.
* @return the descriptor of the given constructor.
* @return the descriptor of the given constructor.
*/
*/
public static String getConstructorDescriptor(final Constructor<?> constructor) {
public static String getConstructorDescriptor(final Constructor<?> constructor) {
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
stringBuilder.append('(');
Class<?>[] parameters = constructor.getParameterTypes();
Class<?>[] parameters = constructor.getParameterTypes();
for (Class<?> parameter : parameters) {
for (Class<?> parameter : parameters) {
appendDescriptor(parameter, stringBuilder);
appendDescriptor(parameter, stringBuilder);
}
}
return stringBuilder.append(")V").toString();
return stringBuilder.append(")V").toString();
}
}
/**
/**
* Returns the descriptor corresponding to the given argument and return types.
* Returns the descriptor corresponding to the given argument and return types.
*
*
* @param returnType the return type of the method.
* @param returnType the return type of the method.
* @param argumentTypes the argument types of the method.
* @param argumentTypes the argument types of the method.
* @return the descriptor corresponding to the given argument and return types.
* @return the descriptor corresponding to the given argument and return types.
*/
*/
public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) {
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
stringBuilder.append('(');
for (Type argumentType : argumentTypes) {
for (Type argumentType : argumentTypes) {
argumentType.appendDescriptor(stringBuilder);
argumentType.appendDescriptor(stringBuilder);
}
}
stringBuilder.append(')');
stringBuilder.append(')');
returnType.appendDescriptor(stringBuilder);
returnType.appendDescriptor(stringBuilder);
return stringBuilder.toString();
return stringBuilder.toString();
}
}
/**
/**
* Returns the descriptor corresponding to the given method.
* Returns the descriptor corresponding to the given method.
*
*
* @param method a {@link Method} object.
* @param method a {@link Method} object.
* @return the descriptor of the given method.
* @return the descriptor of the given method.
*/
*/
public static String getMethodDescriptor(final Method method) {
public static String getMethodDescriptor(final Method method) {
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
stringBuilder.append('(');
Class<?>[] parameters = method.getParameterTypes();
Class<?>[] parameters = method.getParameterTypes();
for (Class<?> parameter : parameters) {
for (Class<?> parameter : parameters) {
appendDescriptor(parameter, stringBuilder);
appendDescriptor(parameter, stringBuilder);
}
}
stringBuilder.append(')');
stringBuilder.append(')');
appendDescriptor(method.getReturnType(), stringBuilder);
appendDescriptor(method.getReturnType(), stringBuilder);
return stringBuilder.toString();
return stringBuilder.toString();
}
}
/**
/**
* Appends the descriptor corresponding to this type to the given string buffer.
* Appends the descriptor corresponding to this type to the given string buffer.
*
*
* @param stringBuilder the string builder to which the descriptor must be appended.
* @param stringBuilder the string builder to which the descriptor must be appended.
*/
*/
private void appendDescriptor(final StringBuilder stringBuilder) {
private void appendDescriptor(final StringBuilder stringBuilder) {
if (sort == OBJECT) {
if (sort == OBJECT) {
stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1);
stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1);
} else if (sort == INTERNAL) {
} else if (sort == INTERNAL) {
stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';');
stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';');
} else {
} else {
stringBuilder.append(valueBuffer, valueBegin, valueEnd);
stringBuilder.append(valueBuffer, valueBegin, valueEnd);
}
}
}
}
/**
/**
* Appends the descriptor of the given class to the given string builder.
* Appends the descriptor of the given class to the given string builder.
*
*
* @param clazz the class whose descriptor must be computed.
* @param clazz the class whose descriptor must be computed.
* @param stringBuilder the string builder to which the descriptor must be appended.
* @param stringBuilder the string builder to which the descriptor must be appended.
*/
*/
private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) {
private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) {
Class<?> currentClass = clazz;
Class<?> currentClass = clazz;
while (currentClass.isArray()) {
while (currentClass.isArray()) {
stringBuilder.append('[');
stringBuilder.append('[');
currentClass = currentClass.getComponentType();
currentClass = currentClass.getComponentType();
}
}
if (currentClass.isPrimitive()) {
if (currentClass.isPrimitive()) {
char descriptor;
char descriptor;
if (currentClass == Integer.TYPE) {
if (currentClass == Integer.TYPE) {
descriptor = 'I';
descriptor = 'I';
} else if (currentClass == Void.TYPE) {
} else if (currentClass == Void.TYPE) {
descriptor = 'V';
descriptor = 'V';
} else if (currentClass == Boolean.TYPE) {
} else if (currentClass == Boolean.TYPE) {
descriptor = 'Z';
descriptor = 'Z';
} else if (currentClass == Byte.TYPE) {
} else if (currentClass == Byte.TYPE) {
descriptor = 'B';
descriptor = 'B';
} else if (currentClass == Character.TYPE) {
} else if (currentClass == Character.TYPE) {
descriptor = 'C';
descriptor = 'C';
} else if (currentClass == Short.TYPE) {
} else if (currentClass == Short.TYPE) {
descriptor = 'S';
descriptor = 'S';
} else if (currentClass == Double.TYPE) {
} else if (currentClass == Double.TYPE) {
descriptor = 'D';
descriptor = 'D';
} else if (currentClass == Float.TYPE) {
} else if (currentClass == Float.TYPE) {
descriptor = 'F';
descriptor = 'F';
} else if (currentClass == Long.TYPE) {
} else if (currentClass == Long.TYPE) {
descriptor = 'J';
descriptor = 'J';
} else {
} else {
throw new AssertionError();
throw new AssertionError();
}
}
stringBuilder.append(descriptor);
stringBuilder.append(descriptor);
} else {
} else {
Copy
Copied
Copy
Copied
stringBuilder.append('L')
;
stringBuilder.append('L')
.append(getInternalName(
currentClass
))
.append(';');
String name =
currentClass
.getName();
int nameLength = name.length();
for (int i = 0; i < nameLength; ++i) {
char car = name.charAt(i);
stringBuilder.append(car == '.' ? '/' : car);
}
stringBuilder
.append(';');
}
}
}
}
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor.
// Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor.
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
/**
* Returns the sort of this type.
* Returns the sort of this type.
*
*
* @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
* @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link
* #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
* #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or
* {@link #METHOD}.
* {@link #METHOD}.
*/
*/
public int getSort() {
public int getSort() {
return sort == INTERNAL ? OBJECT : sort;
return sort == INTERNAL ? OBJECT : sort;
}
}
/**
/**
* Returns the number of dimensions of this array type. This method should only be used for an
* Returns the number of dimensions of this array type. This method should only be used for an
* array type.
* array type.
*
*
* @return the number of dimensions of this array type.
* @return the number of dimensions of this array type.
*/
*/
public int getDimensions() {
public int getDimensions() {
int numDimensions = 1;
int numDimensions = 1;
Copy
Copied
Copy
Copied
while (valueBuffer.charAt(valueBegin + numDimensions)
== '[') {
while (valueBuffer.charAt(valueBegin + numDimensions)
numDimensions++;
Text moved with changes to lines 401-405 (94.1% similarity)
}
return numDimensions;
}
/**
* Returns the size of values of this type. This method must not be used for method types.
*
* @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for
* {@code
Saved diffs
Original text
Open file
// 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.objectweb.asm; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * A Java field or method type. This class can be used to make it easier to manipulate type and * method descriptors. * * @author Eric Bruneton * @author Chris Nokleberg */ public final class Type { /** The sort of the {@code void} type. See {@link #getSort}. */ public static final int VOID = 0; /** The sort of the {@code boolean} type. See {@link #getSort}. */ public static final int BOOLEAN = 1; /** The sort of the {@code char} type. See {@link #getSort}. */ public static final int CHAR = 2; /** The sort of the {@code byte} type. See {@link #getSort}. */ public static final int BYTE = 3; /** The sort of the {@code short} type. See {@link #getSort}. */ public static final int SHORT = 4; /** The sort of the {@code int} type. See {@link #getSort}. */ public static final int INT = 5; /** The sort of the {@code float} type. See {@link #getSort}. */ public static final int FLOAT = 6; /** The sort of the {@code long} type. See {@link #getSort}. */ public static final int LONG = 7; /** The sort of the {@code double} type. See {@link #getSort}. */ public static final int DOUBLE = 8; /** The sort of array reference types. See {@link #getSort}. */ public static final int ARRAY = 9; /** The sort of object reference types. See {@link #getSort}. */ public static final int OBJECT = 10; /** The sort of method types. See {@link #getSort}. */ public static final int METHOD = 11; /** The (private) sort of object reference types represented with an internal name. */ private static final int INTERNAL = 12; /** The descriptors of the primitive types. */ private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD"; /** The {@code void} type. */ public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1); /** The {@code boolean} type. */ public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1); /** The {@code char} type. */ public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1); /** The {@code byte} type. */ public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1); /** The {@code short} type. */ public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1); /** The {@code int} type. */ public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1); /** The {@code float} type. */ public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1); /** The {@code long} type. */ public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1); /** The {@code double} type. */ public static final Type DOUBLE_TYPE = new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1); // ----------------------------------------------------------------------------------------------- // Fields // ----------------------------------------------------------------------------------------------- /** * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}. */ private final int sort; /** * A buffer containing the value of this field or method type. This value is an internal name for * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other * cases. * * <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in * [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link * #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor. */ private final String valueBuffer; /** * The beginning index, inclusive, of the value of this Java field or method type in {@link * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, * and a field or method descriptor in the other cases. */ private final int valueBegin; /** * The end index, exclusive, of the value of this Java field or method type in {@link * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, * and a field or method descriptor in the other cases. */ private final int valueEnd; /** * Constructs a reference type. * * @param sort the sort of this type, see {@link #sort}. * @param valueBuffer a buffer containing the value of this field or method type. * @param valueBegin the beginning index, inclusive, of the value of this field or method type in * valueBuffer. * @param valueEnd the end index, exclusive, of the value of this field or method type in * valueBuffer. */ private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) { this.sort = sort; this.valueBuffer = valueBuffer; this.valueBegin = valueBegin; this.valueEnd = valueEnd; } // ----------------------------------------------------------------------------------------------- // Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc. // ----------------------------------------------------------------------------------------------- /** * Returns the {@link Type} corresponding to the given type descriptor. * * @param typeDescriptor a field or method type descriptor. * @return the {@link Type} corresponding to the given type descriptor. */ public static Type getType(final String typeDescriptor) { return getTypeInternal(typeDescriptor, 0, typeDescriptor.length()); } /** * Returns the {@link Type} corresponding to the given class. * * @param clazz a class. * @return the {@link Type} corresponding to the given class. */ public static Type getType(final Class<?> clazz) { if (clazz.isPrimitive()) { if (clazz == Integer.TYPE) { return INT_TYPE; } else if (clazz == Void.TYPE) { return VOID_TYPE; } else if (clazz == Boolean.TYPE) { return BOOLEAN_TYPE; } else if (clazz == Byte.TYPE) { return BYTE_TYPE; } else if (clazz == Character.TYPE) { return CHAR_TYPE; } else if (clazz == Short.TYPE) { return SHORT_TYPE; } else if (clazz == Double.TYPE) { return DOUBLE_TYPE; } else if (clazz == Float.TYPE) { return FLOAT_TYPE; } else if (clazz == Long.TYPE) { return LONG_TYPE; } else { throw new AssertionError(); } } else { return getType(getDescriptor(clazz)); } } /** * Returns the method {@link Type} corresponding to the given constructor. * * @param constructor a {@link Constructor} object. * @return the method {@link Type} corresponding to the given constructor. */ public static Type getType(final Constructor<?> constructor) { return getType(getConstructorDescriptor(constructor)); } /** * Returns the method {@link Type} corresponding to the given method. * * @param method a {@link Method} object. * @return the method {@link Type} corresponding to the given method. */ public static Type getType(final Method method) { return getType(getMethodDescriptor(method)); } /** * Returns the type of the elements of this array type. This method should only be used for an * array type. * * @return Returns the type of the elements of this array type. */ public Type getElementType() { final int numDimensions = getDimensions(); return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd); } /** * Returns the {@link Type} corresponding to the given internal name. * * @param internalName an internal name. * @return the {@link Type} corresponding to the given internal name. */ public static Type getObjectType(final String internalName) { return new Type( internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length()); } /** * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code> * Type.getType(methodDescriptor)</code>. * * @param methodDescriptor a method descriptor. * @return the {@link Type} corresponding to the given method descriptor. */ public static Type getMethodType(final String methodDescriptor) { return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length()); } /** * Returns the method {@link Type} corresponding to the given argument and return types. * * @param returnType the return type of the method. * @param argumentTypes the argument types of the method. * @return the method {@link Type} corresponding to the given argument and return types. */ public static Type getMethodType(final Type returnType, final Type... argumentTypes) { return getType(getMethodDescriptor(returnType, argumentTypes)); } /** * Returns the argument types of methods of this type. This method should only be used for method * types. * * @return the argument types of methods of this type. */ public Type[] getArgumentTypes() { return getArgumentTypes(getDescriptor()); } /** * Returns the {@link Type} values corresponding to the argument types of the given method * descriptor. * * @param methodDescriptor a method descriptor. * @return the {@link Type} values corresponding to the argument types of the given method * descriptor. */ public static Type[] getArgumentTypes(final String methodDescriptor) { // First step: compute the number of argument types in methodDescriptor. int numArgumentTypes = 0; // Skip the first character, which is always a '('. int currentOffset = 1; // Parse the argument types, one at a each loop iteration. while (methodDescriptor.charAt(currentOffset) != ')') { while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; } ++numArgumentTypes; } // Second step: create a Type instance for each argument type. Type[] argumentTypes = new Type[numArgumentTypes]; // Skip the first character, which is always a '('. currentOffset = 1; // Parse and create the argument types, one at each loop iteration. int currentArgumentTypeIndex = 0; while (methodDescriptor.charAt(currentOffset) != ')') { final int currentArgumentTypeOffset = currentOffset; while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; } argumentTypes[currentArgumentTypeIndex++] = getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset); } return argumentTypes; } /** * Returns the {@link Type} values corresponding to the argument types of the given method. * * @param method a method. * @return the {@link Type} values corresponding to the argument types of the given method. */ public static Type[] getArgumentTypes(final Method method) { Class<?>[] classes = method.getParameterTypes(); Type[] types = new Type[classes.length]; for (int i = classes.length - 1; i >= 0; --i) { types[i] = getType(classes[i]); } return types; } /** * Returns the return type of methods of this type. This method should only be used for method * types. * * @return the return type of methods of this type. */ public Type getReturnType() { return getReturnType(getDescriptor()); } /** * Returns the {@link Type} corresponding to the return type of the given method descriptor. * * @param methodDescriptor a method descriptor. * @return the {@link Type} corresponding to the return type of the given method descriptor. */ public static Type getReturnType(final String methodDescriptor) { // Skip the first character, which is always a '('. int currentOffset = 1; // Skip the argument types, one at a each loop iteration. while (methodDescriptor.charAt(currentOffset) != ')') { while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; } } return getTypeInternal(methodDescriptor, currentOffset + 1, methodDescriptor.length()); } /** * Returns the {@link Type} corresponding to the return type of the given method. * * @param method a method. * @return the {@link Type} corresponding to the return type of the given method. */ public static Type getReturnType(final Method method) { return getType(method.getReturnType()); } /** * Returns the {@link Type} corresponding to the given field or method descriptor. * * @param descriptorBuffer a buffer containing the field or method descriptor. * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in * descriptorBuffer. * @param descriptorEnd the end index, exclusive, of the field or method descriptor in * descriptorBuffer. * @return the {@link Type} corresponding to the given type descriptor. */ private static Type getTypeInternal( final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) { switch (descriptorBuffer.charAt(descriptorBegin)) { case 'V': return VOID_TYPE; case 'Z': return BOOLEAN_TYPE; case 'C': return CHAR_TYPE; case 'B': return BYTE_TYPE; case 'S': return SHORT_TYPE; case 'I': return INT_TYPE; case 'F': return FLOAT_TYPE; case 'J': return LONG_TYPE; case 'D': return DOUBLE_TYPE; case '[': return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd); case 'L': return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1); case '(': return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd); default: throw new IllegalArgumentException(); } } // ----------------------------------------------------------------------------------------------- // Methods to get class names, internal names or descriptors. // ----------------------------------------------------------------------------------------------- /** * Returns the binary name of the class corresponding to this type. This method must not be used * on method types. * * @return the binary name of the class corresponding to this type. */ public String getClassName() { switch (sort) { case VOID: return "void"; case BOOLEAN: return "boolean"; case CHAR: return "char"; case BYTE: return "byte"; case SHORT: return "short"; case INT: return "int"; case FLOAT: return "float"; case LONG: return "long"; case DOUBLE: return "double"; case ARRAY: StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName()); for (int i = getDimensions(); i > 0; --i) { stringBuilder.append("[]"); } return stringBuilder.toString(); case OBJECT: case INTERNAL: return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.'); default: throw new AssertionError(); } } /** * Returns the internal name of the class corresponding to this object or array type. The internal * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are * replaced by '/'). This method should only be used for an object or array type. * * @return the internal name of the class corresponding to this object type. */ public String getInternalName() { return valueBuffer.substring(valueBegin, valueEnd); } /** * Returns the internal name of the given class. The internal name of a class is its fully * qualified name, as returned by Class.getName(), where '.' are replaced by '/'. * * @param clazz an object or array class. * @return the internal name of the given class. */ public static String getInternalName(final Class<?> clazz) { return clazz.getName().replace('.', '/'); } /** * Returns the descriptor corresponding to this type. * * @return the descriptor corresponding to this type. */ public String getDescriptor() { if (sort == OBJECT) { return valueBuffer.substring(valueBegin - 1, valueEnd + 1); } else if (sort == INTERNAL) { return new StringBuilder() .append('L') .append(valueBuffer, valueBegin, valueEnd) .append(';') .toString(); } else { return valueBuffer.substring(valueBegin, valueEnd); } } /** * Returns the descriptor corresponding to the given class. * * @param clazz an object class, a primitive class or an array class. * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class<?> clazz) { StringBuilder stringBuilder = new StringBuilder(); appendDescriptor(clazz, stringBuilder); return stringBuilder.toString(); } /** * Returns the descriptor corresponding to the given constructor. * * @param constructor a {@link Constructor} object. * @return the descriptor of the given constructor. */ public static String getConstructorDescriptor(final Constructor<?> constructor) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); Class<?>[] parameters = constructor.getParameterTypes(); for (Class<?> parameter : parameters) { appendDescriptor(parameter, stringBuilder); } return stringBuilder.append(")V").toString(); } /** * Returns the descriptor corresponding to the given argument and return types. * * @param returnType the return type of the method. * @param argumentTypes the argument types of the method. * @return the descriptor corresponding to the given argument and return types. */ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); for (Type argumentType : argumentTypes) { argumentType.appendDescriptor(stringBuilder); } stringBuilder.append(')'); returnType.appendDescriptor(stringBuilder); return stringBuilder.toString(); } /** * Returns the descriptor corresponding to the given method. * * @param method a {@link Method} object. * @return the descriptor of the given method. */ public static String getMethodDescriptor(final Method method) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); Class<?>[] parameters = method.getParameterTypes(); for (Class<?> parameter : parameters) { appendDescriptor(parameter, stringBuilder); } stringBuilder.append(')'); appendDescriptor(method.getReturnType(), stringBuilder); return stringBuilder.toString(); } /** * Appends the descriptor corresponding to this type to the given string buffer. * * @param stringBuilder the string builder to which the descriptor must be appended. */ private void appendDescriptor(final StringBuilder stringBuilder) { if (sort == OBJECT) { stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1); } else if (sort == INTERNAL) { stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';'); } else { stringBuilder.append(valueBuffer, valueBegin, valueEnd); } } /** * Appends the descriptor of the given class to the given string builder. * * @param clazz the class whose descriptor must be computed. * @param stringBuilder the string builder to which the descriptor must be appended. */ private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) { Class<?> currentClass = clazz; while (currentClass.isArray()) { stringBuilder.append('['); currentClass = currentClass.getComponentType(); } if (currentClass.isPrimitive()) { char descriptor; if (currentClass == Integer.TYPE) { descriptor = 'I'; } else if (currentClass == Void.TYPE) { descriptor = 'V'; } else if (currentClass == Boolean.TYPE) { descriptor = 'Z'; } else if (currentClass == Byte.TYPE) { descriptor = 'B'; } else if (currentClass == Character.TYPE) { descriptor = 'C'; } else if (currentClass == Short.TYPE) { descriptor = 'S'; } else if (currentClass == Double.TYPE) { descriptor = 'D'; } else if (currentClass == Float.TYPE) { descriptor = 'F'; } else if (currentClass == Long.TYPE) { descriptor = 'J'; } else { throw new AssertionError(); } stringBuilder.append(descriptor); } else { stringBuilder.append('L'); String name = currentClass.getName(); int nameLength = name.length(); for (int i = 0; i < nameLength; ++i) { char car = name.charAt(i); stringBuilder.append(car == '.' ? '/' : car); } stringBuilder.append(';'); } } // ----------------------------------------------------------------------------------------------- // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor. // ----------------------------------------------------------------------------------------------- /** * Returns the sort of this type. * * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or * {@link #METHOD}. */ public int getSort() { return sort == INTERNAL ? OBJECT : sort; } /** * Returns the number of dimensions of this array type. This method should only be used for an * array type. * * @return the number of dimensions of this array type. */ public int getDimensions() { int numDimensions = 1; while (valueBuffer.charAt(valueBegin + numDimensions) == '[') { numDimensions++; } return numDimensions; } /** * Returns the size of values of this type. This method must not be used for method types. * * @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for * {@code void} and 1 otherwise. */ public int getSize() { switch (sort) { case VOID: return 0; case BOOLEAN: case CHAR: case BYTE: case SHORT: case INT: case FLOAT: case ARRAY: case OBJECT: case INTERNAL: return 1; case LONG: case DOUBLE: return 2; default: throw new AssertionError(); } } /** * Returns the size of the arguments and of the return value of methods of this type. This method * should only be used for method types. * * @return the size of the arguments of the method (plus one for the implicit this argument), * argumentsSize, and the size of its return value, returnSize, packed into a single int i = * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code * i >> 2}, and returnSize to {@code i & 0x03}). */ public int getArgumentsAndReturnSizes() { return getArgumentsAndReturnSizes(getDescriptor()); } /** * Computes the size of the arguments and of the return value of a method. * * @param methodDescriptor a method descriptor. * @return the size of the arguments of the method (plus one for the implicit this argument), * argumentsSize, and the size of its return value, returnSize, packed into a single int i = * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code * i >> 2}, and returnSize to {@code i & 0x03}). */ public static int getArgumentsAndReturnSizes(final String methodDescriptor) { int argumentsSize = 1; // Skip the first character, which is always a '('. int currentOffset = 1; int currentChar = methodDescriptor.charAt(currentOffset); // Parse the argument types and compute their size, one at a each loop iteration. while (currentChar != ')') { if (currentChar == 'J' || currentChar == 'D') { currentOffset++; argumentsSize += 2; } else { while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; } argumentsSize += 1; } currentChar = methodDescriptor.charAt(currentOffset); } currentChar = methodDescriptor.charAt(currentOffset + 1); if (currentChar == 'V') { return argumentsSize << 2; } else { int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1; return argumentsSize << 2 | returnSize; } } /** * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for * method types. * * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and * IRETURN. * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For * example, if this type is {@code float} and {@code opcode} is IRETURN, this method returns * FRETURN. */ public int getOpcode(final int opcode) { if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { switch (sort) { case BOOLEAN: case BYTE: return opcode + (Opcodes.BALOAD - Opcodes.IALOAD); case CHAR: return opcode + (Opcodes.CALOAD - Opcodes.IALOAD); case SHORT: return opcode + (Opcodes.SALOAD - Opcodes.IALOAD); case INT: return opcode; case FLOAT: return opcode + (Opcodes.FALOAD - Opcodes.IALOAD); case LONG: return opcode + (Opcodes.LALOAD - Opcodes.IALOAD); case DOUBLE: return opcode + (Opcodes.DALOAD - Opcodes.IALOAD); case ARRAY: case OBJECT: case INTERNAL: return opcode + (Opcodes.AALOAD - Opcodes.IALOAD); case METHOD: case VOID: throw new UnsupportedOperationException(); default: throw new AssertionError(); } } else { switch (sort) { case VOID: if (opcode != Opcodes.IRETURN) { throw new UnsupportedOperationException(); } return Opcodes.RETURN; case BOOLEAN: case BYTE: case CHAR: case SHORT: case INT: return opcode; case FLOAT: return opcode + (Opcodes.FRETURN - Opcodes.IRETURN); case LONG: return opcode + (Opcodes.LRETURN - Opcodes.IRETURN); case DOUBLE: return opcode + (Opcodes.DRETURN - Opcodes.IRETURN); case ARRAY: case OBJECT: case INTERNAL: if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) { throw new UnsupportedOperationException(); } return opcode + (Opcodes.ARETURN - Opcodes.IRETURN); case METHOD: throw new UnsupportedOperationException(); default: throw new AssertionError(); } } } // ----------------------------------------------------------------------------------------------- // Equals, hashCode and toString. // ----------------------------------------------------------------------------------------------- /** * Tests if the given object is equal to this type. * * @param object the object to be compared to this type. * @return {@literal true} if the given object is equal to this type. */ @Override public boolean equals(final Object object) { if (this == object) { return true; } if (!(object instanceof Type)) { return false; } Type other = (Type) object; if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) { return false; } int begin = valueBegin; int end = valueEnd; int otherBegin = other.valueBegin; int otherEnd = other.valueEnd; // Compare the values. if (end - begin != otherEnd - otherBegin) { return false; } for (int i = begin, j = otherBegin; i < end; i++, j++) { if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) { return false; } } return true; } /** * Returns a hash code value for this type. * * @return a hash code value for this type. */ @Override public int hashCode() { int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort); if (sort >= ARRAY) { for (int i = valueBegin, end = valueEnd; i < end; i++) { hashCode = 17 * (hashCode + valueBuffer.charAt(i)); } } return hashCode; } /** * Returns a string representation of this type. * * @return the descriptor of this type. */ @Override public String toString() { return getDescriptor(); } }
Changed text
Open file
// 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.objectweb.asm; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * A Java field or method type. This class can be used to make it easier to manipulate type and * method descriptors. * * @author Eric Bruneton * @author Chris Nokleberg */ public final class Type { /** The sort of the {@code void} type. See {@link #getSort}. */ public static final int VOID = 0; /** The sort of the {@code boolean} type. See {@link #getSort}. */ public static final int BOOLEAN = 1; /** The sort of the {@code char} type. See {@link #getSort}. */ public static final int CHAR = 2; /** The sort of the {@code byte} type. See {@link #getSort}. */ public static final int BYTE = 3; /** The sort of the {@code short} type. See {@link #getSort}. */ public static final int SHORT = 4; /** The sort of the {@code int} type. See {@link #getSort}. */ public static final int INT = 5; /** The sort of the {@code float} type. See {@link #getSort}. */ public static final int FLOAT = 6; /** The sort of the {@code long} type. See {@link #getSort}. */ public static final int LONG = 7; /** The sort of the {@code double} type. See {@link #getSort}. */ public static final int DOUBLE = 8; /** The sort of array reference types. See {@link #getSort}. */ public static final int ARRAY = 9; /** The sort of object reference types. See {@link #getSort}. */ public static final int OBJECT = 10; /** The sort of method types. See {@link #getSort}. */ public static final int METHOD = 11; /** The (private) sort of object reference types represented with an internal name. */ private static final int INTERNAL = 12; /** The descriptors of the primitive types. */ private static final String PRIMITIVE_DESCRIPTORS = "VZCBSIFJD"; /** The {@code void} type. */ public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, VOID + 1); /** The {@code boolean} type. */ public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, BOOLEAN + 1); /** The {@code char} type. */ public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, CHAR + 1); /** The {@code byte} type. */ public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, BYTE + 1); /** The {@code short} type. */ public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, SHORT + 1); /** The {@code int} type. */ public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, INT + 1); /** The {@code float} type. */ public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, FLOAT + 1); /** The {@code long} type. */ public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, LONG + 1); /** The {@code double} type. */ public static final Type DOUBLE_TYPE = new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, DOUBLE + 1); // ----------------------------------------------------------------------------------------------- // Fields // ----------------------------------------------------------------------------------------------- /** * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}. */ private final int sort; /** * A buffer containing the value of this field or method type. This value is an internal name for * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other * cases. * * <p>For {@link #OBJECT} types, this field also contains the descriptor: the characters in * [{@link #valueBegin},{@link #valueEnd}) contain the internal name, and those in [{@link * #valueBegin} - 1, {@link #valueEnd} + 1) contain the descriptor. */ private final String valueBuffer; /** * The beginning index, inclusive, of the value of this Java field or method type in {@link * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, * and a field or method descriptor in the other cases. */ private final int valueBegin; /** * The end index, exclusive, of the value of this Java field or method type in {@link * #valueBuffer}. This value is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, * and a field or method descriptor in the other cases. */ private final int valueEnd; /** * Constructs a reference type. * * @param sort the sort of this type, see {@link #sort}. * @param valueBuffer a buffer containing the value of this field or method type. * @param valueBegin the beginning index, inclusive, of the value of this field or method type in * valueBuffer. * @param valueEnd the end index, exclusive, of the value of this field or method type in * valueBuffer. */ private Type(final int sort, final String valueBuffer, final int valueBegin, final int valueEnd) { this.sort = sort; this.valueBuffer = valueBuffer; this.valueBegin = valueBegin; this.valueEnd = valueEnd; } // ----------------------------------------------------------------------------------------------- // Methods to get Type(s) from a descriptor, a reflected Method or Constructor, other types, etc. // ----------------------------------------------------------------------------------------------- /** * Returns the {@link Type} corresponding to the given type descriptor. * * @param typeDescriptor a field or method type descriptor. * @return the {@link Type} corresponding to the given type descriptor. */ public static Type getType(final String typeDescriptor) { return getTypeInternal(typeDescriptor, 0, typeDescriptor.length()); } /** * Returns the {@link Type} corresponding to the given class. * * @param clazz a class. * @return the {@link Type} corresponding to the given class. */ public static Type getType(final Class<?> clazz) { if (clazz.isPrimitive()) { if (clazz == Integer.TYPE) { return INT_TYPE; } else if (clazz == Void.TYPE) { return VOID_TYPE; } else if (clazz == Boolean.TYPE) { return BOOLEAN_TYPE; } else if (clazz == Byte.TYPE) { return BYTE_TYPE; } else if (clazz == Character.TYPE) { return CHAR_TYPE; } else if (clazz == Short.TYPE) { return SHORT_TYPE; } else if (clazz == Double.TYPE) { return DOUBLE_TYPE; } else if (clazz == Float.TYPE) { return FLOAT_TYPE; } else if (clazz == Long.TYPE) { return LONG_TYPE; } else { throw new AssertionError(); } } else { return getType(getDescriptor(clazz)); } } /** * Returns the method {@link Type} corresponding to the given constructor. * * @param constructor a {@link Constructor} object. * @return the method {@link Type} corresponding to the given constructor. */ public static Type getType(final Constructor<?> constructor) { return getType(getConstructorDescriptor(constructor)); } /** * Returns the method {@link Type} corresponding to the given method. * * @param method a {@link Method} object. * @return the method {@link Type} corresponding to the given method. */ public static Type getType(final Method method) { return getType(getMethodDescriptor(method)); } /** * Returns the type of the elements of this array type. This method should only be used for an * array type. * * @return Returns the type of the elements of this array type. */ public Type getElementType() { final int numDimensions = getDimensions(); return getTypeInternal(valueBuffer, valueBegin + numDimensions, valueEnd); } /** * Returns the {@link Type} corresponding to the given internal name. * * @param internalName an internal name. * @return the {@link Type} corresponding to the given internal name. */ public static Type getObjectType(final String internalName) { return new Type( internalName.charAt(0) == '[' ? ARRAY : INTERNAL, internalName, 0, internalName.length()); } /** * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to <code> * Type.getType(methodDescriptor)</code>. * * @param methodDescriptor a method descriptor. * @return the {@link Type} corresponding to the given method descriptor. */ public static Type getMethodType(final String methodDescriptor) { return new Type(METHOD, methodDescriptor, 0, methodDescriptor.length()); } /** * Returns the method {@link Type} corresponding to the given argument and return types. * * @param returnType the return type of the method. * @param argumentTypes the argument types of the method. * @return the method {@link Type} corresponding to the given argument and return types. */ public static Type getMethodType(final Type returnType, final Type... argumentTypes) { return getType(getMethodDescriptor(returnType, argumentTypes)); } /** * Returns the argument types of methods of this type. This method should only be used for method * types. * * @return the argument types of methods of this type. */ public Type[] getArgumentTypes() { return getArgumentTypes(getDescriptor()); } /** * Returns the {@link Type} values corresponding to the argument types of the given method * descriptor. * * @param methodDescriptor a method descriptor. * @return the {@link Type} values corresponding to the argument types of the given method * descriptor. */ public static Type[] getArgumentTypes(final String methodDescriptor) { // First step: compute the number of argument types in methodDescriptor. int numArgumentTypes = 0; // Skip the first character, which is always a '('. int currentOffset = 1; // Parse the argument types, one at a each loop iteration. while (methodDescriptor.charAt(currentOffset) != ')') { while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); currentOffset = Math.max(currentOffset, semiColumnOffset + 1); } ++numArgumentTypes; } // Second step: create a Type instance for each argument type. Type[] argumentTypes = new Type[numArgumentTypes]; // Skip the first character, which is always a '('. currentOffset = 1; // Parse and create the argument types, one at each loop iteration. int currentArgumentTypeIndex = 0; while (methodDescriptor.charAt(currentOffset) != ')') { final int currentArgumentTypeOffset = currentOffset; while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); currentOffset = Math.max(currentOffset, semiColumnOffset + 1); } argumentTypes[currentArgumentTypeIndex++] = getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset); } return argumentTypes; } /** * Returns the {@link Type} values corresponding to the argument types of the given method. * * @param method a method. * @return the {@link Type} values corresponding to the argument types of the given method. */ public static Type[] getArgumentTypes(final Method method) { Class<?>[] classes = method.getParameterTypes(); Type[] types = new Type[classes.length]; for (int i = classes.length - 1; i >= 0; --i) { types[i] = getType(classes[i]); } return types; } /** * Returns the return type of methods of this type. This method should only be used for method * types. * * @return the return type of methods of this type. */ public Type getReturnType() { return getReturnType(getDescriptor()); } /** * Returns the {@link Type} corresponding to the return type of the given method descriptor. * * @param methodDescriptor a method descriptor. * @return the {@link Type} corresponding to the return type of the given method descriptor. */ public static Type getReturnType(final String methodDescriptor) { return getTypeInternal( methodDescriptor, getReturnTypeOffset(methodDescriptor), methodDescriptor.length()); } /** * Returns the {@link Type} corresponding to the return type of the given method. * * @param method a method. * @return the {@link Type} corresponding to the return type of the given method. */ public static Type getReturnType(final Method method) { return getType(method.getReturnType()); } /** * Returns the start index of the return type of the given method descriptor. * * @param methodDescriptor a method descriptor. * @return the start index of the return type of the given method descriptor. */ static int getReturnTypeOffset(final String methodDescriptor) { // Skip the first character, which is always a '('. int currentOffset = 1; // Skip the argument types, one at a each loop iteration. while (methodDescriptor.charAt(currentOffset) != ')') { while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); currentOffset = Math.max(currentOffset, semiColumnOffset + 1); } } return currentOffset + 1; } /** * Returns the {@link Type} corresponding to the given field or method descriptor. * * @param descriptorBuffer a buffer containing the field or method descriptor. * @param descriptorBegin the beginning index, inclusive, of the field or method descriptor in * descriptorBuffer. * @param descriptorEnd the end index, exclusive, of the field or method descriptor in * descriptorBuffer. * @return the {@link Type} corresponding to the given type descriptor. */ private static Type getTypeInternal( final String descriptorBuffer, final int descriptorBegin, final int descriptorEnd) { switch (descriptorBuffer.charAt(descriptorBegin)) { case 'V': return VOID_TYPE; case 'Z': return BOOLEAN_TYPE; case 'C': return CHAR_TYPE; case 'B': return BYTE_TYPE; case 'S': return SHORT_TYPE; case 'I': return INT_TYPE; case 'F': return FLOAT_TYPE; case 'J': return LONG_TYPE; case 'D': return DOUBLE_TYPE; case '[': return new Type(ARRAY, descriptorBuffer, descriptorBegin, descriptorEnd); case 'L': return new Type(OBJECT, descriptorBuffer, descriptorBegin + 1, descriptorEnd - 1); case '(': return new Type(METHOD, descriptorBuffer, descriptorBegin, descriptorEnd); default: throw new IllegalArgumentException(); } } // ----------------------------------------------------------------------------------------------- // Methods to get class names, internal names or descriptors. // ----------------------------------------------------------------------------------------------- /** * Returns the binary name of the class corresponding to this type. This method must not be used * on method types. * * @return the binary name of the class corresponding to this type. */ public String getClassName() { switch (sort) { case VOID: return "void"; case BOOLEAN: return "boolean"; case CHAR: return "char"; case BYTE: return "byte"; case SHORT: return "short"; case INT: return "int"; case FLOAT: return "float"; case LONG: return "long"; case DOUBLE: return "double"; case ARRAY: StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName()); for (int i = getDimensions(); i > 0; --i) { stringBuilder.append("[]"); } return stringBuilder.toString(); case OBJECT: case INTERNAL: return valueBuffer.substring(valueBegin, valueEnd).replace('/', '.'); default: throw new AssertionError(); } } /** * Returns the internal name of the class corresponding to this object or array type. The internal * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are * replaced by '/'). This method should only be used for an object or array type. * * @return the internal name of the class corresponding to this object type. */ public String getInternalName() { return valueBuffer.substring(valueBegin, valueEnd); } /** * Returns the internal name of the given class. The internal name of a class is its fully * qualified name, as returned by Class.getName(), where '.' are replaced by '/'. * * @param clazz an object or array class. * @return the internal name of the given class. */ public static String getInternalName(final Class<?> clazz) { return clazz.getName().replace('.', '/'); } /** * Returns the descriptor corresponding to this type. * * @return the descriptor corresponding to this type. */ public String getDescriptor() { if (sort == OBJECT) { return valueBuffer.substring(valueBegin - 1, valueEnd + 1); } else if (sort == INTERNAL) { return 'L' + valueBuffer.substring(valueBegin, valueEnd) + ';'; } else { return valueBuffer.substring(valueBegin, valueEnd); } } /** * Returns the descriptor corresponding to the given class. * * @param clazz an object class, a primitive class or an array class. * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class<?> clazz) { StringBuilder stringBuilder = new StringBuilder(); appendDescriptor(clazz, stringBuilder); return stringBuilder.toString(); } /** * Returns the descriptor corresponding to the given constructor. * * @param constructor a {@link Constructor} object. * @return the descriptor of the given constructor. */ public static String getConstructorDescriptor(final Constructor<?> constructor) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); Class<?>[] parameters = constructor.getParameterTypes(); for (Class<?> parameter : parameters) { appendDescriptor(parameter, stringBuilder); } return stringBuilder.append(")V").toString(); } /** * Returns the descriptor corresponding to the given argument and return types. * * @param returnType the return type of the method. * @param argumentTypes the argument types of the method. * @return the descriptor corresponding to the given argument and return types. */ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); for (Type argumentType : argumentTypes) { argumentType.appendDescriptor(stringBuilder); } stringBuilder.append(')'); returnType.appendDescriptor(stringBuilder); return stringBuilder.toString(); } /** * Returns the descriptor corresponding to the given method. * * @param method a {@link Method} object. * @return the descriptor of the given method. */ public static String getMethodDescriptor(final Method method) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); Class<?>[] parameters = method.getParameterTypes(); for (Class<?> parameter : parameters) { appendDescriptor(parameter, stringBuilder); } stringBuilder.append(')'); appendDescriptor(method.getReturnType(), stringBuilder); return stringBuilder.toString(); } /** * Appends the descriptor corresponding to this type to the given string buffer. * * @param stringBuilder the string builder to which the descriptor must be appended. */ private void appendDescriptor(final StringBuilder stringBuilder) { if (sort == OBJECT) { stringBuilder.append(valueBuffer, valueBegin - 1, valueEnd + 1); } else if (sort == INTERNAL) { stringBuilder.append('L').append(valueBuffer, valueBegin, valueEnd).append(';'); } else { stringBuilder.append(valueBuffer, valueBegin, valueEnd); } } /** * Appends the descriptor of the given class to the given string builder. * * @param clazz the class whose descriptor must be computed. * @param stringBuilder the string builder to which the descriptor must be appended. */ private static void appendDescriptor(final Class<?> clazz, final StringBuilder stringBuilder) { Class<?> currentClass = clazz; while (currentClass.isArray()) { stringBuilder.append('['); currentClass = currentClass.getComponentType(); } if (currentClass.isPrimitive()) { char descriptor; if (currentClass == Integer.TYPE) { descriptor = 'I'; } else if (currentClass == Void.TYPE) { descriptor = 'V'; } else if (currentClass == Boolean.TYPE) { descriptor = 'Z'; } else if (currentClass == Byte.TYPE) { descriptor = 'B'; } else if (currentClass == Character.TYPE) { descriptor = 'C'; } else if (currentClass == Short.TYPE) { descriptor = 'S'; } else if (currentClass == Double.TYPE) { descriptor = 'D'; } else if (currentClass == Float.TYPE) { descriptor = 'F'; } else if (currentClass == Long.TYPE) { descriptor = 'J'; } else { throw new AssertionError(); } stringBuilder.append(descriptor); } else { stringBuilder.append('L').append(getInternalName(currentClass)).append(';'); } } // ----------------------------------------------------------------------------------------------- // Methods to get the sort, dimension, size, and opcodes corresponding to a Type or descriptor. // ----------------------------------------------------------------------------------------------- /** * Returns the sort of this type. * * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or * {@link #METHOD}. */ public int getSort() { return sort == INTERNAL ? OBJECT : sort; } /** * Returns the number of dimensions of this array type. This method should only be used for an * array type. * * @return the number of dimensions of this array type. */ public int getDimensions() { int numDimensions = 1; while (valueBuffer.charAt(valueBegin + numDimensions) == '[') { numDimensions++; } return numDimensions; } /** * Returns the size of values of this type. This method must not be used for method types. * * @return the size of values of this type, i.e., 2 for {@code long} and {@code double}, 0 for * {@code void} and 1 otherwise. */ public int getSize() { switch (sort) { case VOID: return 0; case BOOLEAN: case CHAR: case BYTE: case SHORT: case INT: case FLOAT: case ARRAY: case OBJECT: case INTERNAL: return 1; case LONG: case DOUBLE: return 2; default: throw new AssertionError(); } } /** * Returns the size of the arguments and of the return value of methods of this type. This method * should only be used for method types. * * @return the size of the arguments of the method (plus one for the implicit this argument), * argumentsSize, and the size of its return value, returnSize, packed into a single int i = * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code * i >> 2}, and returnSize to {@code i & 0x03}). */ public int getArgumentsAndReturnSizes() { return getArgumentsAndReturnSizes(getDescriptor()); } /** * Computes the size of the arguments and of the return value of a method. * * @param methodDescriptor a method descriptor. * @return the size of the arguments of the method (plus one for the implicit this argument), * argumentsSize, and the size of its return value, returnSize, packed into a single int i = * {@code (argumentsSize << 2) | returnSize} (argumentsSize is therefore equal to {@code * i >> 2}, and returnSize to {@code i & 0x03}). */ public static int getArgumentsAndReturnSizes(final String methodDescriptor) { int argumentsSize = 1; // Skip the first character, which is always a '('. int currentOffset = 1; int currentChar = methodDescriptor.charAt(currentOffset); // Parse the argument types and compute their size, one at a each loop iteration. while (currentChar != ')') { if (currentChar == 'J' || currentChar == 'D') { currentOffset++; argumentsSize += 2; } else { while (methodDescriptor.charAt(currentOffset) == '[') { currentOffset++; } if (methodDescriptor.charAt(currentOffset++) == 'L') { // Skip the argument descriptor content. int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset); currentOffset = Math.max(currentOffset, semiColumnOffset + 1); } argumentsSize += 1; } currentChar = methodDescriptor.charAt(currentOffset); } currentChar = methodDescriptor.charAt(currentOffset + 1); if (currentChar == 'V') { return argumentsSize << 2; } else { int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1; return argumentsSize << 2 | returnSize; } } /** * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for * method types. * * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and * IRETURN. * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For * example, if this type is {@code float} and {@code opcode} is IRETURN, this method returns * FRETURN. */ public int getOpcode(final int opcode) { if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { switch (sort) { case BOOLEAN: case BYTE: return opcode + (Opcodes.BALOAD - Opcodes.IALOAD); case CHAR: return opcode + (Opcodes.CALOAD - Opcodes.IALOAD); case SHORT: return opcode + (Opcodes.SALOAD - Opcodes.IALOAD); case INT: return opcode; case FLOAT: return opcode + (Opcodes.FALOAD - Opcodes.IALOAD); case LONG: return opcode + (Opcodes.LALOAD - Opcodes.IALOAD); case DOUBLE: return opcode + (Opcodes.DALOAD - Opcodes.IALOAD); case ARRAY: case OBJECT: case INTERNAL: return opcode + (Opcodes.AALOAD - Opcodes.IALOAD); case METHOD: case VOID: throw new UnsupportedOperationException(); default: throw new AssertionError(); } } else { switch (sort) { case VOID: if (opcode != Opcodes.IRETURN) { throw new UnsupportedOperationException(); } return Opcodes.RETURN; case BOOLEAN: case BYTE: case CHAR: case SHORT: case INT: return opcode; case FLOAT: return opcode + (Opcodes.FRETURN - Opcodes.IRETURN); case LONG: return opcode + (Opcodes.LRETURN - Opcodes.IRETURN); case DOUBLE: return opcode + (Opcodes.DRETURN - Opcodes.IRETURN); case ARRAY: case OBJECT: case INTERNAL: if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) { throw new UnsupportedOperationException(); } return opcode + (Opcodes.ARETURN - Opcodes.IRETURN); case METHOD: throw new UnsupportedOperationException(); default: throw new AssertionError(); } } } // ----------------------------------------------------------------------------------------------- // Equals, hashCode and toString. // ----------------------------------------------------------------------------------------------- /** * Tests if the given object is equal to this type. * * @param object the object to be compared to this type. * @return {@literal true} if the given object is equal to this type. */ @Override public boolean equals(final Object object) { if (this == object) { return true; } if (!(object instanceof Type)) { return false; } Type other = (Type) object; if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) { return false; } int begin = valueBegin; int end = valueEnd; int otherBegin = other.valueBegin; int otherEnd = other.valueEnd; // Compare the values. if (end - begin != otherEnd - otherBegin) { return false; } for (int i = begin, j = otherBegin; i < end; i++, j++) { if (valueBuffer.charAt(i) != other.valueBuffer.charAt(j)) { return false; } } return true; } /** * Returns a hash code value for this type. * * @return a hash code value for this type. */ @Override public int hashCode() { int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort); if (sort >= ARRAY) { for (int i = valueBegin, end = valueEnd; i < end; i++) { hashCode = 17 * (hashCode + valueBuffer.charAt(i)); } } return hashCode; } /** * Returns a string representation of this type. * * @return the descriptor of this type. */ @Override public String toString() { return getDescriptor(); } }
Find difference