/* Type Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode;
import jode.bytecode.ClassInfo;
///#ifdef JDK12
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///import java.util.Map;
///import java.util.HashMap;
///#else
import java.util.Hashtable;
///#endif
/**
* This is my type class. It differs from java.lang.class, in
* that it maintains a type range. This type range may be implicit or
* explicit.
*
*
* Think of this global type hierarchie:
*
* * tUnknown * / | \ * / | \ * tObject boolean int * / \ / \ * / tArray short char * other | * classes byte ** * int implements the "interface" tBoolInt. boolean and byte * implement the "interface" tBoolByte which extends tBoolInt.
getTop
). The
* type tUInt is * * specialization chooses the common sub type of the two types. It * is used to find the start point of the intersected interval.
* * generalization chooses the common super type of two types. It * is used to find the end point of the intersected interval.
*
* When the new interval is created with createRangeType
* the start and end points are adjusted so that they only consists of
* possible types.
*
* @author Jochen Hoenicke */
public class Type {
public static final int TC_BOOLEAN = 0;
public static final int TC_BYTE = 1;
public static final int TC_CHAR = 2;
public static final int TC_SHORT = 3;
public static final int TC_INT = 4;
public static final int TC_LONG = 5;
public static final int TC_FLOAT = 6;
public static final int TC_DOUBLE = 7;
public static final int TC_NULL = 8;
public static final int TC_ARRAY = 9;
public static final int TC_CLASS = 10;
public static final int TC_VOID = 11;
public static final int TC_METHOD = 12;
public static final int TC_ERROR = 13;
public static final int TC_UNKNOWN = 101;
public static final int TC_RANGE = 103;
public static final int TC_INTEGER = 107;
protected static JodeEnvironment env;
///#ifdef JDK12
/// private static final Map classHash = new HashMap();
/// private static final ReferenceQueue classQueue = new ReferenceQueue();
/// private static final Map arrayHash = new HashMap();
/// private static final ReferenceQueue arrayQueue = new ReferenceQueue();
///#else
private static final Hashtable classHash = new Hashtable();
private static final Hashtable arrayHash = new Hashtable();
///#endif
public static final Type tBoolean = new IntegerType(IntegerType.IT_Z);
public static final Type tByte = new IntegerType(IntegerType.IT_B);
public static final Type tChar = new IntegerType(IntegerType.IT_C);
public static final Type tShort = new IntegerType(IntegerType.IT_S);
public static final Type tInt = new IntegerType(IntegerType.IT_I);
public static final Type tLong = new Type(TC_LONG);
public static final Type tFloat = new Type(TC_FLOAT);
public static final Type tDouble = new Type(TC_DOUBLE);
public static final Type tVoid = new Type(TC_VOID);
public static final Type tError = new Type(TC_ERROR);
public static final Type tUnknown = new Type(TC_UNKNOWN);
public static final Type tUInt = new IntegerType(IntegerType.IT_I
| IntegerType.IT_B
| IntegerType.IT_C
| IntegerType.IT_S);
public static final Type tBoolInt = new IntegerType(IntegerType.IT_I
| IntegerType.IT_Z);
public static final Type tBoolUInt= new IntegerType(IntegerType.IT_I
| IntegerType.IT_B
| IntegerType.IT_C
| IntegerType.IT_S
| IntegerType.IT_Z);
public static final Type tBoolByte= new IntegerType(IntegerType.IT_B
| IntegerType.IT_Z);
public static final ClassInterfacesType tObject =
tClass("java.lang.Object");
public static final ReferenceType tNull = new NullType();
public static final Type tUObject = tRange(tObject, tNull);
public static final Type tString = tClass("java.lang.String");
public static final Type tStringBuffer = tClass("java.lang.StringBuffer");
public static final Type tJavaLangClass = tClass("java.lang.Class");
public static final Type tType(String type) {
if (type == null || type.length() == 0)
return tError;
switch(type.charAt(0)) {
case 'Z':
return tBoolean;
case 'B':
return tByte;
case 'C':
return tChar;
case 'S':
return tShort;
case 'I':
return tInt;
case 'F':
return tFloat;
case 'J':
return tLong;
case 'D':
return tDouble;
case 'V':
return tVoid;
case '[':
return tArray(tType(type.substring(1)));
case 'L':
int index = type.indexOf(';');
if (index != type.length()-1)
return tError;
return tClass(type.substring(1, index));
case '(':
return new MethodType(type);
}
throw new AssertError("Unknown type signature: "+type);
}
public static final ClassInterfacesType tClass(String clazzname) {
return tClass(ClassInfo.forName(clazzname.replace('/','.')));
}
public static final ClassInterfacesType tClass(ClassInfo clazzinfo) {
///#ifdef JDK12
/// java.lang.ref.Reference died;
/// while ((died = classQueue.poll()) != null)
/// classHash.values().remove(died);
/// WeakReference ref = (WeakReference) classHash.get(clazzinfo);
/// Object result = (ref == null) ? null : ref.get();
///#else
Object result = classHash.get(clazzinfo);
///#endif
if (result == null) {
result = new ClassInterfacesType(clazzinfo);
///#ifdef JDK12
/// classHash.put(clazzinfo, new WeakReference(result, classQueue));
///#else
classHash.put(clazzinfo, result);
///#endif
}
return (ClassInterfacesType) result;
}
public static final Type tArray(Type type) {
if (type == tError)
return type;
///#ifdef JDK12
/// java.lang.ref.Reference died;
/// while ((died = arrayQueue.poll()) != null)
/// arrayHash.values().remove(died);
/// WeakReference ref = (WeakReference) arrayHash.get(type);
/// Type result = (ref == null) ? null : (Type) ref.get();
///#else
Type result = (Type) arrayHash.get(type);
///#endif
if (result == null) {
result = new ArrayType(type);
///#ifdef JDK12
/// arrayHash.put(type, new WeakReference(result, arrayQueue));
///#else
arrayHash.put(type, result);
///#endif
}
return result;
}
public static final Type tRange(ReferenceType bottom,
ReferenceType top) {
return new RangeType(bottom, top);
}
public static Type tSuperType(Type type) {
return type.getSuperType();
}
public static Type tSubType(Type type) {
return type.getSubType();
}
public static Type tClassOrArray(String ident) {
if (ident.charAt(0) == '[')
return Type.tType(ident);
else
return Type.tClass(ident);
}
public static void setEnvironment(JodeEnvironment e) {
env = e;
}
int typecode;
/**
* Create a new type with the given type code.
*/
protected Type(int typecode) {
this.typecode = typecode;
}
public Type getSubType() {
return this;
}
public Type getSuperType() {
return this;
}
// public Type getBottom() {
// return this;
// }
// public Type getTop() {
// return this;
// }
public Type getHint() {
return this;
}
/**
* @return the type code of the type.
*/
public final int getTypeCode() {
return typecode;
}
public int stackSize()
{
switch(typecode) {
case TC_VOID:
case TC_ERROR:
return 0;
default:
return 1;
case TC_DOUBLE:
case TC_LONG:
return 2;
}
}
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (this == tError || type == tError)
return tError;
if (this == tUnknown)
return type;
if (type == tUnknown || this == type)
return this;
if (Decompiler.isTypeDebugging)
Decompiler.err.println("intersecting "+ this +" and "+ type
+ " to