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 { 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[][] = { private final static Type types[][] = {
{BOOL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE }, // Local types
{ INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE, { Type.tBoolUInt, Type.tLong, Type.tFloat, Type.tDouble,
BYTEBOOL_TYPE, CHAR_TYPE, SHORT_TYPE }, Type.tUObject },
{ BYTE_TYPE, CHAR_TYPE, SHORT_TYPE }, // Array types
{ ALL_INT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE, OBJECT_TYPE } { 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, 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))); (ca, addr, 1, new EmptyBlock(new Jump(addr+1)));
case opc_aconst_null: case opc_aconst_null:
return createNormal return createNormal
(ca, addr, 1, new ConstOperator(OBJECT_TYPE, "null")); (ca, addr, 1, new ConstOperator(Type.tUObject, "null"));
case opc_iconst_0: case opc_iconst_1: case opc_iconst_m1:
return createNormal case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
(ca, addr, 1, new ConstOperator
(Type.tBoolInt, Integer.toString(opcode - opc_iconst_0)));
case opc_iconst_m1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
return createNormal return createNormal
(ca, addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator(opcode - opc_iconst_0));
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0)));
case opc_lconst_0: case opc_lconst_1: case opc_lconst_0: case opc_lconst_1:
return createNormal return createNormal
(ca, addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(LONG_TYPE, (Type.tLong, (char) (opcode + ('0'-opc_lconst_0)) + ""));
Integer.toString(opcode - opc_lconst_0)));
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
return createNormal return createNormal
(ca, addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(FLOAT_TYPE, (Type.tFloat, (char) (opcode + ('0'-opc_fconst_0)) + ".0F"));
Integer.toString(opcode - opc_fconst_0) + ".0"));
case opc_dconst_0: case opc_dconst_1: case opc_dconst_0: case opc_dconst_1:
return createNormal return createNormal
(ca, addr, 1, new ConstOperator (ca, addr, 1, new ConstOperator
(DOUBLE_TYPE, (Type.tDouble, (char) (opcode + ('0'-opc_dconst_0)) + ".0"));
Integer.toString(opcode - opc_dconst_0) + ".0"));
case opc_bipush: case opc_bipush:
return createNormal return createNormal
(ca, addr, 2, new ConstOperator (ca, addr, 2, new ConstOperator(stream.readByte()));
(ALL_INT_TYPE, Integer.toString(stream.readByte()))); case opc_sipush:
case opc_sipush: {
short value = stream.readShort();
return createNormal return createNormal
(ca, addr, 3, new ConstOperator (ca, addr, 3, new ConstOperator(stream.readShort()));
((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)));
}
case opc_ldc: { case opc_ldc: {
int index = stream.readUnsignedByte(); int index = stream.readUnsignedByte();
return createNormal ConstOperator op;
(ca, addr, 2, new ConstOperator if (cpool.getConstantType(index) == Type.tInt)
(cpool.getConstantType(index), op = new ConstOperator(cpool.getConstantInt(index));
cpool.getConstantString(index))); else
op = new ConstOperator(cpool.getConstantType(index),
cpool.getConstantString(index));
return createNormal (ca, addr, 2, op);
} }
case opc_ldc_w: case opc_ldc_w:
case opc_ldc2_w: { case opc_ldc2_w: {
int index = stream.readUnsignedShort(); int index = stream.readUnsignedShort();
return createNormal ConstOperator op;
(ca, addr, 3, new ConstOperator if (cpool.getConstantType(index) == Type.tInt)
(cpool.getConstantType(index), op = new ConstOperator(cpool.getConstantInt(index));
cpool.getConstantString(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_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload: 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: case opc_ixor: case opc_lxor:
return createNormal return createNormal
(ca, addr, 1, new BinaryOperator (ca, addr, 1, new BinaryOperator
(types[0][(opcode - opc_iand)%2], (types[4][(opcode - opc_iand)%2],
(opcode - opc_iand)/2 + Operator.AND_OP)); (opcode - opc_iand)/2 + Operator.AND_OP));
case opc_iinc: { case opc_iinc: {
int local = stream.readUnsignedByte(); int local = stream.readUnsignedByte();
@ -421,7 +406,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
operation = Operator.NEG_OP; operation = Operator.NEG_OP;
} }
LocalInfo li = ca.getLocalInfo(addr, local); LocalInfo li = ca.getLocalInfo(addr, local);
li.setType(ALL_INT_TYPE); li.setType(Type.tUInt);
return createNormal return createNormal
(ca, addr, 3, new IIncOperator (ca, addr, 3, new IIncOperator
(li, Integer.toString(value), (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: case opc_i2b: case opc_i2c: case opc_i2s:
return createNormal return createNormal
(ca, addr, 1, new ConvertOperator (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_lcmp:
case opc_fcmpl: case opc_fcmpg: case opc_fcmpl: case opc_fcmpg:
case opc_dcmpl: case opc_dcmpg: case opc_dcmpl: case opc_dcmpg:
@ -454,12 +439,12 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
return createIfGoto return createIfGoto
(ca, addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator 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: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle:
return createIfGoto return createIfGoto
(ca, addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator 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: case opc_if_icmpeq: case opc_if_icmpne:
return createIfGoto return createIfGoto
(ca, addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
@ -471,13 +456,13 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
return createIfGoto return createIfGoto
(ca, addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator new CompareBinaryOperator
(ALL_INT_TYPE, (Type.tUInt,
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); opcode - (opc_if_icmpeq-Operator.COMPARE_OP)));
case opc_if_acmpeq: case opc_if_acmpne: case opc_if_acmpeq: case opc_if_acmpne:
return createIfGoto return createIfGoto
(ca, addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareBinaryOperator new CompareBinaryOperator
(OBJECT_TYPE, (Type.tUObject,
opcode - (opc_if_acmpeq-Operator.COMPARE_OP))); opcode - (opc_if_acmpeq-Operator.COMPARE_OP)));
case opc_goto: case opc_goto:
return createGoto return createGoto
@ -648,7 +633,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
operation = Operator.NEG_OP; operation = Operator.NEG_OP;
} }
LocalInfo li = ca.getLocalInfo(addr, local); LocalInfo li = ca.getLocalInfo(addr, local);
li.setType(ALL_INT_TYPE); li.setType(Type.tUInt);
return createNormal return createNormal
(ca, addr, 6, new IIncOperator (ca, addr, 6, new IIncOperator
(li, Integer.toString(value), (li, Integer.toString(value),
@ -674,7 +659,7 @@ public abstract class Opcodes implements jode.bytecode.Opcodes {
return createIfGoto return createIfGoto
(ca, addr, 3, addr+stream.readShort(), (ca, addr, 3, addr+stream.readShort(),
new CompareUnaryOperator new CompareUnaryOperator
(OBJECT_TYPE, opcode - (opc_ifnull-Operator.COMPARE_OP))); (Type.tUObject, opcode - (opc_ifnull-Operator.COMPARE_OP)));
case opc_goto_w: case opc_goto_w:
return createGoto return createGoto
(ca, addr, 5, addr + stream.readInt()); (ca, addr, 5, addr + stream.readInt());

@ -19,17 +19,44 @@
package jode.expr; package jode.expr;
import jode.Type; import jode.Type;
import jode.IntegerType;
public class ConstOperator extends NoArgOperator { public class ConstOperator extends NoArgOperator {
String value; String value;
boolean isInitializer = false; 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) { public ConstOperator(Type type, String value) {
super(type); super(type);
this.value = value; 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() { public String getValue() {
return value; return value;
} }
@ -58,7 +85,7 @@ public class ConstOperator extends NoArgOperator {
throw new jode.AssertError throw new jode.AssertError
("boolean is neither false nor true"); ("boolean is neither false nor true");
} }
if (type.getBottom() == Type.tChar) { if (type.getHint().equals(Type.tChar)) {
char c = (char) Integer.parseInt(value); char c = (char) Integer.parseInt(value);
switch (c) { switch (c) {
case '\0': case '\0':
@ -114,7 +141,9 @@ public class ConstOperator extends NoArgOperator {
return value+"L"; return value+"L";
if (type.isOfType(Type.tFloat)) if (type.isOfType(Type.tFloat))
return value+"F"; 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 && !isInitializer
&& (parent == null && (parent == null
|| parent.getOperator().getOperatorIndex() != ASSIGN_OP)) { || parent.getOperator().getOperatorIndex() != ASSIGN_OP)) {
@ -123,7 +152,7 @@ public class ConstOperator extends NoArgOperator {
* But in assignments and initializers this cast is unnecessary. * But in assignments and initializers this cast is unnecessary.
* See JLS section 5.2 * See JLS section 5.2
*/ */
return "("+type+") "+value; return "("+type.getHint()+") "+value;
} }
return value; return value;

@ -73,7 +73,15 @@ public class ClassInterfacesType extends Type {
this.ifaces = ifaces; 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 */ /* Make sure that every {java.lang.Object} equals tObject */
if (ifaces.length == 0 && clazz == null) if (ifaces.length == 0 && clazz == null)
return tObject; return tObject;
@ -99,16 +107,14 @@ public class ClassInterfacesType extends Type {
* @param bottom the start point of the range * @param bottom the start point of the range
* @return the range type, or tError if range is empty. * @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); return (this == tObject) ? tObject : tRange(tObject, this);
if (bottomType.typecode != TC_CLASS) if (bottom.typecode != TC_CLASS)
return tError; return tError;
ClassInterfacesType bottom = (ClassInterfacesType) bottomType;
if (bottom.clazz != null) { if (bottom.clazz != null) {
/* The searched type must be a class type. /* 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: big:
for (int i=0; i < otherIfaces.length; i++) { for (int i=0; i < otherIfaces.length; i++) {
ClassInfo iface = otherIfaces[i]; ClassInfo iface = otherIfaces[i];
@ -204,10 +210,14 @@ public class ClassInterfacesType extends Type {
*/ */
public Type getSpecializedType(Type type) { public Type getSpecializedType(Type type) {
int code = type.typecode; int code = type.typecode;
if (code == TC_UNKNOWN) if (code == TC_RANGE) {
return this; type = ((RangeType) type).getBottom();
code = type.typecode;
}
if (code == TC_NULL)
return this;
if (code == TC_ARRAY) if (code == TC_ARRAY)
return type.getSpecializedType(this); return ((ArrayType) type).getSpecializedType(this);
if (code != TC_CLASS) if (code != TC_CLASS)
return tError; return tError;
@ -229,9 +239,9 @@ public class ClassInterfacesType extends Type {
else else
return tError; 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 * 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 if (clazz == this.clazz
&& implementsAllIfaces(other.ifaces)) && implementsAllIfaces(other.ifaces))
@ -294,10 +304,14 @@ public class ClassInterfacesType extends Type {
* implements. */ * implements. */
public Type getGeneralizedType(Type type) { public Type getGeneralizedType(Type type) {
int code = type.typecode; 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; return this;
if (code == TC_ARRAY) if (code == TC_ARRAY)
return type.getGeneralizedType(this); return ((ArrayType) type).getGeneralizedType(this);
if (code != TC_CLASS) if (code != TC_CLASS)
return tError; return tError;
ClassInterfacesType other = (ClassInterfacesType) type; ClassInterfacesType other = (ClassInterfacesType) type;
@ -388,12 +402,10 @@ public class ClassInterfacesType extends Type {
* Marks this type as used, so that the class is imported. * Marks this type as used, so that the class is imported.
*/ */
public void useType() { public void useType() {
if (!jode.Decompiler.isTypeDebugging) { if (clazz != null)
if (clazz != null) env.useClass(clazz.getName());
env.useClass(clazz.getName()); else if (ifaces.length > 0)
else if (ifaces.length > 0) env.useClass(ifaces[0].getName());
env.useClass(ifaces[0].getName());
}
} }
public String getTypeSignature() { public String getTypeSignature() {
@ -407,68 +419,59 @@ public class ClassInterfacesType extends Type {
public String toString() public String toString()
{ {
if (jode.Decompiler.isTypeDebugging) { if (this == tObject)
if (this == tObject) return env.classString("java.lang.Object");
return "java.lang.Object";
if (ifaces.length == 0)
if (ifaces.length == 0) return env.classString(clazz.getName());
return clazz.getName(); if (clazz == null && ifaces.length == 1)
if (clazz == null && ifaces.length == 1) return env.classString(ifaces[0].getName());
return ifaces[0].getName();
StringBuffer sb = new StringBuffer("{");
StringBuffer sb = new StringBuffer("{"); String comma = "";
String comma = ""; if (clazz != null) {
if (clazz != null) { sb = sb.append(clazz.getName());
sb = sb.append(clazz.getName());
comma = ", ";
}
for (int i=0; i< ifaces.length; i++) {
sb.append(comma).append(ifaces[i].getName());
comma = ", "; 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 * Checks if this type represents a valid type instead of a list
* of minimum types. * of minimum types.
@ -503,7 +506,7 @@ public class ClassInterfacesType extends Type {
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) if (o == this)
return true; return true;
if (o instanceof ClassInterfacesType) { if (o instanceof Type && ((Type)o).typecode == TC_CLASS) {
ClassInterfacesType type = (ClassInterfacesType) o; ClassInterfacesType type = (ClassInterfacesType) o;
if (type.clazz == clazz if (type.clazz == clazz
&& type.ifaces.length == ifaces.length) { && type.ifaces.length == ifaces.length) {
@ -520,4 +523,51 @@ public class ClassInterfacesType extends Type {
} }
return false; 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 * @date 98/08/06
*/ */
public class RangeType extends Type { public class RangeType extends Type {
final Type bottomType; final ClassInterfacesType bottomType;
final Type topType; final ClassInterfacesType topType;
final Type hintType; // final Type hintType;
public RangeType(Type bottomType, Type topType, Type hintType) { // public RangeType(Type bottomType, Type topType, Type hintType) {
super(TC_RANGE); // super(TC_RANGE);
this.bottomType = bottomType; // if (bottom.typecode == TC_RANGE
this.topType = topType; // || top.typecode == TC_RANGE)
this.hintType = hintType; // throw new AssertError("tRange("+bottom+","+top+")");
} // if (top.typecode == TC_UNKNOWN)
// throw new AssertError("tRange(tUnknown, "+top+")");
public RangeType(Type bottomType, Type topType) { // this.bottomType = bottomType;
// this.topType = topType;
// this.hintType = hintType;
// }
public RangeType(ClassInterfacesType bottomType,
ClassInterfacesType topType) {
super(TC_RANGE); super(TC_RANGE);
if (bottomType == tNull)
throw new jode.AssertError("bottom is NULL");
this.bottomType = bottomType; this.bottomType = bottomType;
this.topType = topType; this.topType = topType;
this.hintType = bottomType.isValidType() ? bottomType : topType; // this.hintType = bottomType.isValidType() ? bottomType : topType;
} }
public Type getBottom() { public ClassInterfacesType getBottom() {
return bottomType; return bottomType;
} }
public Type getTop() { public ClassInterfacesType getTop() {
return topType; return topType;
} }
public Type getHint() { public Type getHint() {
return hintType.getHint(); return topType == tNull && bottomType.equals(bottomType.getHint())
? bottomType.getHint(): topType.getHint();
} }
/** public Type getSuperType() {
* Create the type corresponding to the range from bottomType to this. return topType.getSuperType();
* @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 getSubType() {
* Returns the common sub type of this and type. return bottomType.getSubType();
* @param type the other type.
* @return the common sub type.
*/
public Type getSpecializedType(Type type) {
throw new AssertError("getSpecializedType called on RangeType");
} }
/** // /**
* Returns the common super type of this and type. // * Create the type corresponding to the range from bottomType to this.
* @param type the other type. // * @param bottomType the start point of the range
* @return the common super type. // * @return the range type, or tError if not possible.
*/ // */
public Type getGeneralizedType(Type type) { // public ClassInterfacesType createRangeType(ClassInterfacesType bottomType) {
throw new AssertError("getGeneralizedType called on RangeType"); // 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. * Marks this type as used, so that the class is imported.
@ -122,13 +139,13 @@ public class RangeType extends Type {
public String toString() public String toString()
{ {
if (jode.Decompiler.isTypeDebugging) if (topType == tNull)
return "<" + bottomType + "-" + hintType + "-" + topType + ">"; return "<" + bottomType + "-NULL>";
return hintType.toString(); return "<" + bottomType + "-" + topType + ">";
} }
public String getDefaultName() { public String getDefaultName() {
return hintType.getDefaultName(); throw new AssertError("getDefaultName() not called on Hint");
} }
public int hashCode() { public int hashCode() {
@ -144,4 +161,38 @@ public class RangeType extends Type {
} }
return false; 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 * tObject boolean int
* / \ / \ * / \ / \
* / tArray short char * / tArray short char
* other \ / * other |
* classes byte * classes byte
* </pre> * </pre>
* *
* int implements the "interface" tBoolInt. boolean and byte * 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_ERROR = 13;
public static final int TC_UNKNOWN = 101; public static final int TC_UNKNOWN = 101;
public static final int TC_RANGE = 103; public static final int TC_RANGE = 103;
public static final int TC_BOOLBYTE = 105; public static final int TC_INTEGER = 107;
public static final int TC_BOOLINT = 106;
protected static JodeEnvironment env; protected static JodeEnvironment env;
public static final Hashtable classHash = new Hashtable(); public static final Hashtable classHash = new Hashtable();
public static final Hashtable arrayHash = new Hashtable(); public static final Hashtable arrayHash = new Hashtable();
public static final Type tBoolean = new Type(TC_BOOLEAN); public static final Type tBoolean = new IntegerType(IntegerType.IT_Z);
public static final Type tByte = new Type(TC_BYTE); public static final Type tByte = new IntegerType(IntegerType.IT_B);
public static final Type tChar = new Type(TC_CHAR); public static final Type tChar = new IntegerType(IntegerType.IT_C);
public static final Type tShort = new Type(TC_SHORT); public static final Type tShort = new IntegerType(IntegerType.IT_S);
public static final Type tInt = new Type(TC_INT); public static final Type tInt = new IntegerType(IntegerType.IT_I);
public static final Type tLong = new Type(TC_LONG); public static final Type tLong = new Type(TC_LONG);
public static final Type tFloat = new Type(TC_FLOAT); public static final Type tFloat = new Type(TC_FLOAT);
public static final Type tDouble = new Type(TC_DOUBLE); public static final Type tDouble = new Type(TC_DOUBLE);
public static final Type tVoid = new Type(TC_VOID); public static final Type tVoid = new Type(TC_VOID);
public static final Type tError = new Type(TC_ERROR); public static final Type tError = new Type(TC_ERROR);
public static final Type tUnknown = new Type(TC_UNKNOWN); public static final Type tUnknown = new Type(TC_UNKNOWN);
public static final Type tUInt = tRange(tInt, tByte); public static final Type tUInt = new IntegerType(IntegerType.IT_I
public static final Type tBoolInt = new Type(TC_BOOLINT); | IntegerType.IT_B
public static final Type tBoolByte= new Type(TC_BOOLBYTE); | IntegerType.IT_C
public static final Type tObject = tClass("java.lang.Object"); | IntegerType.IT_S);
public static final Type tUObject = tRange(tObject, tUnknown); 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 tString = tClass("java.lang.String");
public static final Type tStringBuffer = tClass("java.lang.StringBuffer"); public static final Type tStringBuffer = tClass("java.lang.StringBuffer");
public static final Type tJavaLangClass = tClass("java.lang.Class"); 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('/', '.'); clazzname = clazzname.replace('/', '.');
Object result = classHash.get(clazzname); Object result = classHash.get(clazzname);
if (result == null) { if (result == null) {
result = new ClassInterfacesType(clazzname); result = new ClassInterfacesType(clazzname);
classHash.put(clazzname, result); classHash.put(clazzname, result);
} }
return (Type) result; return (ClassInterfacesType) result;
} }
public static final Type tArray(Type type) { public static final Type tArray(Type type) {
@ -169,25 +179,17 @@ public class Type {
return result; return result;
} }
public static final Type tRange(Type bottom, Type top) { public static final Type tRange(ClassInterfacesType bottom,
if (bottom.typecode == TC_RANGE ClassInterfacesType top) {
|| top.typecode == TC_RANGE)
throw new AssertError("tRange("+bottom+","+top+")");
return new RangeType(bottom, top); return new RangeType(bottom, top);
} }
public static Type tSuperType(Type type) { public static Type tSuperType(Type type) {
if (type.getTop() == tUnknown) { return type.getSuperType();
if (type == tBoolInt || type == tBoolByte)
return tBoolInt;
if (type.getBottom().typecode == TC_CLASS)
return tUObject;
}
return type.getTop().createRangeType(tUnknown);
} }
public static Type tSubType(Type type) { public static Type tSubType(Type type) {
return tUnknown.createRangeType(type.getBottom()); return type.getSubType();
} }
public static Type tClassOrArray(String ident) { public static Type tClassOrArray(String ident) {
@ -210,14 +212,22 @@ public class Type {
this.typecode = typecode; this.typecode = typecode;
} }
public Type getBottom() { public Type getSubType() {
return this; return this;
} }
public Type getTop() { public Type getSuperType() {
return (this == tBoolByte || this == tBoolInt) ? tUnknown : this; return this;
} }
// public Type getBottom() {
// return this;
// }
// public Type getTop() {
// return this;
// }
public Type getHint() { public Type getHint() {
return this; return this;
} }
@ -243,184 +253,82 @@ public class Type {
} }
} }
/** // /**
* Returns the common sub type of this and type. // * Returns the common sub type of this and type.
* @param type the other type. // * @param type the other type.
* @return the common sub type. // * @return the common sub type.
*/ // */
public Type getSpecializedType(Type type) { // public Type getSpecializedType(Type type) {
/* tError , x -> tError // /* tError , x -> tError
* tUnknown, x -> x // * tUnknown, x -> x
* x , x -> x // * x , x -> x
* boolean , boolint -> boolean // */
* byte , boolint -> byte // return (this == tError || type == tError) ? tError
* boolean , boolbyte -> boolean // : (this == type || type == tUnknown) ? this
* byte , boolbyte -> byte // : (this == tUnknown) ? type
* short , boolbyte -> byte // : tError;
* int , boolbyte -> byte // }
* byte , short -> byte
* boolint , short -> short // /**
* boolint , boolbyte -> boolbyte // * Returns the common super type of this and type.
* boolbyte, short -> tError // * @param type the other type.
*/ // * @return the common super type.
return (this == tError || type == tError) ? tError // */
: (this == type || type == tUnknown) ? this // public Type getGeneralizedType(Type type) {
: (this == tUnknown) ? type // /* Note that type can't be boolint/boolbyte (set getBottom) */
// /* tError , x -> tError
: (typecode == TC_BOOLEAN) ? // * tUnknown, x -> x
/* TC_BOOLEAN is only compatible to TC_BOOLINT / TC_BOOLBYTE */ // * x , x -> x
((type == tBoolInt || type == tBoolByte) ? this : tError) // * byte , short -> short
// */
: (typecode <= TC_INT)
/* TC_BYTE, ..., TC_INT are compatible to higher // return (this == tError || type == tError) ? tError
* types and TC_BOOLINT, TC_BYTE is compatible to TC_BOOLBYTE // : (this == type || type == tUnknown) ? this
*/ // : (this == tUnknown) ? type
? (( type.typecode == TC_BOOLEAN) ? tError // : tError;
: (type.typecode <= typecode) ? type // }
: (type.typecode <= TC_INT
|| type.typecode == TC_BOOLINT) ? this // /**
: (type == tBoolByte) ? tByte // * Create the type corresponding to the range from bottomType to this.
: tError) // * @param bottomType the start point of the range
// * @return the range type, or tError if not possible.
: (typecode == TC_BOOLINT) // */
/* TC_BOOLEAN,...,TC_INT all implement TC_BOOLINT // public Type createRangeType(Type bottomType) {
*/ // /* Note that this can't be tBoolByte or tBoolInt */
? ( (type.typecode <= TC_INT // /* x , tError -> tError
|| type.typecode == TC_BOOLBYTE) ? type : tError ) // * x , x -> x
// * tUnknown, x -> x
: (typecode == TC_BOOLBYTE) // * object , tUnknown -> <object, tUnknown>
/* TC_BOOLEAN, TC_BYTE implement TC_BOOLBYTE; // * int , tUnknown -> int
* TC_BYTE extend TC_SHORT, TC_INT. // * x , tUnknown -> x
* TC_BOOLBYTE extends TC_BOOLINT. // */
*/
? ( (type.typecode <= TC_BYTE) ? type // return (this == tError || bottomType == tError) ? tError
: (type.typecode <= TC_INT) ? tByte // : (this == bottomType) ? this
: (type == tBoolInt) ? this : tError ) // : (bottomType == tUnknown) ? this
// : (this == tUnknown)
: tError; // ? ((bottomType.typecode == TC_ARRAY
} // || bottomType.typecode == TC_CLASS)
// ? tRange(bottomType, this)
/** // : bottomType)
* Returns the common super type of this and type. // : tError;
* @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;
}
/** /**
* Intersect this type with another type and return the new type. * Intersect this type with another type and return the new type.
* @param type the other type. * @param type the other type.
* @return the intersection, or tError, if a type conflict happens. * @return the intersection, or tError, if a type conflict happens.
*/ */
public final Type intersection(Type type) { public Type intersection(Type type) {
if (this == tError || type == tError)
Type top = getTop().getGeneralizedType(type.getTop()); return type;
Type bottom = getBottom().getSpecializedType(type.getBottom()); if (this == tUnknown)
Type result = top.createRangeType(bottom); return type;
if (this == type)
if (result == tError) { return this;
boolean oldTypeDebugging = Decompiler.isTypeDebugging; Decompiler.err.println("intersecting "+ this +" and "+ type
Decompiler.isTypeDebugging = true; + " to <error>");
Decompiler.err.println("intersecting "+ this +" and "+ type return tError;
+ " 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;
} }
/** /**
@ -437,9 +345,7 @@ public class Type {
* of minimum types. * of minimum types.
*/ */
public boolean isValidType() { public boolean isValidType() {
return typecode <= TC_DOUBLE return typecode <= TC_DOUBLE;
|| typecode == TC_BOOLBYTE
|| typecode == TC_BOOLINT;
} }
/** /**
@ -454,10 +360,8 @@ public class Type {
* @param type a simple type; this mustn't be a range type. * @param type a simple type; this mustn't be a range type.
* @return true if this is the case. * @return true if this is the case.
*/ */
public final boolean isOfType(Type type) { public boolean isOfType(Type type) {
return (getTop().getGeneralizedType(type.getTop()).createRangeType return (this == tUnknown || (this == type && this != tError));
(getBottom().getSpecializedType(type.getBottom())) != tError);
// return (getSpecializedType(type).equals(type));
} }
/** /**
@ -469,18 +373,6 @@ public class Type {
public String getDefaultName() { public String getDefaultName() {
switch (typecode) { 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: case TC_LONG:
return "l"; return "l";
case TC_FLOAT: case TC_FLOAT:
@ -494,18 +386,6 @@ public class Type {
public String getTypeSignature() { public String getTypeSignature() {
switch (typecode) { 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: case TC_LONG:
return "J"; return "J";
case TC_FLOAT: case TC_FLOAT:
@ -519,24 +399,6 @@ public class Type {
public String toString() { public String toString() {
switch (typecode) { 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: case TC_LONG:
return "long"; return "long";
case TC_FLOAT: case TC_FLOAT:

Loading…
Cancel
Save