From d4f444d3a4ae5ab973e71140bb44befa8e332914 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 11 Mar 1999 22:51:37 +0000 Subject: [PATCH] new type concept git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@367 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/decompiler/Opcodes.java | 105 +++---- jode/jode/expr/ConstOperator.java | 37 ++- jode/jode/type/ClassInterfacesType.java | 208 +++++++++----- jode/jode/type/RangeType.java | 135 ++++++--- jode/jode/type/Type.java | 366 ++++++++---------------- 5 files changed, 414 insertions(+), 437 deletions(-) diff --git a/jode/jode/decompiler/Opcodes.java b/jode/jode/decompiler/Opcodes.java index 56c5e40..fa3056c 100644 --- a/jode/jode/decompiler/Opcodes.java +++ b/jode/jode/decompiler/Opcodes.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()); diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index a9c3e4f..bfdd581 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -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; diff --git a/jode/jode/type/ClassInterfacesType.java b/jode/jode/type/ClassInterfacesType.java index 4050611..79542c3 100644 --- a/jode/jode/type/ClassInterfacesType.java +++ b/jode/jode/type/ClassInterfacesType.java @@ -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 "); +// 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 "); + } else if (Decompiler.isTypeDebugging) { + Decompiler.err.println("intersecting "+ this +" and "+ type + + " to " + result); + } + return result; + } } diff --git a/jode/jode/type/RangeType.java b/jode/jode/type/RangeType.java index 955667c..ffe6691 100644 --- a/jode/jode/type/RangeType.java +++ b/jode/jode/type/RangeType.java @@ -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 "); + } else if (Decompiler.isTypeDebugging) { + Decompiler.err.println("intersecting "+ this +" and "+ type + + " to " + result); + } + return result; + } } diff --git a/jode/jode/type/Type.java b/jode/jode/type/Type.java index df48bb3..2979b1c 100644 --- a/jode/jode/type/Type.java +++ b/jode/jode/type/Type.java @@ -35,8 +35,8 @@ import java.util.Hashtable; * tObject boolean int * / \ / \ * / tArray short char - * other \ / - * classes byte + * other | + * classes 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_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 -> - * boolean , tUnknown -> boolean - * int , tUnknown -> - * boolint , tUnknown -> boolint - * x , x -> x - * tUnknown, boolean -> boolean - * tUnknown, short -> - * 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 -> - * short , byte -> - * byte , short -> tError - * boolint , 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 -> +// * 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 "); - 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 "); + 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 ""; - /* fall through */ - case TC_BOOLBYTE: - if (Decompiler.isTypeDebugging) - return ""; - /* 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: