mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 09:40:21 +00:00
873 lines
21 KiB
Java
873 lines
21 KiB
Java
/***
|
|
* ASM: a very small and fast Java bytecode manipulation framework
|
|
* Copyright (c) 2000-2005 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 clojure.asm;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.Method;
|
|
|
|
/**
|
|
* A Java 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 final static int VOID = 0;
|
|
|
|
/**
|
|
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int BOOLEAN = 1;
|
|
|
|
/**
|
|
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int CHAR = 2;
|
|
|
|
/**
|
|
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int BYTE = 3;
|
|
|
|
/**
|
|
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int SHORT = 4;
|
|
|
|
/**
|
|
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int INT = 5;
|
|
|
|
/**
|
|
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int FLOAT = 6;
|
|
|
|
/**
|
|
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int LONG = 7;
|
|
|
|
/**
|
|
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int DOUBLE = 8;
|
|
|
|
/**
|
|
* The sort of array reference types. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int ARRAY = 9;
|
|
|
|
/**
|
|
* The sort of object reference type. See {@link #getSort getSort}.
|
|
*/
|
|
public final static int OBJECT = 10;
|
|
|
|
/**
|
|
* The <tt>void</tt> type.
|
|
*/
|
|
public final static Type VOID_TYPE = new Type(VOID);
|
|
|
|
/**
|
|
* The <tt>boolean</tt> type.
|
|
*/
|
|
public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
|
|
|
|
/**
|
|
* The <tt>char</tt> type.
|
|
*/
|
|
public final static Type CHAR_TYPE = new Type(CHAR);
|
|
|
|
/**
|
|
* The <tt>byte</tt> type.
|
|
*/
|
|
public final static Type BYTE_TYPE = new Type(BYTE);
|
|
|
|
/**
|
|
* The <tt>short</tt> type.
|
|
*/
|
|
public final static Type SHORT_TYPE = new Type(SHORT);
|
|
|
|
/**
|
|
* The <tt>int</tt> type.
|
|
*/
|
|
public final static Type INT_TYPE = new Type(INT);
|
|
|
|
/**
|
|
* The <tt>float</tt> type.
|
|
*/
|
|
public final static Type FLOAT_TYPE = new Type(FLOAT);
|
|
|
|
/**
|
|
* The <tt>long</tt> type.
|
|
*/
|
|
public final static Type LONG_TYPE = new Type(LONG);
|
|
|
|
/**
|
|
* The <tt>double</tt> type.
|
|
*/
|
|
public final static Type DOUBLE_TYPE = new Type(DOUBLE);
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Fields
|
|
// ------------------------------------------------------------------------
|
|
|
|
/**
|
|
* The sort of this Java type.
|
|
*/
|
|
private final int sort;
|
|
|
|
/**
|
|
* A buffer containing the descriptor of this Java type. This field is only
|
|
* used for reference types.
|
|
*/
|
|
private char[] buf;
|
|
|
|
/**
|
|
* The offset of the descriptor of this Java type in {@link #buf buf}. This
|
|
* field is only used for reference types.
|
|
*/
|
|
private int off;
|
|
|
|
/**
|
|
* The length of the descriptor of this Java type.
|
|
*/
|
|
private int len;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Constructors
|
|
// ------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Constructs a primitive type.
|
|
*
|
|
* @param sort the sort of the primitive type to be constructed.
|
|
*/
|
|
private Type(final int sort){
|
|
this.sort = sort;
|
|
this.len = 1;
|
|
}
|
|
|
|
/**
|
|
* 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 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 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 {@link Type#OBJECT} type for the given internal class name.
|
|
* This is a shortcut method for <code>Type.getType("L"+name+";")</code>.
|
|
* <i>Note that opposed to {@link Type#getType(String)}, this method takes
|
|
* internal class names and not class descriptor.</i>
|
|
*
|
|
* @param name an internal class name.
|
|
* @return the the {@link Type#OBJECT} type for the given class name.
|
|
*/
|
|
public static Type getObjectType(String name){
|
|
int l = name.length();
|
|
char[] buf = new char[l + 2];
|
|
buf[0] = 'L';
|
|
buf[l + 1] = ';';
|
|
name.getChars(0, l, buf, 1);
|
|
return new Type(OBJECT, buf, 0, l + 2);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
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();
|
|
return getType(buf, methodDescriptor.indexOf(')') + 1);
|
|
}
|
|
|
|
/**
|
|
* 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());
|
|
}
|
|
|
|
/**
|
|
* Returns the Java type corresponding to the given type descriptor.
|
|
*
|
|
* @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':
|
|
default:
|
|
len = 1;
|
|
while(buf[off + len] != ';')
|
|
{
|
|
++len;
|
|
}
|
|
return new Type(OBJECT, buf, off, len + 1);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// 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} or
|
|
* {@link #OBJECT OBJECT}.
|
|
*/
|
|
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 name of the class corresponding to this type.
|
|
*
|
|
* @return the fully qualified 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:
|
|
StringBuffer b = new StringBuffer(getElementType().getClassName());
|
|
for(int i = getDimensions(); i > 0; --i)
|
|
{
|
|
b.append("[]");
|
|
}
|
|
return b.toString();
|
|
// case OBJECT:
|
|
default:
|
|
return new String(buf, off + 1, len - 2).replace('/', '.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the internal name of the class corresponding to this object type.
|
|
* The internal name of a class is its fully qualified name, where '.' are
|
|
* replaced by '/'. This method should only be used for an object type.
|
|
*
|
|
* @return the internal name of the class corresponding to this object type.
|
|
*/
|
|
public String getInternalName(){
|
|
return new String(buf, off + 1, len - 2);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Conversion to type descriptors
|
|
// ------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Returns the descriptor corresponding to this Java type.
|
|
*
|
|
* @return the descriptor corresponding to this Java type.
|
|
*/
|
|
public String getDescriptor(){
|
|
StringBuffer buf = new StringBuffer();
|
|
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){
|
|
StringBuffer buf = new StringBuffer();
|
|
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 StringBuffer buf){
|
|
switch(sort)
|
|
{
|
|
case VOID:
|
|
buf.append('V');
|
|
return;
|
|
case BOOLEAN:
|
|
buf.append('Z');
|
|
return;
|
|
case CHAR:
|
|
buf.append('C');
|
|
return;
|
|
case BYTE:
|
|
buf.append('B');
|
|
return;
|
|
case SHORT:
|
|
buf.append('S');
|
|
return;
|
|
case INT:
|
|
buf.append('I');
|
|
return;
|
|
case FLOAT:
|
|
buf.append('F');
|
|
return;
|
|
case LONG:
|
|
buf.append('J');
|
|
return;
|
|
case DOUBLE:
|
|
buf.append('D');
|
|
return;
|
|
// case ARRAY:
|
|
// case OBJECT:
|
|
default:
|
|
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, where '.' are replaced by '/'.
|
|
*
|
|
* @param c an object 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){
|
|
StringBuffer buf = new StringBuffer();
|
|
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();
|
|
StringBuffer buf = new StringBuffer();
|
|
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();
|
|
StringBuffer buf = new StringBuffer();
|
|
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 StringBuffer 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.
|
|
*
|
|
* @return the size of values of this type, i.e., 2 for <tt>long</tt> and
|
|
* <tt>double</tt>, and 1 otherwise.
|
|
*/
|
|
public int getSize(){
|
|
return sort == LONG || sort == DOUBLE ? 2 : 1;
|
|
}
|
|
|
|
/**
|
|
* Returns a JVM instruction opcode adapted to this Java type.
|
|
*
|
|
* @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)
|
|
{
|
|
switch(sort)
|
|
{
|
|
case BOOLEAN:
|
|
case BYTE:
|
|
return opcode + 5;
|
|
case CHAR:
|
|
return opcode + 6;
|
|
case SHORT:
|
|
return opcode + 7;
|
|
case INT:
|
|
return opcode;
|
|
case FLOAT:
|
|
return opcode + 2;
|
|
case LONG:
|
|
return opcode + 1;
|
|
case DOUBLE:
|
|
return opcode + 3;
|
|
// case ARRAY:
|
|
// case OBJECT:
|
|
default:
|
|
return opcode + 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(sort)
|
|
{
|
|
case VOID:
|
|
return opcode + 5;
|
|
case BOOLEAN:
|
|
case CHAR:
|
|
case BYTE:
|
|
case SHORT:
|
|
case INT:
|
|
return opcode;
|
|
case FLOAT:
|
|
return opcode + 2;
|
|
case LONG:
|
|
return opcode + 1;
|
|
case DOUBLE:
|
|
return opcode + 3;
|
|
// case ARRAY:
|
|
// case OBJECT:
|
|
default:
|
|
return opcode + 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.
|
|
*/
|
|
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 == Type.OBJECT || sort == Type.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.
|
|
*/
|
|
public int hashCode(){
|
|
int hc = 13 * sort;
|
|
if(sort == Type.OBJECT || sort == Type.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.
|
|
*/
|
|
public String toString(){
|
|
return getDescriptor();
|
|
}
|
|
}
|