new type concept

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@367 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 969c42f8f1
commit d4f444d3a4
  1. 105
      jode/jode/decompiler/Opcodes.java
  2. 37
      jode/jode/expr/ConstOperator.java
  3. 208
      jode/jode/type/ClassInterfacesType.java
  4. 135
      jode/jode/type/RangeType.java
  5. 366
      jode/jode/type/Type.java

@ -32,26 +32,19 @@ import java.util.Vector;
*/
public abstract class Opcodes implements jode.bytecode.Opcodes {
private final static Type ALL_INT_TYPE = Type.tUInt;
private final static Type BOOL_INT_TYPE = Type.tBoolInt;
private final static Type INT_TYPE = Type.tInt;
private final static Type LONG_TYPE = Type.tLong;
private final static Type FLOAT_TYPE = Type.tFloat;
private final static Type DOUBLE_TYPE = Type.tDouble;
private final static Type OBJECT_TYPE = Type.tUObject;
private final static Type BOOLEAN_TYPE = Type.tBoolean;
private final static Type BYTEBOOL_TYPE = Type.tBoolByte;
private final static Type BYTE_TYPE = Type.tByte;
private final static Type CHAR_TYPE = Type.tChar;
private final static Type SHORT_TYPE = Type.tShort;
private final static Type VOID_TYPE = Type.tVoid;
private final static Type types[][] = {
{BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE },
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE,
BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE },
{ BYTE_TYPE, CHAR_TYPE, SHORT_TYPE },
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }
// Local types
{ Type.tBoolUInt, Type.tLong, Type.tFloat, Type.tDouble,
Type.tUObject },
// Array types
{ Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject,
Type.tBoolByte, Type.tChar, Type.tShort },
// i2bcs types
{ Type.tByte, Type.tChar, Type.tShort },
// add/sub/mul/div types
{ Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject },
// and/or/xor types
{ Type.tBoolInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject }
};
private static StructuredBlock createNormal(CodeAnalyzer ca,
@ -273,58 +266,50 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
(ca, addr, 1, new EmptyBlock(new Jump(addr+1)));
case opc_aconst_null:
return createNormal
(ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null"));
case opc_iconst_0: case opc_iconst_1:
return createNormal
(ca, addr, 1, new ConstOperator
(Type.tBoolInt, Integer.toString(opcode - opc_iconst_0)));
case opc_iconst_m1: case opc_iconst_2:
(ca, addr, 1, new ConstOperator(Type.tUObject, "null"));
case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return createNormal
(ca, addr, 1, new ConstOperator
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
(ca, addr, 1, new ConstOperator(opcode - opc_iconst_0));
case opc_lconst_0: case opc_lconst_1:
return createNormal
(ca, addr, 1, new ConstOperator
(LONG_TYPE,
Integer.toString(opcode - opc_lconst_0)));
(Type.tLong, (char) (opcode + ('0'-opc_lconst_0)) + ""));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return createNormal
(ca, addr, 1, new ConstOperator
(FLOAT_TYPE,
Integer.toString(opcode - opc_fconst_0) + ".0"));
(Type.tFloat, (char) (opcode + ('0'-opc_fconst_0)) + ".0F"));
case opc_dconst_0: case opc_dconst_1:
return createNormal
(ca, addr, 1, new ConstOperator
(DOUBLE_TYPE,
Integer.toString(opcode - opc_dconst_0) + ".0"));
(Type.tDouble, (char) (opcode + ('0'-opc_dconst_0)) + ".0"));
case opc_bipush:
return createNormal
(ca, addr, 2, new ConstOperator
(ALL_INT_TYPE, Integer.toString(stream.readByte())));
case opc_sipush: {
short value = stream.readShort();
(ca, addr, 2, new ConstOperator(stream.readByte()));
case opc_sipush:
return createNormal
(ca, addr, 3, new ConstOperator
((value < Byte.MIN_VALUE || value > Byte.MAX_VALUE)
/* yes javac codes -128 with sipush :-( */
? Type.tRange(Type.tInt, Type.tChar) : ALL_INT_TYPE,
Integer.toString(value)));
}
(ca, addr, 3, new ConstOperator(stream.readShort()));
case opc_ldc: {
int index = stream.readUnsignedByte();
return createNormal
(ca, addr, 2, new ConstOperator
(cpool.getConstantType(index),
cpool.getConstantString(index)));
ConstOperator op;
if (cpool.getConstantType(index) == Type.tInt)
op = new ConstOperator(cpool.getConstantInt(index));
else
op = new ConstOperator(cpool.getConstantType(index),
cpool.getConstantString(index));
return createNormal (ca, addr, 2, op);
}
case opc_ldc_w:
case opc_ldc2_w: {
int index = stream.readUnsignedShort();
return createNormal
(ca, addr, 3, new ConstOperator
(cpool.getConstantType(index),
cpool.getConstantString(index)));
ConstOperator op;
if (cpool.getConstantType(index) == Type.tInt)
op = new ConstOperator(cpool.getConstantInt(index));
else
op = new ConstOperator(cpool.getConstantType(index),
cpool.getConstantString(index));
return createNormal(ca, addr, 3, op);
}
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
@ -410,7 +395,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
case opc_ixor: case opc_lxor:
return createNormal
(ca, addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2],
(types[4][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: {
int local = stream.readUnsignedByte();
@ -421,7 +406,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
operation = Operator.NEG_OP;
}
LocalInfo li = ca.getLocalInfo(addr, local);
li.setType(ALL_INT_TYPE);
li.setType(Type.tUInt);
return createNormal
(ca, addr, 3, new IIncOperator
(li, Integer.toString(value),
@ -442,7 +427,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
case opc_i2b: case opc_i2c: case opc_i2s:
return createNormal
(ca, addr, 1, new ConvertOperator
(ALL_INT_TYPE, types[2][opcode-opc_i2b]));
(types[3][0], types[2][opcode-opc_i2b]));
case opc_lcmp:
case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg:
@ -454,12 +439,12 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
return createIfGoto
(ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(BOOL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP)));
(Type.tBoolUInt, opcode - (opc_ifeq-Operator.COMPARE_OP)));
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return createIfGoto
(ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(ALL_INT_TYPE, opcode - (opc_ifeq-Operator.COMPARE_OP)));
(Type.tUInt, opcode - (opc_ifeq-Operator.COMPARE_OP)));
case opc_if_icmpeq: case opc_if_icmpne:
return createIfGoto
(ca, addr, 3, addr+stream.readShort(),
@ -471,13 +456,13 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
return createIfGoto
(ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(ALL_INT_TYPE,
(Type.tUInt,
opcode - (opc_if_icmpeq-Operator.COMPARE_OP)));
case opc_if_acmpeq: case opc_if_acmpne:
return createIfGoto
(ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator
(OBJECT_TYPE,
(Type.tUObject,
opcode - (opc_if_acmpeq-Operator.COMPARE_OP)));
case opc_goto:
return createGoto
@ -648,7 +633,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
operation = Operator.NEG_OP;
}
LocalInfo li = ca.getLocalInfo(addr, local);
li.setType(ALL_INT_TYPE);
li.setType(Type.tUInt);
return createNormal
(ca, addr, 6, new IIncOperator
(li, Integer.toString(value),
@ -674,7 +659,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
return createIfGoto
(ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator
(OBJECT_TYPE, opcode - (opc_ifnull-Operator.COMPARE_OP)));
(Type.tUObject, opcode - (opc_ifnull-Operator.COMPARE_OP)));
case opc_goto_w:
return createGoto
(ca, addr, 5, addr + stream.readInt());

@ -19,17 +19,44 @@
package jode.expr;
import jode.Type;
import jode.IntegerType;
public class ConstOperator extends NoArgOperator {
String value;
boolean isInitializer = false;
private static final Type tBoolConstInt
= new IntegerType(IntegerType.IT_I | IntegerType.IT_C
| IntegerType.IT_Z
| IntegerType.IT_S | IntegerType.IT_B);
public ConstOperator(Type type, String value) {
super(type);
this.value = value;
}
public ConstOperator(int value) {
super(tBoolConstInt);
this.value = Integer.toString(value);
if (value < 0 || value > 1) {
setType
((value < Short.MIN_VALUE
|| value > Character.MAX_VALUE) ? Type.tInt
: new IntegerType
((value < Byte.MIN_VALUE)
? IntegerType.IT_S|IntegerType.IT_I
: (value < 0)
? IntegerType.IT_S|IntegerType.IT_B|IntegerType.IT_I
: (value <= Byte.MAX_VALUE)
? (IntegerType.IT_S|IntegerType.IT_B
|IntegerType.IT_C|IntegerType.IT_I)
: (value <= Short.MAX_VALUE)
? IntegerType.IT_S|IntegerType.IT_C|IntegerType.IT_I
: IntegerType.IT_C|IntegerType.IT_I));
}
}
public String getValue() {
return value;
}
@ -58,7 +85,7 @@ public class ConstOperator extends NoArgOperator {
throw new jode.AssertError
("boolean is neither false nor true");
}
if (type.getBottom() == Type.tChar) {
if (type.getHint().equals(Type.tChar)) {
char c = (char) Integer.parseInt(value);
switch (c) {
case '\0':
@ -114,7 +141,9 @@ public class ConstOperator extends NoArgOperator {
return value+"L";
if (type.isOfType(Type.tFloat))
return value+"F";
if (!type.isOfType(Type.tInt) && type.isOfType(Type.tUInt)
if (!type.isOfType(Type.tInt)
&& (type.getHint().equals(Type.tByte)
|| type.getHint().equals(Type.tShort))
&& !isInitializer
&& (parent == null
|| parent.getOperator().getOperatorIndex() != ASSIGN_OP)) {
@ -123,7 +152,7 @@ public class ConstOperator extends NoArgOperator {
* But in assignments and initializers this cast is unnecessary.
* See JLS section 5.2
*/
return "("+type+") "+value;
return "("+type.getHint()+") "+value;
}
return value;

@ -73,7 +73,15 @@ public class ClassInterfacesType extends Type {
this.ifaces = ifaces;
}
static Type create(ClassInfo clazz, ClassInfo[] ifaces) {
public Type getSuperType() {
return (this == tObject) ? tObject : tRange(tObject, this);
}
public Type getSubType() {
return tRange(this, tNull);
}
static ClassInterfacesType create(ClassInfo clazz, ClassInfo[] ifaces) {
/* Make sure that every {java.lang.Object} equals tObject */
if (ifaces.length == 0 && clazz == null)
return tObject;
@ -99,16 +107,14 @@ public class ClassInterfacesType extends Type {
* @param bottom the start point of the range
* @return the range type, or tError if range is empty.
*/
public Type createRangeType(Type bottomType) {
public Type createRangeType(ClassInterfacesType bottom) {
if (bottomType == tUnknown || bottomType == tObject)
if (bottom == tObject)
return (this == tObject) ? tObject : tRange(tObject, this);
if (bottomType.typecode != TC_CLASS)
if (bottom.typecode != TC_CLASS)
return tError;
ClassInterfacesType bottom = (ClassInterfacesType) bottomType;
if (bottom.clazz != null) {
/* The searched type must be a class type.
*/
@ -181,7 +187,7 @@ public class ClassInterfacesType extends Type {
}
}
boolean implementsAllIfaces(ClassInfo[] otherIfaces) {
protected boolean implementsAllIfaces(ClassInfo[] otherIfaces) {
big:
for (int i=0; i < otherIfaces.length; i++) {
ClassInfo iface = otherIfaces[i];
@ -204,10 +210,14 @@ public class ClassInterfacesType extends Type {
*/
public Type getSpecializedType(Type type) {
int code = type.typecode;
if (code == TC_UNKNOWN)
return this;
if (code == TC_RANGE) {
type = ((RangeType) type).getBottom();
code = type.typecode;
}
if (code == TC_NULL)
return this;
if (code == TC_ARRAY)
return type.getSpecializedType(this);
return ((ArrayType) type).getSpecializedType(this);
if (code != TC_CLASS)
return tError;
@ -229,9 +239,9 @@ public class ClassInterfacesType extends Type {
else
return tError;
/* Most times (99.9999999%) one of the two classes is already
/* Most times (99.9999999 %) one of the two classes is already
* more specialized. Optimize for this case. (I know of one
* class where this doesn't succeed at one intersection)
* class where at one intersection this doesn't succeed)
*/
if (clazz == this.clazz
&& implementsAllIfaces(other.ifaces))
@ -294,10 +304,14 @@ public class ClassInterfacesType extends Type {
* implements. */
public Type getGeneralizedType(Type type) {
int code = type.typecode;
if (code == TC_UNKNOWN)
if (code == TC_RANGE) {
type = ((RangeType) type).getTop();
code = type.typecode;
}
if (code == TC_NULL)
return this;
if (code == TC_ARRAY)
return type.getGeneralizedType(this);
return ((ArrayType) type).getGeneralizedType(this);
if (code != TC_CLASS)
return tError;
ClassInterfacesType other = (ClassInterfacesType) type;
@ -388,12 +402,10 @@ public class ClassInterfacesType extends Type {
* Marks this type as used, so that the class is imported.
*/
public void useType() {
if (!jode.Decompiler.isTypeDebugging) {
if (clazz != null)
env.useClass(clazz.getName());
else if (ifaces.length > 0)
env.useClass(ifaces[0].getName());
}
if (clazz != null)
env.useClass(clazz.getName());
else if (ifaces.length > 0)
env.useClass(ifaces[0].getName());
}
public String getTypeSignature() {
@ -407,68 +419,59 @@ public class ClassInterfacesType extends Type {
public String toString()
{
if (jode.Decompiler.isTypeDebugging) {
if (this == tObject)
return "java.lang.Object";
if (ifaces.length == 0)
return clazz.getName();
if (clazz == null && ifaces.length == 1)
return ifaces[0].getName();
StringBuffer sb = new StringBuffer("{");
String comma = "";
if (clazz != null) {
sb = sb.append(clazz.getName());
comma = ", ";
}
for (int i=0; i< ifaces.length; i++) {
sb.append(comma).append(ifaces[i].getName());
if (this == tObject)
return env.classString("java.lang.Object");
if (ifaces.length == 0)
return env.classString(clazz.getName());
if (clazz == null && ifaces.length == 1)
return env.classString(ifaces[0].getName());
StringBuffer sb = new StringBuffer("{");
String comma = "";
if (clazz != null) {
sb = sb.append(clazz.getName());
comma = ", ";
}
return sb.append("}").toString();
} else {
if (clazz != null)
return env.classString(clazz.getName());
else if (ifaces.length > 0)
return env.classString(ifaces[0].getName());
else
return env.classString("java.lang.Object");
}
}
/**
* Checks if we need to cast to a middle type, before we can cast from
* fromType to this type.
* @return the middle type, or null if it is not necessary.
*/
public Type getCastHelper(Type fromType) {
Type topType = fromType.getTop();
switch (topType.getTypeCode()) {
case TC_ARRAY:
if (clazz == null
&& ArrayType.implementsAllIfaces(this.ifaces))
return null;
else
return tObject;
case TC_CLASS:
ClassInterfacesType top = (ClassInterfacesType) topType;
if (top.clazz == null || clazz == null
|| clazz.superClassOf(top.clazz)
|| top.clazz.superClassOf(clazz))
return null;
ClassInfo superClazz = clazz.getSuperclass();
while (superClazz != null
&& !superClazz.superClassOf(top.clazz)) {
superClazz = superClazz.getSuperclass();
}
return tClass(superClazz.getName());
case TC_UNKNOWN:
return null;
}
return tObject;
for (int i=0; i< ifaces.length; i++) {
sb.append(comma).append(ifaces[i].getName());
comma = ", ";
}
return sb.append("}").toString();
}
// /**
// * Checks if we need to cast to a middle type, before we can cast from
// * fromType to this type.
// * @return the middle type, or null if it is not necessary.
// */
// public Type getCastHelper(Type fromType) {
// Type topType = fromType.getTop();
// switch (topType.getTypeCode()) {
// case TC_ARRAY:
// if (clazz == null
// && ArrayType.implementsAllIfaces(this.ifaces))
// return null;
// else
// return tObject;
// case TC_CLASS:
// ClassInterfacesType top = (ClassInterfacesType) topType;
// if (top.clazz == null || clazz == null
// || clazz.superClassOf(top.clazz)
// || top.clazz.superClassOf(clazz))
// return null;
// ClassInfo superClazz = clazz.getSuperclass();
// while (superClazz != null
// && !superClazz.superClassOf(top.clazz)) {
// superClazz = superClazz.getSuperclass();
// }
// return tClass(superClazz.getName());
// case TC_UNKNOWN:
// return null;
// }
// return tObject;
// }
/**
* Checks if this type represents a valid type instead of a list
* of minimum types.
@ -503,7 +506,7 @@ public class ClassInterfacesType extends Type {
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof ClassInterfacesType) {
if (o instanceof Type && ((Type)o).typecode == TC_CLASS) {
ClassInterfacesType type = (ClassInterfacesType) o;
if (type.clazz == clazz
&& type.ifaces.length == ifaces.length) {
@ -520,4 +523,51 @@ public class ClassInterfacesType extends Type {
}
return false;
}
/**
* 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 (type == tError)
return type;
if (type == Type.tUnknown)
return this;
ClassInterfacesType top, bottom;
// if (type instanceof RangeType) {
// top = ((RangeType)type).getTop();
// bottom = ((RangeType)type).getBottom();
// } else if (type instanceof ClassInterfacesType) {
// top = bottom = (ClassInterfacesType) type;
// } else {
// Decompiler.err.println("intersecting "+ this +" and "+ type
// + " to <error>");
// if (Decompiler.isTypeDebugging)
// throw new AssertError("type error");
// return tError;
// }
Type newBottom = getSpecializedType(type);
Type newTop = getGeneralizedType(type);
Type result;
if (newTop.equals(newBottom))
result = newTop;
else if (newTop instanceof ClassInterfacesType
&& newBottom instanceof ClassInterfacesType)
result = ((ClassInterfacesType) newTop)
.createRangeType((ClassInterfacesType) newBottom);
else
result = tError;
if (result == tError) {
Decompiler.err.println("intersecting "+ this +" and "+ type
+ " to <" + newBottom + "," + newTop + ">"
+ " to <error>");
} else if (Decompiler.isTypeDebugging) {
Decompiler.err.println("intersecting "+ this +" and "+ type +
" to " + result);
}
return result;
}
}

@ -36,62 +36,79 @@ import java.util.Hashtable;
* @date 98/08/06
*/
public class RangeType extends Type {
final Type bottomType;
final Type topType;
final Type hintType;
public RangeType(Type bottomType, Type topType, Type hintType) {
super(TC_RANGE);
this.bottomType = bottomType;
this.topType = topType;
this.hintType = hintType;
}
public RangeType(Type bottomType, Type topType) {
final ClassInterfacesType bottomType;
final ClassInterfacesType topType;
// final Type hintType;
// public RangeType(Type bottomType, Type topType, Type hintType) {
// super(TC_RANGE);
// if (bottom.typecode == TC_RANGE
// || top.typecode == TC_RANGE)
// throw new AssertError("tRange("+bottom+","+top+")");
// if (top.typecode == TC_UNKNOWN)
// throw new AssertError("tRange(tUnknown, "+top+")");
// this.bottomType = bottomType;
// this.topType = topType;
// this.hintType = hintType;
// }
public RangeType(ClassInterfacesType bottomType,
ClassInterfacesType topType) {
super(TC_RANGE);
if (bottomType == tNull)
throw new jode.AssertError("bottom is NULL");
this.bottomType = bottomType;
this.topType = topType;
this.hintType = bottomType.isValidType() ? bottomType : topType;
// this.hintType = bottomType.isValidType() ? bottomType : topType;
}
public Type getBottom() {
public ClassInterfacesType getBottom() {
return bottomType;
}
public Type getTop() {
public ClassInterfacesType getTop() {
return topType;
}
public Type getHint() {
return hintType.getHint();
return topType == tNull && bottomType.equals(bottomType.getHint())
? bottomType.getHint(): topType.getHint();
}
/**
* Create the type corresponding to the range from bottomType to this.
* @param bottomType the start point of the range
* @return the range type, or tError if not possible.
*/
public Type createRangeType(Type bottomType) {
throw new AssertError("createRangeType called on RangeType");
public Type getSuperType() {
return topType.getSuperType();
}
/**
* Returns the common sub type of this and type.
* @param type the other type.
* @return the common sub type.
*/
public Type getSpecializedType(Type type) {
throw new AssertError("getSpecializedType called on RangeType");
public Type getSubType() {
return bottomType.getSubType();
}
/**
* Returns the common super type of this and type.
* @param type the other type.
* @return the common super type.
*/
public Type getGeneralizedType(Type type) {
throw new AssertError("getGeneralizedType called on RangeType");
}
// /**
// * Create the type corresponding to the range from bottomType to this.
// * @param bottomType the start point of the range
// * @return the range type, or tError if not possible.
// */
// public ClassInterfacesType createRangeType(ClassInterfacesType bottomType) {
// throw new AssertError("createRangeType called on RangeType");
// }
// /**
// * Returns the common sub type of this and type.
// * @param type the other type.
// * @return the common sub type.
// */
// public ClassInterfacesType getSpecializedType(ClassInterfacesType type) {
// throw new AssertError("getSpecializedType called on RangeType");
// }
// /**
// * Returns the common super type of this and type.
// * @param type the other type.
// * @return the common super type.
// */
// public Type getGeneralizedType(Type type) {
// throw new AssertError("getGeneralizedType called on RangeType");
// }
/**
* Marks this type as used, so that the class is imported.
@ -122,13 +139,13 @@ public class RangeType extends Type {
public String toString()
{
if (jode.Decompiler.isTypeDebugging)
return "<" + bottomType + "-" + hintType + "-" + topType + ">";
return hintType.toString();
if (topType == tNull)
return "<" + bottomType + "-NULL>";
return "<" + bottomType + "-" + topType + ">";
}
public String getDefaultName() {
return hintType.getDefaultName();
throw new AssertError("getDefaultName() not called on Hint");
}
public int hashCode() {
@ -144,4 +161,38 @@ public class RangeType extends Type {
}
return false;
}
/**
* 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 (type == tError)
return type;
if (type == Type.tUnknown)
return this;
Type top, bottom, result;
top = topType.getGeneralizedType(type);
bottom = bottomType.getSpecializedType(type);
if (top.equals(bottom))
result = top;
else if (top instanceof ClassInterfacesType
&& bottom instanceof ClassInterfacesType)
result = ((ClassInterfacesType)top)
.createRangeType((ClassInterfacesType)bottom);
else
result = tError;
if (result == tError) {
Decompiler.err.println("intersecting "+ this +" and "+ type
+ " to <" + bottom + "," + top + ">"
+ " to <error>");
} else if (Decompiler.isTypeDebugging) {
Decompiler.err.println("intersecting "+ this +" and "+ type +
" to " + result);
}
return result;
}
}

@ -35,8 +35,8 @@ import java.util.Hashtable;
* tObject boolean int
* / \ / \
* / tArray short char
* other \ /
* classes byte
* other |
* classes byte
* </pre>
*
* int implements the "interface" tBoolInt. boolean and byte
@ -86,30 +86,40 @@ public class Type {
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_BOOLBYTE = 105;
public static final int TC_BOOLINT = 106;
public static final int TC_INTEGER = 107;
protected static JodeEnvironment env;
public static final Hashtable classHash = new Hashtable();
public static final Hashtable arrayHash = new Hashtable();
public static final Type tBoolean = new Type(TC_BOOLEAN);
public static final Type tByte = new Type(TC_BYTE);
public static final Type tChar = new Type(TC_CHAR);
public static final Type tShort = new Type(TC_SHORT);
public static final Type tInt = new Type(TC_INT);
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 = tRange(tInt, tByte);
public static final Type tBoolInt = new Type(TC_BOOLINT);
public static final Type tBoolByte= new Type(TC_BOOLBYTE);
public static final Type tObject = tClass("java.lang.Object");
public static final Type tUObject = tRange(tObject, tUnknown);
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 ClassInterfacesType 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");
@ -148,14 +158,14 @@ public class Type {
}
public static final Type tClass(String clazzname) {
public static final ClassInterfacesType tClass(String clazzname) {
clazzname = clazzname.replace('/', '.');
Object result = classHash.get(clazzname);
if (result == null) {
result = new ClassInterfacesType(clazzname);
classHash.put(clazzname, result);
}
return (Type) result;
return (ClassInterfacesType) result;
}
public static final Type tArray(Type type) {
@ -169,25 +179,17 @@ public class Type {
return result;
}
public static final Type tRange(Type bottom, Type top) {
if (bottom.typecode == TC_RANGE
|| top.typecode == TC_RANGE)
throw new AssertError("tRange("+bottom+","+top+")");
public static final Type tRange(ClassInterfacesType bottom,
ClassInterfacesType top) {
return new RangeType(bottom, top);
}
public static Type tSuperType(Type type) {
if (type.getTop() == tUnknown) {
if (type == tBoolInt || type == tBoolByte)
return tBoolInt;
if (type.getBottom().typecode == TC_CLASS)
return tUObject;
}
return type.getTop().createRangeType(tUnknown);
return type.getSuperType();
}
public static Type tSubType(Type type) {
return tUnknown.createRangeType(type.getBottom());
return type.getSubType();
}
public static Type tClassOrArray(String ident) {
@ -210,14 +212,22 @@ public class Type {
this.typecode = typecode;
}
public Type getBottom() {
public Type getSubType() {
return this;
}
public Type getTop() {
return (this == tBoolByte || this == tBoolInt) ? tUnknown : this;
public Type getSuperType() {
return this;
}
// public Type getBottom() {
// return this;
// }
// public Type getTop() {
// return this;
// }
public Type getHint() {
return this;
}
@ -243,184 +253,82 @@ public class Type {
}
}
/**
* Returns the common sub type of this and type.
* @param type the other type.
* @return the common sub type.
*/
public Type getSpecializedType(Type type) {
/* tError , x -> tError
* tUnknown, x -> x
* x , x -> x
* boolean , boolint -> boolean
* byte , boolint -> byte
* boolean , boolbyte -> boolean
* byte , boolbyte -> byte
* short , boolbyte -> byte
* int , boolbyte -> byte
* byte , short -> byte
* boolint , short -> short
* boolint , boolbyte -> boolbyte
* boolbyte, short -> tError
*/
return (this == tError || type == tError) ? tError
: (this == type || type == tUnknown) ? this
: (this == tUnknown) ? type
: (typecode == TC_BOOLEAN) ?
/* TC_BOOLEAN is only compatible to TC_BOOLINT / TC_BOOLBYTE */
((type == tBoolInt || type == tBoolByte) ? this : tError)
: (typecode <= TC_INT)
/* TC_BYTE, ..., TC_INT are compatible to higher
* types and TC_BOOLINT, TC_BYTE is compatible to TC_BOOLBYTE
*/
? (( type.typecode == TC_BOOLEAN) ? tError
: (type.typecode <= typecode) ? type
: (type.typecode <= TC_INT
|| type.typecode == TC_BOOLINT) ? this
: (type == tBoolByte) ? tByte
: tError)
: (typecode == TC_BOOLINT)
/* TC_BOOLEAN,...,TC_INT all implement TC_BOOLINT
*/
? ( (type.typecode <= TC_INT
|| type.typecode == TC_BOOLBYTE) ? type : tError )
: (typecode == TC_BOOLBYTE)
/* TC_BOOLEAN, TC_BYTE implement TC_BOOLBYTE;
* TC_BYTE extend TC_SHORT, TC_INT.
* TC_BOOLBYTE extends TC_BOOLINT.
*/
? ( (type.typecode <= TC_BYTE) ? type
: (type.typecode <= TC_INT) ? tByte
: (type == tBoolInt) ? this : tError )
: tError;
}
/**
* Returns the common super type of this and type.
* @param type the other type.
* @return the common super type.
*/
public Type getGeneralizedType(Type type) {
/* Note that type can't be boolint/boolbyte (set getBottom) */
/* tError , x -> tError
* tUnknown, x -> x
* x , x -> x
* byte , short -> short
*/
return (this == tError || type == tError) ? tError
: (this == type || type == tUnknown) ? this
: (this == tUnknown) ? type
: (typecode >= TC_BYTE && typecode <= TC_INT)
/* TC_BYTE, ..., TC_INT are compatible to higher
*/
? ((type.typecode < TC_BYTE) ? tError
: (type.typecode <= typecode) ? this
: (type.typecode <= TC_INT) ? type : tError)
: tError;
}
/**
* Create the type corresponding to the range from bottomType to this.
* @param bottomType the start point of the range
* @return the range type, or tError if not possible.
*/
public Type createRangeType(Type bottomType) {
/* Note that this can't be tBoolByte or tBoolInt */
/* x , tError -> tError
* object , tUnknown -> <object, tUnknown>
* boolean , tUnknown -> boolean
* int , tUnknown -> <int, byte>
* boolint , tUnknown -> boolint
* x , x -> x
* tUnknown, boolean -> boolean
* tUnknown, short -> <int, short>
* short , byte -> <short, byte>
* byte , short -> tError
* tUnknown, float -> float
*/
return (this == tError || bottomType == tError) ? tError
: (this == bottomType) ? this
: (this == tUnknown)
? ((bottomType == tBoolInt
|| bottomType == tBoolByte
|| bottomType == tBoolean
|| bottomType == tByte ) ? bottomType
:(bottomType.typecode <= TC_INT)
? tRange(bottomType, tByte)
: tRange(bottomType, this))
: (this == tBoolean)
? ((bottomType == tBoolInt
|| bottomType == tBoolByte
|| bottomType == tUnknown) ? this : tError)
: (typecode <= TC_INT)
/* tUnknown, short -> <int, short>
* short , byte -> <short, byte>
* byte , short -> tError
* boolint , short -> <int, short>
* boolbyte, byte -> byte
* boolbyte, short -> tError
*/
? ((bottomType.typecode < typecode)
? tError
: (bottomType.typecode <= TC_INT)
? tRange(bottomType, this)
: (bottomType.typecode == TC_BOOLBYTE
&& this == tByte)
? tByte
: (bottomType.typecode == TC_BOOLINT
|| bottomType.typecode == TC_UNKNOWN)
? (this == tInt) ? tInt : tRange(tInt, this)
: tError)
: (bottomType.typecode == TC_UNKNOWN) ? this
: tError;
}
// /**
// * Returns the common sub type of this and type.
// * @param type the other type.
// * @return the common sub type.
// */
// public Type getSpecializedType(Type type) {
// /* tError , x -> tError
// * tUnknown, x -> x
// * x , x -> x
// */
// return (this == tError || type == tError) ? tError
// : (this == type || type == tUnknown) ? this
// : (this == tUnknown) ? type
// : tError;
// }
// /**
// * Returns the common super type of this and type.
// * @param type the other type.
// * @return the common super type.
// */
// public Type getGeneralizedType(Type type) {
// /* Note that type can't be boolint/boolbyte (set getBottom) */
// /* tError , x -> tError
// * tUnknown, x -> x
// * x , x -> x
// * byte , short -> short
// */
// return (this == tError || type == tError) ? tError
// : (this == type || type == tUnknown) ? this
// : (this == tUnknown) ? type
// : tError;
// }
// /**
// * Create the type corresponding to the range from bottomType to this.
// * @param bottomType the start point of the range
// * @return the range type, or tError if not possible.
// */
// public Type createRangeType(Type bottomType) {
// /* Note that this can't be tBoolByte or tBoolInt */
// /* x , tError -> tError
// * x , x -> x
// * tUnknown, x -> x
// * object , tUnknown -> <object, tUnknown>
// * int , tUnknown -> int
// * x , tUnknown -> x
// */
// return (this == tError || bottomType == tError) ? tError
// : (this == bottomType) ? this
// : (bottomType == tUnknown) ? this
// : (this == tUnknown)
// ? ((bottomType.typecode == TC_ARRAY
// || bottomType.typecode == TC_CLASS)
// ? tRange(bottomType, this)
// : bottomType)
// : tError;
// }
/**
* 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 final Type intersection(Type type) {
Type top = getTop().getGeneralizedType(type.getTop());
Type bottom = getBottom().getSpecializedType(type.getBottom());
Type result = top.createRangeType(bottom);
if (result == tError) {
boolean oldTypeDebugging = Decompiler.isTypeDebugging;
Decompiler.isTypeDebugging = true;
Decompiler.err.println("intersecting "+ this +" and "+ type
+ " to <" + bottom + "," + top + ">"
+ " to <error>");
Decompiler.isTypeDebugging = oldTypeDebugging;
if (oldTypeDebugging)
throw new AssertError("type error");
} else if (Decompiler.isTypeDebugging) {
if (this.equals(type)) {
// Decompiler.err.println("intersecting identical: "+this);
// Thread.dumpStack();
} else
Decompiler.err.println("intersecting "+ this +" and "+ type +
" to " + result);
}
return result;
public Type intersection(Type type) {
if (this == tError || type == tError)
return type;
if (this == tUnknown)
return type;
if (this == type)
return this;
Decompiler.err.println("intersecting "+ this +" and "+ type
+ " to <error>");
return tError;
}
/**
@ -437,9 +345,7 @@ public class Type {
* of minimum types.
*/
public boolean isValidType() {
return typecode <= TC_DOUBLE
|| typecode == TC_BOOLBYTE
|| typecode == TC_BOOLINT;
return typecode <= TC_DOUBLE;
}
/**
@ -454,10 +360,8 @@ public class Type {
* @param type a simple type; this mustn't be a range type.
* @return true if this is the case.
*/
public final boolean isOfType(Type type) {
return (getTop().getGeneralizedType(type.getTop()).createRangeType
(getBottom().getSpecializedType(type.getBottom())) != tError);
// return (getSpecializedType(type).equals(type));
public boolean isOfType(Type type) {
return (this == tUnknown || (this == type && this != tError));
}
/**
@ -469,18 +373,6 @@ public class Type {
public String getDefaultName() {
switch (typecode) {
case TC_BOOLINT:
case TC_BOOLBYTE:
case TC_BOOLEAN:
return "bool";
case TC_BYTE:
return "i";
case TC_CHAR:
return "c";
case TC_SHORT:
return "i";
case TC_INT:
return "i";
case TC_LONG:
return "l";
case TC_FLOAT:
@ -494,18 +386,6 @@ public class Type {
public String getTypeSignature() {
switch (typecode) {
case TC_BOOLINT:
case TC_BOOLBYTE:
case TC_BOOLEAN:
return "Z";
case TC_BYTE:
return "B";
case TC_CHAR:
return "C";
case TC_SHORT:
return "S";
case TC_INT:
return "I";
case TC_LONG:
return "J";
case TC_FLOAT:
@ -519,24 +399,6 @@ public class Type {
public String toString() {
switch (typecode) {
case TC_BOOLINT:
if (Decompiler.isTypeDebugging)
return "<bool or int>";
/* fall through */
case TC_BOOLBYTE:
if (Decompiler.isTypeDebugging)
return "<bool or byte>";
/* fall through */
case TC_BOOLEAN:
return "boolean";
case TC_BYTE:
return "byte";
case TC_CHAR:
return "char";
case TC_SHORT:
return "short";
case TC_INT:
return "int";
case TC_LONG:
return "long";
case TC_FLOAT:

Loading…
Cancel
Save