/* |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
/* |
|
* This file is available under and governed by the GNU General Public |
|
* License version 2 only, as published by the Free Software Foundation. |
|
* However, the following notice accompanied the original version of this |
|
* 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 jdk.internal.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 class Type { |
|
/** |
|
* The sort of the <tt>void</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int VOID = 0; |
|
/** |
|
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int BOOLEAN = 1; |
|
/** |
|
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int CHAR = 2; |
|
/** |
|
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int BYTE = 3; |
|
/** |
|
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int SHORT = 4; |
|
/** |
|
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int INT = 5; |
|
/** |
|
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int FLOAT = 6; |
|
/** |
|
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int LONG = 7; |
|
/** |
|
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}. |
|
*/ |
|
public static final int DOUBLE = 8; |
|
/** |
|
* The sort of array reference types. See {@link #getSort getSort}. |
|
*/ |
|
public static final int ARRAY = 9; |
|
/** |
|
* The sort of object reference types. See {@link #getSort getSort}. |
|
*/ |
|
public static final int OBJECT = 10; |
|
/** |
|
* The sort of method types. See {@link #getSort getSort}. |
|
*/ |
|
public static final int METHOD = 11; |
|
/** |
|
* The <tt>void</tt> type. |
|
*/ |
|
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) |
|
| (5 << 16) | (0 << 8) | 0, 1); |
|
/** |
|
* The <tt>boolean</tt> type. |
|
*/ |
|
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) |
|
| (0 << 16) | (5 << 8) | 1, 1); |
|
/** |
|
* The <tt>char</tt> type. |
|
*/ |
|
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) |
|
| (0 << 16) | (6 << 8) | 1, 1); |
|
/** |
|
* The <tt>byte</tt> type. |
|
*/ |
|
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) |
|
| (0 << 16) | (5 << 8) | 1, 1); |
|
/** |
|
* The <tt>short</tt> type. |
|
*/ |
|
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) |
|
| (0 << 16) | (7 << 8) | 1, 1); |
|
/** |
|
* The <tt>int</tt> type. |
|
*/ |
|
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) |
|
| (0 << 16) | (0 << 8) | 1, 1); |
|
/** |
|
* The <tt>float</tt> type. |
|
*/ |
|
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) |
|
| (2 << 16) | (2 << 8) | 1, 1); |
|
/** |
|
* The <tt>long</tt> type. |
|
*/ |
|
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) |
|
| (1 << 16) | (1 << 8) | 2, 1); |
|
/** |
|
* The <tt>double</tt> type. |
|
*/ |
|
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) |
|
| (3 << 16) | (3 << 8) | 2, 1); |
|
// ------------------------------------------------------------------------ |
|
// Fields |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* The sort of this Java type. |
|
*/ |
|
private final int sort; |
|
/** |
|
* A buffer containing the internal name of this Java type. This field is |
|
* only used for reference types. |
|
*/ |
|
private final char[] buf; |
|
/** |
|
* The offset of the internal name of this Java type in {@link #buf buf} or, |
|
* for primitive types, the size, descriptor and getOpcode offsets for this |
|
* type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset |
|
* for IALOAD or IASTORE, byte 3 the offset for all other instructions). |
|
*/ |
|
private final int off; |
|
/** |
|
* The length of the internal name of this Java type. |
|
*/ |
|
private final int len; |
|
// ------------------------------------------------------------------------ |
|
// Constructors |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* Constructs a reference type. |
|
* |
|
* @param sort |
|
* the sort of the reference type to be constructed. |
|
* @param buf |
|
* a buffer containing the descriptor of the previous type. |
|
* @param off |
|
* the offset of this descriptor in the previous buffer. |
|
* @param len |
|
* the length of this descriptor. |
|
*/ |
|
private Type(final int sort, final char[] buf, final int off, final int len) { |
|
this.sort = sort; |
|
this.buf = buf; |
|
this.off = off; |
|
this.len = len; |
|
} |
|
/** |
|
* Returns the Java type corresponding to the given type descriptor. |
|
* |
|
* @param typeDescriptor |
|
* a field or method type descriptor. |
|
* @return the Java type corresponding to the given type descriptor. |
|
*/ |
|
public static Type getType(final String typeDescriptor) { |
|
return getType(typeDescriptor.toCharArray(), 0); |
|
} |
|
/** |
|
* Returns the Java type corresponding to the given internal name. |
|
* |
|
* @param internalName |
|
* an internal name. |
|
* @return the Java type corresponding to the given internal name. |
|
*/ |
|
public static Type getObjectType(final String internalName) { |
|
char[] buf = internalName.toCharArray(); |
|
return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); |
|
} |
|
/** |
|
* Returns the Java type corresponding to the given method descriptor. |
|
* Equivalent to <code>Type.getType(methodDescriptor)</code>. |
|
* |
|
* @param methodDescriptor |
|
* a method descriptor. |
|
* @return the Java type corresponding to the given method descriptor. |
|
*/ |
|
public static Type getMethodType(final String methodDescriptor) { |
|
return getType(methodDescriptor.toCharArray(), 0); |
|
} |
|
/** |
|
* Returns the Java method 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 Java 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 Java type corresponding to the given class. |
|
* |
|
* @param c |
|
* a class. |
|
* @return the Java type corresponding to the given class. |
|
*/ |
|
public static Type getType(final Class<?> c) { |
|
if (c.isPrimitive()) { |
|
if (c == Integer.TYPE) { |
|
return INT_TYPE; |
|
} else if (c == Void.TYPE) { |
|
return VOID_TYPE; |
|
} else if (c == Boolean.TYPE) { |
|
return BOOLEAN_TYPE; |
|
} else if (c == Byte.TYPE) { |
|
return BYTE_TYPE; |
|
} else if (c == Character.TYPE) { |
|
return CHAR_TYPE; |
|
} else if (c == Short.TYPE) { |
|
return SHORT_TYPE; |
|
} else if (c == Double.TYPE) { |
|
return DOUBLE_TYPE; |
|
} else if (c == Float.TYPE) { |
|
return FLOAT_TYPE; |
|
} else /* if (c == Long.TYPE) */{ |
|
return LONG_TYPE; |
|
} |
|
} else { |
|
return getType(getDescriptor(c)); |
|
} |
|
} |
|
/** |
|
* Returns the Java method type corresponding to the given constructor. |
|
* |
|
* @param c |
|
* a {@link Constructor Constructor} object. |
|
* @return the Java method type corresponding to the given constructor. |
|
*/ |
|
public static Type getType(final Constructor<?> c) { |
|
return getType(getConstructorDescriptor(c)); |
|
} |
|
/** |
|
* Returns the Java method type corresponding to the given method. |
|
* |
|
* @param m |
|
* a {@link Method Method} object. |
|
* @return the Java method type corresponding to the given method. |
|
*/ |
|
public static Type getType(final Method m) { |
|
return getType(getMethodDescriptor(m)); |
|
} |
|
/** |
|
* Returns the Java types corresponding to the argument types of the given |
|
* method descriptor. |
|
* |
|
* @param methodDescriptor |
|
* a method descriptor. |
|
* @return the Java types corresponding to the argument types of the given |
|
* method descriptor. |
|
*/ |
|
public static Type[] getArgumentTypes(final String methodDescriptor) { |
|
char[] buf = methodDescriptor.toCharArray(); |
|
int off = 1; |
|
int size = 0; |
|
while (true) { |
|
char car = buf[off++]; |
|
if (car == ')') { |
|
break; |
|
} else if (car == 'L') { |
|
while (buf[off++] != ';') { |
|
} |
|
++size; |
|
} else if (car != '[') { |
|
++size; |
|
} |
|
} |
|
Type[] args = new Type[size]; |
|
off = 1; |
|
size = 0; |
|
while (buf[off] != ')') { |
|
args[size] = getType(buf, off); |
|
off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); |
|
size += 1; |
|
} |
|
return args; |
|
} |
|
/** |
|
* Returns the Java types corresponding to the argument types of the given |
|
* method. |
|
* |
|
* @param method |
|
* a method. |
|
* @return the Java types 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 Java type corresponding to the return type of the given |
|
* method descriptor. |
|
* |
|
* @param methodDescriptor |
|
* a method descriptor. |
|
* @return the Java type corresponding to the return type of the given |
|
* method descriptor. |
|
*/ |
|
public static Type getReturnType(final String methodDescriptor) { |
|
char[] buf = methodDescriptor.toCharArray(); |
|
int off = 1; |
|
while (true) { |
|
char car = buf[off++]; |
|
if (car == ')') { |
|
return getType(buf, off); |
|
} else if (car == 'L') { |
|
while (buf[off++] != ';') { |
|
} |
|
} |
|
} |
|
} |
|
/** |
|
* Returns the Java type corresponding to the return type of the given |
|
* method. |
|
* |
|
* @param method |
|
* a method. |
|
* @return the Java type corresponding to the return type of the given |
|
* method. |
|
*/ |
|
public static Type getReturnType(final Method method) { |
|
return getType(method.getReturnType()); |
|
} |
|
/** |
|
* Computes the size of the arguments and of the return value of a method. |
|
* |
|
* @param desc |
|
* the descriptor of a method. |
|
* @return the size of the arguments of the method (plus one for the |
|
* implicit this argument), argSize, and the size of its return |
|
* value, retSize, packed into a single int i = |
|
* <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to |
|
* <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). |
|
*/ |
|
public static int getArgumentsAndReturnSizes(final String desc) { |
|
int n = 1; |
|
int c = 1; |
|
while (true) { |
|
char car = desc.charAt(c++); |
|
if (car == ')') { |
|
car = desc.charAt(c); |
|
return n << 2 |
|
| (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); |
|
} else if (car == 'L') { |
|
while (desc.charAt(c++) != ';') { |
|
} |
|
n += 1; |
|
} else if (car == '[') { |
|
while ((car = desc.charAt(c)) == '[') { |
|
++c; |
|
} |
|
if (car == 'D' || car == 'J') { |
|
n -= 1; |
|
} |
|
} else if (car == 'D' || car == 'J') { |
|
n += 2; |
|
} else { |
|
n += 1; |
|
} |
|
} |
|
} |
|
/** |
|
* Returns the Java type corresponding to the given type descriptor. For |
|
* method descriptors, buf is supposed to contain nothing more than the |
|
* descriptor itself. |
|
* |
|
* @param buf |
|
* a buffer containing a type descriptor. |
|
* @param off |
|
* the offset of this descriptor in the previous buffer. |
|
* @return the Java type corresponding to the given type descriptor. |
|
*/ |
|
private static Type getType(final char[] buf, final int off) { |
|
int len; |
|
switch (buf[off]) { |
|
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 '[': |
|
len = 1; |
|
while (buf[off + len] == '[') { |
|
++len; |
|
} |
|
if (buf[off + len] == 'L') { |
|
++len; |
|
while (buf[off + len] != ';') { |
|
++len; |
|
} |
|
} |
|
return new Type(ARRAY, buf, off, len + 1); |
|
case 'L': |
|
len = 1; |
|
while (buf[off + len] != ';') { |
|
++len; |
|
} |
|
return new Type(OBJECT, buf, off + 1, len - 1); |
|
// case '(': |
|
default: |
|
return new Type(METHOD, buf, off, buf.length - off); |
|
} |
|
} |
|
// ------------------------------------------------------------------------ |
|
// Accessors |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* Returns the sort of this Java type. |
|
* |
|
* @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, |
|
* {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT}, |
|
* {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, |
|
* {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD |
|
* METHOD}. |
|
*/ |
|
public int getSort() { |
|
return 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 i = 1; |
|
while (buf[off + i] == '[') { |
|
++i; |
|
} |
|
return i; |
|
} |
|
/** |
|
* 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() { |
|
return getType(buf, off + getDimensions()); |
|
} |
|
/** |
|
* 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 sb = new StringBuilder(getElementType().getClassName()); |
|
for (int i = getDimensions(); i > 0; --i) { |
|
sb.append("[]"); |
|
} |
|
return sb.toString(); |
|
case OBJECT: |
|
return new String(buf, off, len).replace('/', '.'); |
|
default: |
|
return null; |
|
} |
|
} |
|
/** |
|
* 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 new String(buf, off, len); |
|
} |
|
/** |
|
* 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 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 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 (plus one for the implicit this |
|
* argument), argSize, and the size of the return value, retSize, |
|
* packed into a single |
|
* int i = <tt>(argSize << 2) | retSize</tt> |
|
* (argSize is therefore equal to <tt>i >> 2</tt>, |
|
* and retSize to <tt>i & 0x03</tt>). |
|
*/ |
|
public int getArgumentsAndReturnSizes() { |
|
return getArgumentsAndReturnSizes(getDescriptor()); |
|
} |
|
// ------------------------------------------------------------------------ |
|
// Conversion to type descriptors |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* Returns the descriptor corresponding to this Java type. |
|
* |
|
* @return the descriptor corresponding to this Java type. |
|
*/ |
|
public String getDescriptor() { |
|
StringBuilder buf = new StringBuilder(); |
|
getDescriptor(buf); |
|
return buf.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 buf = new StringBuilder(); |
|
buf.append('('); |
|
for (int i = 0; i < argumentTypes.length; ++i) { |
|
argumentTypes[i].getDescriptor(buf); |
|
} |
|
buf.append(')'); |
|
returnType.getDescriptor(buf); |
|
return buf.toString(); |
|
} |
|
/** |
|
* Appends the descriptor corresponding to this Java type to the given |
|
* string buffer. |
|
* |
|
* @param buf |
|
* the string buffer to which the descriptor must be appended. |
|
*/ |
|
private void getDescriptor(final StringBuilder buf) { |
|
if (this.buf == null) { |
|
// descriptor is in byte 3 of 'off' for primitive types (buf == |
|
// null) |
|
buf.append((char) ((off & 0xFF000000) >>> 24)); |
|
} else if (sort == OBJECT) { |
|
buf.append('L'); |
|
buf.append(this.buf, off, len); |
|
buf.append(';'); |
|
} else { // sort == ARRAY || sort == METHOD |
|
buf.append(this.buf, off, len); |
|
} |
|
} |
|
// ------------------------------------------------------------------------ |
|
// Direct conversion from classes to type descriptors, |
|
// without intermediate Type objects |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* 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 c |
|
* an object or array class. |
|
* @return the internal name of the given class. |
|
*/ |
|
public static String getInternalName(final Class<?> c) { |
|
return c.getName().replace('.', '/'); |
|
} |
|
/** |
|
* Returns the descriptor corresponding to the given Java type. |
|
* |
|
* @param c |
|
* an object class, a primitive class or an array class. |
|
* @return the descriptor corresponding to the given class. |
|
*/ |
|
public static String getDescriptor(final Class<?> c) { |
|
StringBuilder buf = new StringBuilder(); |
|
getDescriptor(buf, c); |
|
return buf.toString(); |
|
} |
|
/** |
|
* Returns the descriptor corresponding to the given constructor. |
|
* |
|
* @param c |
|
* a {@link Constructor Constructor} object. |
|
* @return the descriptor of the given constructor. |
|
*/ |
|
public static String getConstructorDescriptor(final Constructor<?> c) { |
|
Class<?>[] parameters = c.getParameterTypes(); |
|
StringBuilder buf = new StringBuilder(); |
|
buf.append('('); |
|
for (int i = 0; i < parameters.length; ++i) { |
|
getDescriptor(buf, parameters[i]); |
|
} |
|
return buf.append(")V").toString(); |
|
} |
|
/** |
|
* Returns the descriptor corresponding to the given method. |
|
* |
|
* @param m |
|
* a {@link Method Method} object. |
|
* @return the descriptor of the given method. |
|
*/ |
|
public static String getMethodDescriptor(final Method m) { |
|
Class<?>[] parameters = m.getParameterTypes(); |
|
StringBuilder buf = new StringBuilder(); |
|
buf.append('('); |
|
for (int i = 0; i < parameters.length; ++i) { |
|
getDescriptor(buf, parameters[i]); |
|
} |
|
buf.append(')'); |
|
getDescriptor(buf, m.getReturnType()); |
|
return buf.toString(); |
|
} |
|
/** |
|
* Appends the descriptor of the given class to the given string buffer. |
|
* |
|
* @param buf |
|
* the string buffer to which the descriptor must be appended. |
|
* @param c |
|
* the class whose descriptor must be computed. |
|
*/ |
|
private static void getDescriptor(final StringBuilder buf, final Class<?> c) { |
|
Class<?> d = c; |
|
while (true) { |
|
if (d.isPrimitive()) { |
|
char car; |
|
if (d == Integer.TYPE) { |
|
car = 'I'; |
|
} else if (d == Void.TYPE) { |
|
car = 'V'; |
|
} else if (d == Boolean.TYPE) { |
|
car = 'Z'; |
|
} else if (d == Byte.TYPE) { |
|
car = 'B'; |
|
} else if (d == Character.TYPE) { |
|
car = 'C'; |
|
} else if (d == Short.TYPE) { |
|
car = 'S'; |
|
} else if (d == Double.TYPE) { |
|
car = 'D'; |
|
} else if (d == Float.TYPE) { |
|
car = 'F'; |
|
} else /* if (d == Long.TYPE) */{ |
|
car = 'J'; |
|
} |
|
buf.append(car); |
|
return; |
|
} else if (d.isArray()) { |
|
buf.append('['); |
|
d = d.getComponentType(); |
|
} else { |
|
buf.append('L'); |
|
String name = d.getName(); |
|
int len = name.length(); |
|
for (int i = 0; i < len; ++i) { |
|
char car = name.charAt(i); |
|
buf.append(car == '.' ? '/' : car); |
|
} |
|
buf.append(';'); |
|
return; |
|
} |
|
} |
|
} |
|
// ------------------------------------------------------------------------ |
|
// Corresponding size and opcodes |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* 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 <tt>long</tt> and |
|
* <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise. |
|
*/ |
|
public int getSize() { |
|
// the size is in byte 0 of 'off' for primitive types (buf == null) |
|
return buf == null ? (off & 0xFF) : 1; |
|
} |
|
/** |
|
* Returns a JVM instruction opcode adapted to this Java 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 Java type. For example, if this type is <tt>float</tt> and |
|
* <tt>opcode</tt> is IRETURN, this method returns FRETURN. |
|
*/ |
|
public int getOpcode(final int opcode) { |
|
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { |
|
// the offset for IALOAD or IASTORE is in byte 1 of 'off' for |
|
// primitive types (buf == null) |
|
return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); |
|
} else { |
|
// the offset for other instructions is in byte 2 of 'off' for |
|
// primitive types (buf == null) |
|
return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); |
|
} |
|
} |
|
// ------------------------------------------------------------------------ |
|
// Equals, hashCode and toString |
|
// ------------------------------------------------------------------------ |
|
/** |
|
* Tests if the given object is equal to this type. |
|
* |
|
* @param o |
|
* the object to be compared to this type. |
|
* @return <tt>true</tt> if the given object is equal to this type. |
|
*/ |
|
@Override |
|
public boolean equals(final Object o) { |
|
if (this == o) { |
|
return true; |
|
} |
|
if (!(o instanceof Type)) { |
|
return false; |
|
} |
|
Type t = (Type) o; |
|
if (sort != t.sort) { |
|
return false; |
|
} |
|
if (sort >= ARRAY) { |
|
if (len != t.len) { |
|
return false; |
|
} |
|
for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { |
|
if (buf[i] != t.buf[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 hc = 13 * sort; |
|
if (sort >= ARRAY) { |
|
for (int i = off, end = i + len; i < end; i++) { |
|
hc = 17 * (hc + buf[i]); |
|
} |
|
} |
|
return hc; |
|
} |
|
/** |
|
* Returns a string representation of this type. |
|
* |
|
* @return the descriptor of this type. |
|
*/ |
|
@Override |
|
public String toString() { |
|
return getDescriptor(); |
|
} |
|
} |