From d131840eec7bd49c4059e1a65c4e51bf23669d06 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 23 Oct 1998 11:32:06 +0000 Subject: [PATCH] Much type improvements git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@58 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/Decompiler.java | 32 +++- jode/jode/bytecode/Opcodes.java | 22 ++- jode/jode/decompiler/ClassAnalyzer.java | 41 +++-- jode/jode/decompiler/CodeAnalyzer.java | 51 +++--- jode/jode/decompiler/FieldAnalyzer.java | 1 + jode/jode/decompiler/ImportHandler.java | 41 +++-- jode/jode/decompiler/LocalInfo.java | 22 ++- jode/jode/decompiler/MethodAnalyzer.java | 28 ++- jode/jode/decompiler/TabbedPrintWriter.java | 7 + jode/jode/expr/ArrayLoadOperator.java | 4 +- jode/jode/expr/ArrayStoreOperator.java | 15 +- jode/jode/expr/BinaryOperator.java | 3 +- jode/jode/expr/CompareBinaryOperator.java | 6 +- jode/jode/expr/ComplexExpression.java | 186 ++++++++++++-------- jode/jode/expr/ConstOperator.java | 23 +++ jode/jode/expr/ConstantArrayOperator.java | 4 +- jode/jode/expr/ConstructorOperator.java | 4 +- jode/jode/expr/Expression.java | 3 +- jode/jode/expr/GetFieldOperator.java | 4 +- jode/jode/expr/IIncOperator.java | 1 + jode/jode/expr/InvokeOperator.java | 25 ++- jode/jode/expr/LocalLoadOperator.java | 5 + jode/jode/expr/LocalStoreOperator.java | 12 +- jode/jode/expr/NewArrayOperator.java | 2 +- jode/jode/expr/Operator.java | 7 +- jode/jode/expr/PutFieldOperator.java | 5 +- jode/jode/expr/StoreInstruction.java | 16 +- jode/jode/type/ArrayType.java | 4 + jode/jode/type/ClassInterfacesType.java | 40 +++-- jode/jode/type/RangeType.java | 10 +- jode/jode/type/Type.java | 18 +- 31 files changed, 405 insertions(+), 237 deletions(-) diff --git a/jode/jode/Decompiler.java b/jode/jode/Decompiler.java index eceb144..da5f2d1 100644 --- a/jode/jode/Decompiler.java +++ b/jode/jode/Decompiler.java @@ -25,20 +25,34 @@ public class Decompiler { public static boolean isTypeDebugging = false; public static boolean isFlowDebugging = false; public static boolean debugInOut = false; + public static boolean debugAnalyze = false; public static boolean showLVT = false; public static boolean doChecks = false; + public static boolean immediateOutput = false; public static int importPackageLimit = 3; public static int importClassLimit = 3; + public static void usage() { + System.err.println("use: jode [-v][-imm][-debug][-analyze][-flow]" + +"[-type][-inout][-lvt][-check]" + +"[-import pkglimit clslimit]" + +" class1 [class2 ...]"); + } + public static void main(String[] params) { JodeEnvironment env = new JodeEnvironment(); - for (int i=0; i 0) writer.print(modif + " "); - writer.print((clazz.isInterface())?"interface ":"class "); + writer.print(clazz.isInterface() ? "interface " : "class "); writer.println(env.classString(clazz)); writer.tab(); Class superClazz = clazz.getSuperclass(); - if (superClazz != null && - superClazz != new Object().getClass()) { + if (superClazz != null && superClazz != Object.class) { writer.println("extends "+env.classString(superClazz)); } - Class interfaces[] = clazz.getInterfaces(); + Class[] interfaces = clazz.getInterfaces(); if (interfaces.length > 0) { writer.print("implements "); for (int i=0; i < interfaces.length; i++) { @@ -191,4 +197,3 @@ public class ClassAnalyzer implements Analyzer { } } - diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 2acad76..0ced5c7 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -24,6 +24,8 @@ import jode.flow.StructuredBlock; import jode.flow.RawTryCatchBlock; import java.util.Stack; +import java.util.Vector; +import java.util.Enumeration; import java.io.DataInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -39,6 +41,7 @@ public class CodeAnalyzer implements Analyzer { MethodAnalyzer method; public JodeEnvironment env; + Vector allLocals = new Vector(); jode.flow.VariableSet param; LocalVariableTable lvt; @@ -72,36 +75,32 @@ public class CodeAnalyzer implements Analyzer { } catch (IOException ex) { throw new ClassFormatError(ex.toString()); } - for (int addr=0; addr handlers[i + 2])) { + FlowBlock startBlock = instr[handlers[i + 0]]; - tryBlock = ((RawTryCatchBlock)tryBlock).getTryBlock(); - } - Type type = null; - if (handlers[i + 3 ] != 0) { CpoolClass cpcls = (CpoolClass) method.classAnalyzer.getConstant(handlers[i + 3]); type = Type.tClass(cpcls.getName().getString()); } - - new RawTryCatchBlock(type, tryBlock, - new Jump(instr[handlers[i + 1]]), - new Jump(instr[handlers[i + 2]])); + + instr[handlers[i + 0]] = + new RawTryCatchBlock(type, + new Jump(instr[handlers[i + 1]]), + new Jump(instr[handlers[i + 2]]) + ).chainTo(instr[handlers[i + 0]]); } + for (int addr=0; addr= - (importName.endsWith(".*") - ? Decompiler.importPackageLimit - : Decompiler.importClassLimit)) - writer.println("import "+importName+";"); + if (!importName.endsWith(".*")) { + if (vote.intValue() < Decompiler.importClassLimit) + continue; + int delim = importName.lastIndexOf("."); + Integer pkgvote = (Integer) + imports.get(importName.substring(0, delim)+".*"); + if (pkgvote.intValue() >= Decompiler.importPackageLimit) + continue; + + } else { + if (vote.intValue() < Decompiler.importPackageLimit) + continue; + } + writer.println("import "+importName+";"); } writer.println(""); } @@ -109,14 +117,19 @@ public class JodeEnvironment { if (pkgName.equals(pkg) || pkgName.equals("java.lang")) return; - Integer i = (Integer) imports.get(pkgName+".*"); - i = (i == null)? new Integer(1): new Integer(i.intValue()+1); - imports.put(pkgName+".*", i); - if (i.intValue() >= Decompiler.importPackageLimit) - return; - - i = (Integer) imports.get(name); - i = (i == null)? new Integer(1): new Integer(i.intValue()+1); + Integer i = (Integer) imports.get(name); + if (i== null) { + + i = (Integer) imports.get(pkgName+".*"); + i = (i == null)? new Integer(1): new Integer(i.intValue()+1); + imports.put(pkgName+".*", i); + if (i.intValue() >= Decompiler.importPackageLimit) + return; + + i = new Integer(1); + + } else + i = new Integer(i.intValue()+1); imports.put(name, i); } } diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index 113d6a3..c8dd9c5 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -73,10 +73,22 @@ public class LocalInfo { } else { if (this != li) { shadow = li; +// System.err.println("combining "+name+"("+type+") and " +// +li.name+"("+li.type+")"); li.setType(type); + + + boolean needTypeUpdate = !li.type.equals(type); + java.util.Enumeration enum = operators.elements(); while (enum.hasMoreElements()) { - shadow.operators.addElement(enum.nextElement()); + LocalVarOperator lvo = + (LocalVarOperator) enum.nextElement(); + if (needTypeUpdate) { +// System.err.println("updating "+lvo+" in "+((Expression)lvo).parent); + lvo.updateType(); + } + shadow.operators.addElement(lvo); } /* Clear unused fields, to allow garbage collection. @@ -151,11 +163,15 @@ public class LocalInfo { public Type setType(Type newType) { LocalInfo li = getLocalInfo(); newType = li.type.intersection(newType); +// System.err.println(getName()+" setType, new: "+newType+" old: "+li.type); if (!li.type.equals(newType)) { li.type = newType; java.util.Enumeration enum = li.operators.elements(); - while (enum.hasMoreElements()) - ((LocalVarOperator)enum.nextElement()).updateType(); + while (enum.hasMoreElements()) { + LocalVarOperator lvo = (LocalVarOperator) enum.nextElement(); +// System.err.println("updating "+lvo+" in "+((Expression)lvo).parent); + lvo.updateType(); + } } return li.type; } diff --git a/jode/jode/decompiler/MethodAnalyzer.java b/jode/jode/decompiler/MethodAnalyzer.java index b2f0b3a..4476b4f 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java +++ b/jode/jode/decompiler/MethodAnalyzer.java @@ -103,19 +103,37 @@ public class MethodAnalyzer implements Analyzer { clazz.setName("this"); offset++; } + Class[] paramTypes = isConstructor ? constr.getParameterTypes() : method.getParameterTypes(); for (int i=0; i< paramTypes.length; i++) code.getParamInfo(offset+i).setType(Type.tType(paramTypes[i])); - - // We do the code.analyze() in dumpSource, to get - // immediate output. + + Class[] exceptions = isConstructor + ? constr.getExceptionTypes() : method.getExceptionTypes(); + for (int i= 0; i< exceptions.length; i++) + env.useClass(exceptions[i]); + + if (!isConstructor) + getReturnType().useType(); + + if (!Decompiler.immediateOutput) { + if (Decompiler.isVerbose) + System.err.print((isConstructor + ? "" : method.getName())+": "); + code.analyze(); + if (Decompiler.isVerbose) + System.err.println(""); + } } public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { - if (code != null) { + if (Decompiler.immediateOutput && code != null) { + // We do the code.analyze() here, to get + // immediate output. + if (Decompiler.isVerbose) System.err.print((isConstructor ? "" : method.getName())+": "); @@ -136,7 +154,7 @@ public class MethodAnalyzer implements Analyzer { if (isConstructor) writer.print(env.classString(classAnalyzer.clazz)); else - writer.print(Type.tType(method.getReturnType()).toString() + writer.print(getReturnType().toString() + " " + method.getName()); writer.print("("); Class[] paramTypes = isConstructor diff --git a/jode/jode/decompiler/TabbedPrintWriter.java b/jode/jode/decompiler/TabbedPrintWriter.java index 38aa167..475fb25 100644 --- a/jode/jode/decompiler/TabbedPrintWriter.java +++ b/jode/jode/decompiler/TabbedPrintWriter.java @@ -33,6 +33,13 @@ public class TabbedPrintWriter { atbol = true; } + public TabbedPrintWriter (Writer os, String tabstr) { + pw = new PrintWriter(os); + this.tabstr=tabstr; + indent = new StringBuffer(); + atbol = true; + } + public void tab() { indent.append(tabstr); } diff --git a/jode/jode/expr/ArrayLoadOperator.java b/jode/jode/expr/ArrayLoadOperator.java index e1fe934..602edf5 100644 --- a/jode/jode/expr/ArrayLoadOperator.java +++ b/jode/jode/expr/ArrayLoadOperator.java @@ -48,7 +48,9 @@ public class ArrayLoadOperator extends SimpleOperator { public void setOperandType(Type[] t) { super.setOperandType(t); - if (operandTypes[0] instanceof ArrayType) + if (operandTypes[0] == Type.tError) + type = Type.tError; + else if (operandTypes[0] instanceof ArrayType) type = type.intersection (((ArrayType)operandTypes[0]).getElementType()); else diff --git a/jode/jode/expr/ArrayStoreOperator.java b/jode/jode/expr/ArrayStoreOperator.java index 4f76de6..d47a7b1 100644 --- a/jode/jode/expr/ArrayStoreOperator.java +++ b/jode/jode/expr/ArrayStoreOperator.java @@ -47,15 +47,6 @@ public class ArrayStoreOperator extends StoreInstruction { return 0; } - /** - * Sets the type of the lvalue (and rvalue). - * @return true since the operand types changed - */ - public boolean setLValueType(Type type) { - this.lvalueType = type; - return true; - } - public Type getLValueOperandType(int i) { if (i == 0) return Type.tArray(lvalueType); @@ -66,10 +57,10 @@ public class ArrayStoreOperator extends StoreInstruction { public void setLValueOperandType(Type[] t) { indexType = indexType.intersection(t[1]); Type arrayType = t[0].intersection(Type.tArray(lvalueType)); - if (arrayType instanceof ArrayType) + if (arrayType == Type.tError) + lvalueType = Type.tError; + else lvalueType = ((ArrayType)arrayType).getElementType(); - else - throw new AssertError("No Array type: "+arrayType); } public String getLValueString(String[] operands) { diff --git a/jode/jode/expr/BinaryOperator.java b/jode/jode/expr/BinaryOperator.java index 651dfef..8355f96 100644 --- a/jode/jode/expr/BinaryOperator.java +++ b/jode/jode/expr/BinaryOperator.java @@ -66,8 +66,7 @@ public class BinaryOperator extends Operator { public void setOperandType(Type[] inputTypes) { operandType = operandType - .intersection(inputTypes[0]) - .intersection(inputTypes[1]); + .intersection(inputTypes[0]).intersection(inputTypes[1]); type = operandType; } diff --git a/jode/jode/expr/CompareBinaryOperator.java b/jode/jode/expr/CompareBinaryOperator.java index a6c2e17..d898f12 100644 --- a/jode/jode/expr/CompareBinaryOperator.java +++ b/jode/jode/expr/CompareBinaryOperator.java @@ -45,10 +45,8 @@ public class CompareBinaryOperator extends SimpleOperator { public void setOperandType(Type[] inputTypes) { super.setOperandType(inputTypes); - Type operandType = - Type.tSubType(Type.tSuperType(operandTypes[0]) - .intersection(Type.tSuperType(operandTypes[1]))); - operandTypes[0] = operandTypes[1] = operandType; + operandTypes[0] = operandTypes[1] = + operandTypes[0].intersection(operandTypes[1]); } public boolean equals(Object o) { diff --git a/jode/jode/expr/ComplexExpression.java b/jode/jode/expr/ComplexExpression.java index 9ec91a3..0ca22e7 100644 --- a/jode/jode/expr/ComplexExpression.java +++ b/jode/jode/expr/ComplexExpression.java @@ -25,24 +25,16 @@ public class ComplexExpression extends Expression { public ComplexExpression(Operator op, Expression[] sub) { super(Type.tUnknown); + if (sub.length != op.getOperandCount()) + throw new AssertError ("Operand count mismatch: "+ + sub.length + " != " + + op.getOperandCount()); operator = op; operator.parent = this; subExpressions = sub; - operator.setExpression(this); - if (subExpressions.length != op.getOperandCount()) - throw new AssertError ("Operand count mismatch: "+ - subExpressions.length + " != " + - op.getOperandCount()); - if (subExpressions.length > 0) { - Type types[] = new Type[subExpressions.length]; - for (int i=0; i < types.length; i++) { - subExpressions[i].parent = this; - types[i] = subExpressions[i].getType(); - } - operator.setOperandType(types); - updateSubTypes(); - } - this.type = operator.getType(); + for (int i=0; i< subExpressions.length; i++) + subExpressions[i].parent = this; + updateType(); } public int getOperandCount() { @@ -74,8 +66,7 @@ public class ComplexExpression extends Expression { Operator negop = new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP); - Expression[] e = { this }; - return new ComplexExpression(negop, e); + return new ComplexExpression(negop, new Expression[] { this }); } public Expression tryToCombine(Expression e) { @@ -118,18 +109,49 @@ public class ComplexExpression extends Expression { void updateSubTypes() { for (int i=0; i < subExpressions.length; i++) { - subExpressions[i].setType(operator.getOperandType(i)); + if (i == 0 && operator instanceof ArrayStoreOperator) { + /* No rule without exception: + * We can always use tSubType, except for the + * array operand of an array store instruction. + */ + subExpressions[i].setType(operator.getOperandType(i)); + } else + subExpressions[i].setType + (Type.tSubType(operator.getOperandType(i))); } } public void updateType() { - updateSubTypes(); if (subExpressions.length > 0) { Type types[] = new Type[subExpressions.length]; - for (int i=0; i < types.length; i++) { - types[i] = subExpressions[i].getType(); + while (true) { + boolean changed = false; + updateSubTypes(); + for (int i=0; i < types.length; i++) { + if (i == 0 && operator instanceof ArrayStoreOperator) { + /* No rule without exception: + * We can always use tSuperType, except for the + * array operand of an array store instruction. + */ + types[i] = subExpressions[i].getType(); + } else + types[i] = Type.tSuperType + (subExpressions[i].getType()); + types[i] = + types[i].intersection(operator.getOperandType(i)); + if (!types[i].equals(operator.getOperandType(i))) { + if (Decompiler.isTypeDebugging) + System.err.println("change in "+this+": " + +operator.getOperandType(i) + +"->"+types[i]); + changed = true; + } + } + if (changed) + operator.setOperandType(types); + else + break; } - operator.setOperandType(types); } setType(operator.getType()); } @@ -140,6 +162,8 @@ public class ComplexExpression extends Expression { type = newType; operator.setType(type); updateSubTypes(); + if (parent != null) + parent.updateType(); } } @@ -151,14 +175,22 @@ public class ComplexExpression extends Expression { String[] expr = new String[subExpressions.length]; for (int i=0; i") + + operator.getOperandType(i)+") "+expr[i]; + if (700 < operator.getOperandPriority(i)) + expr[i] = "(" + expr[i] + ")"; + } + else if (subExpressions[i].getType() == Type.tError) + expr[i] = "(/*type error */" + expr[i]+")"; } - String result = operator.toString(expr); - if (Decompiler.isTypeDebugging) - result = "("+operator.getType()+") ("+result+")"; - else if (operator.getType() == Type.tError) - result = "(/*type error */" + result+")"; - return result; + return operator.toString(expr); } public boolean equals(Object o) { @@ -186,6 +218,7 @@ public class ComplexExpression extends Expression { if (operator instanceof InvokeOperator && ((field = ((InvokeOperator)operator).getField()) .getCpoolClass().getName().getString() + .replace(java.io.File.separatorChar, '.') .equals("java.lang.StringBuffer")) && !((InvokeOperator)operator).isStatic() && field.getNameAndType().getName().getString().equals("append") && @@ -199,9 +232,9 @@ public class ComplexExpression extends Expression { subExpressions[1].getType().isOfType(Type.tString)) return subExpressions[1]; - Expression[] exprs = { e, - (Expression)subExpressions[1].simplify() }; - return new ComplexExpression(new StringAddOperator(), exprs); + return new ComplexExpression + (new StringAddOperator(), new Expression[] + { e, (Expression)subExpressions[1].simplify() }); } if (operator instanceof ConstructorOperator && operator.getType().isOfType(Type.tStringBuffer)) { @@ -224,45 +257,51 @@ public class ComplexExpression extends Expression { (ConstOperator) subExpressions[1].getOperator(); ConstOperator c2 = (ConstOperator) subExpressions[2].getOperator(); - if (c1.getValue().equals("true") && - c2.getValue().equals("false")) + if (c1.getValue().equals("1") && + c2.getValue().equals("0")) return subExpressions[0].simplify(); - if (c2.getValue().equals("true") && - c1.getValue().equals("false")) + if (c2.getValue().equals("1") && + c1.getValue().equals("0")) return subExpressions[0].negate().simplify(); } } -// if ((operator instanceof AssignOperator || -// operator instanceof StoreInstruction) && -// subExpressions[subExpressions.length-1] -// .operator instanceof ConstOperator) { -// StoreInstruction store; -// if (operator instanceof AssignOperator) -// store = ((AssignOperator)operator).getStore(); -// else -// store = (StoreInstruction)operator; + else if ((operator instanceof AssignOperator || + operator instanceof StoreInstruction) && + subExpressions[subExpressions.length-1] + .getOperator() instanceof ConstOperator) { + + StoreInstruction store; + if (operator instanceof AssignOperator) + store = ((AssignOperator)operator).getStore(); + else + store = (StoreInstruction)operator; + + ConstOperator one = (ConstOperator) + subExpressions[subExpressions.length-1].getOperator(); -// ConstOperator one = (ConstOperator) -// subExpressions[subExpressions.length-1].operator; + if ((operator.getOperatorIndex() == + operator.OPASSIGN_OP+operator.ADD_OP || + operator.getOperatorIndex() == + operator.OPASSIGN_OP+operator.NEG_OP) && + (one.getValue().equals("1") || + one.getValue().equals("-1"))) { -// if ((operator.getOperatorIndex() == -// operator.OPASSIGN_OP+operator.ADD_OP || -// operator.getOperatorIndex() == -// operator.OPASSIGN_OP+operator.NEG_OP) && -// (one.getValue().equals("1") || -// one.getValue().equals("-1"))) { + int op = ((operator.getOperatorIndex() == + operator.OPASSIGN_OP+operator.ADD_OP) == + one.getValue().equals("1"))? + operator.INC_OP : operator.DEC_OP; -// int op = ((operator.getOperatorIndex() == -// operator.OPASSIGN_OP+operator.ADD_OP) == -// one.getValue().equals("1"))? -// operator.INC_OP : operator.DEC_OP; + Operator ppfixop = new PrePostFixOperator + (store.getLValueType(), op, store, + operator instanceof StoreInstruction); + if (subExpressions.length == 1) + return ppfixop.simplify(); -// return new PostFixOperator -// (store.getType(), op, store, -// operator instanceof StoreInstruction).simplify(); -// } -// } - if (operator instanceof CompareUnaryOperator && + operator = ppfixop; + ppfixop.parent = this; + } + } + else if (operator instanceof CompareUnaryOperator && subExpressions[0].getOperator() instanceof CompareToIntOperator) { CompareBinaryOperator newOp = new CompareBinaryOperator @@ -277,7 +316,7 @@ public class ComplexExpression extends Expression { } else return newOp.simplify(); } - if (operator instanceof CompareUnaryOperator && + else if (operator instanceof CompareUnaryOperator && operator.getOperandType(0).isOfType(Type.tBoolean)) { /* xx == false */ if (operator.getOperatorIndex() == operator.EQUALS_OP) @@ -286,42 +325,39 @@ public class ComplexExpression extends Expression { if (operator.getOperatorIndex() == operator.NOTEQUALS_OP) return subExpressions[0].simplify(); } - - if (operator instanceof InvokeOperator + else if (operator instanceof InvokeOperator && (((InvokeOperator)operator).getField() .getNameAndType().getName().getString().equals("toString")) && !((InvokeOperator)operator).isStatic() && (((InvokeOperator)operator).getField() .getCpoolClass().getName().getString() + .replace(java.io.File.separatorChar, '.') .equals("java.lang.StringBuffer")) && subExpressions.length == 1) { Instruction simple = subExpressions[0].simplifyStringBuffer(); if (simple != null) return simple; } - if (operator instanceof InvokeOperator + else if (operator instanceof InvokeOperator && (((InvokeOperator)operator).getField() .getNameAndType().getName().getString().equals("valueOf")) && ((InvokeOperator)operator).isStatic() && (((InvokeOperator)operator).getField() .getCpoolClass().getName().getString() + .replace(java.io.File.separatorChar, '.') .equals("java.lang.String")) && subExpressions.length == 1) { if (subExpressions[0].getType() == Type.tString) return subExpressions[0].simplify(); - else { - Expression[] exprs = { - emptyString, - (Expression) subExpressions[0].simplify() - }; - return new ComplexExpression(new StringAddOperator(), exprs); - } + + return new ComplexExpression + (new StringAddOperator(), new Expression[] + { emptyString, (Expression) subExpressions[0].simplify() }); } for (int i=0; i< subExpressions.length; i++) { subExpressions[i] = (Expression) subExpressions[i].simplify(); subExpressions[i].parent = this; } - return this; } } diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index ed280d5..f613ef9 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -46,6 +46,29 @@ public class ConstOperator extends NoArgOperator { return "false"; else if (value.equals("1")) return "true"; + } else if (parent != null) { + int opindex = parent.getOperator().getOperatorIndex(); + if (opindex >= OPASSIGN_OP + ADD_OP + && opindex < OPASSIGN_OP + ASSIGN_OP) + opindex -= OPASSIGN_OP; + + if (opindex >= AND_OP && opindex < AND_OP + 3) { + /* For bit wise and/or/xor change representation. + */ + if (type.isOfType(Type.tUInt)) { + int i = Integer.parseInt(value); + if (i < -1) + return "~0x"+Integer.toHexString(-i-1); + else + return "0x"+Integer.toHexString(i); + } else if (type.equals(Type.tLong)) { + long l = Long.parseLong(value); + if (l < -1) + return "~0x"+Long.toHexString(-l-1); + else + return "0x"+Long.toHexString(l); + } + } } return value; } diff --git a/jode/jode/expr/ConstantArrayOperator.java b/jode/jode/expr/ConstantArrayOperator.java index f1351e6..00cbac0 100644 --- a/jode/jode/expr/ConstantArrayOperator.java +++ b/jode/jode/expr/ConstantArrayOperator.java @@ -24,7 +24,7 @@ public class ConstantArrayOperator extends SimpleOperator { public ConstantArrayOperator(Type type, int size) { super(type, 0, size); for (int i=0; i< size; i++) - operandTypes[i] = Type.tSubType(((ArrayType)type).getElementType()); + operandTypes[i] = ((ArrayType)type).getElementType(); } public int getPriority() { @@ -37,7 +37,7 @@ public class ConstantArrayOperator extends SimpleOperator { public String toString(String[] operands) { StringBuffer result - = new StringBuffer("{"); + = new StringBuffer("new "+type+" {"); for (int i=0; i< getOperandCount(); i++) { if (i>0) result.append(", "); diff --git a/jode/jode/expr/ConstructorOperator.java b/jode/jode/expr/ConstructorOperator.java index 980ef61..5bea45e 100644 --- a/jode/jode/expr/ConstructorOperator.java +++ b/jode/jode/expr/ConstructorOperator.java @@ -48,8 +48,8 @@ public class ConstructorOperator extends Operator { public Type getOperandType(int i) { if (i == 0) - return Type.tSubType(type); - return Type.tSubType(methodType.getArgumentTypes()[i-1]); + return type; + return methodType.getArgumentTypes()[i-1]; } public void setOperandType(Type types[]) { diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index 67ec520..ed74b50 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -36,8 +36,7 @@ public abstract class Expression extends Instruction { public Expression negate() { Operator negop = new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP); - Expression[] e = { this }; - return new ComplexExpression(negop, e); + return new ComplexExpression(negop, new Expression[] { this }); } public Expression tryToCombine(Expression e) { diff --git a/jode/jode/expr/GetFieldOperator.java b/jode/jode/expr/GetFieldOperator.java index 614df64..2dfc84c 100644 --- a/jode/jode/expr/GetFieldOperator.java +++ b/jode/jode/expr/GetFieldOperator.java @@ -54,8 +54,8 @@ public class GetFieldOperator extends Operator { /* shouldn't be called */ throw new RuntimeException("Field is static"); } - return Type.tSubType(Type.tClass(field.getCpoolClass() - .getName().getString())); + return Type.tClass(field.getCpoolClass() + .getName().getString()); } public void setOperandType(Type types[]) { diff --git a/jode/jode/expr/IIncOperator.java b/jode/jode/expr/IIncOperator.java index ac0ae3b..e53509a 100644 --- a/jode/jode/expr/IIncOperator.java +++ b/jode/jode/expr/IIncOperator.java @@ -28,6 +28,7 @@ implements LocalVarOperator { super(Type.tVoid, operator); this.local = local; this.value = value; + local.setType(Type.tUInt); local.setOperator(this); } diff --git a/jode/jode/expr/InvokeOperator.java b/jode/jode/expr/InvokeOperator.java index 341c07a..1113d0c 100644 --- a/jode/jode/expr/InvokeOperator.java +++ b/jode/jode/expr/InvokeOperator.java @@ -75,10 +75,10 @@ public final class InvokeOperator extends Operator { public Type getOperandType(int i) { if (!staticFlag) { if (i == 0) - return Type.tSubType(getClassType()); + return getClassType(); i--; } - return Type.tSubType(methodType.getArgumentTypes()[i]); + return methodType.getArgumentTypes()[i]; } public void setOperandType(Type types[]) { @@ -97,19 +97,14 @@ public final class InvokeOperator extends Operator { ? "" : codeAnalyzer.getTypeString(getClassType())) : (operands[0].equals("this") - ? (specialFlag - ? ( (field.getCpoolClass().getName().getString() - .replace(java.io.File.separatorChar, '.') - .equals(codeAnalyzer.getClazz() - .getSuperclass().getName())) - ? "super" - : "((" + codeAnalyzer.getTypeString(getClassType()) - + ") this)" ) - : "") - : (specialFlag - ? "((" + codeAnalyzer.getTypeString(getClassType()) - + ") " + operands[0]+")" - : operands[0] )); + ? ((specialFlag && + (field.getCpoolClass().getName().getString() + .replace(java.io.File.separatorChar, '.') + .equals(codeAnalyzer.getClazz() + .getSuperclass().getName()))) + ? "super" + : "") + : operands[0]); int arg = staticFlag ? 0 : 1; String method; diff --git a/jode/jode/expr/LocalLoadOperator.java b/jode/jode/expr/LocalLoadOperator.java index 8e4d9ed..fb74613 100644 --- a/jode/jode/expr/LocalLoadOperator.java +++ b/jode/jode/expr/LocalLoadOperator.java @@ -26,6 +26,7 @@ implements LocalVarOperator { public LocalLoadOperator(Type type, LocalInfo local) { super(type, ""); this.local = local; + local.setType(type); local.setOperator(this); } @@ -47,6 +48,10 @@ implements LocalVarOperator { } public void updateType() { + if (Decompiler.isTypeDebugging) + System.err.println("local "+local.getName()+" changed: " + +type+" to "+local.getType() + +" in "+parent); super.setType(local.getType()); if (parent != null) parent.updateType(); diff --git a/jode/jode/expr/LocalStoreOperator.java b/jode/jode/expr/LocalStoreOperator.java index eceefdd..4c8fce9 100644 --- a/jode/jode/expr/LocalStoreOperator.java +++ b/jode/jode/expr/LocalStoreOperator.java @@ -26,6 +26,7 @@ implements LocalVarOperator { public LocalStoreOperator(Type lvalueType, LocalInfo local, int operator) { super(lvalueType, operator); this.local = local; + local.setType(lvalueType); local.setOperator(this); } @@ -47,20 +48,13 @@ implements LocalVarOperator { } public Type getLValueType() { -// System.err.println("LocalStore.getType of "+local.getName()+": "+local.getType()); return local.getType(); } - public boolean setLValueType(Type type) { -// System.err.println("LocalStore.setType of "+local.getName()+": "+local.getType()); - return super.setLValueType - (local.setType(Type.tSuperType(type))); + public void setLValueType(Type type) { + local.setType(type); } -// public int getSlot() { -// return slot; -// } - public boolean matches(Operator loadop) { return loadop instanceof LocalLoadOperator && ((LocalLoadOperator)loadop).getLocalInfo().getLocalInfo() diff --git a/jode/jode/expr/NewArrayOperator.java b/jode/jode/expr/NewArrayOperator.java index c35b4ae..e9ce4f5 100644 --- a/jode/jode/expr/NewArrayOperator.java +++ b/jode/jode/expr/NewArrayOperator.java @@ -25,7 +25,7 @@ public class NewArrayOperator extends SimpleOperator { public NewArrayOperator(Type arrayType, int dimensions) { super(arrayType, 0, dimensions); for (int i=0; i< dimensions; i++) { - operandTypes[i] = Type.tInt; + operandTypes[i] = Type.tUInt; } } diff --git a/jode/jode/expr/Operator.java b/jode/jode/expr/Operator.java index 1deb0c2..637c9d0 100644 --- a/jode/jode/expr/Operator.java +++ b/jode/jode/expr/Operator.java @@ -45,8 +45,7 @@ public abstract class Operator extends Expression { }; protected int operator; - protected Expression expression = null; - + Operator (Type type, int op) { super(type); this.operator = op; @@ -54,10 +53,6 @@ public abstract class Operator extends Expression { throw new AssertError("type == null"); } - public void setExpression(Expression expr) { - expression = expr; - } - public Operator getOperator() { return this; } diff --git a/jode/jode/expr/PutFieldOperator.java b/jode/jode/expr/PutFieldOperator.java index 97c6743..fce0e3d 100644 --- a/jode/jode/expr/PutFieldOperator.java +++ b/jode/jode/expr/PutFieldOperator.java @@ -55,8 +55,8 @@ public class PutFieldOperator extends StoreInstruction { /* shouldn't be called */ throw new AssertError("Field is static"); } - return Type.tSubType(Type.tClass(field.getCpoolClass() - .getName().getString())); + return Type.tClass(field.getCpoolClass() + .getName().getString()); } public void setLValueOperandType(Type[] t) { @@ -71,6 +71,7 @@ public class PutFieldOperator extends StoreInstruction { String object; if (staticFlag) { if (field.getCpoolClass().getName().getString() + .replace(java.io.File.separatorChar, '.') .equals(codeAnalyzer.getClazz().getName())) return field.getNameAndType().getName().getString(); object = codeAnalyzer.getTypeString diff --git a/jode/jode/expr/StoreInstruction.java b/jode/jode/expr/StoreInstruction.java index 41b75f2..6fa1111 100644 --- a/jode/jode/expr/StoreInstruction.java +++ b/jode/jode/expr/StoreInstruction.java @@ -26,7 +26,7 @@ public abstract class StoreInstruction extends Operator { public StoreInstruction(Type type, int operator) { super(Type.tVoid, operator); - lvalueType = Type.tSubType(type); + lvalueType = type; lvCasts = lvalueType.toString(); } @@ -42,11 +42,9 @@ public abstract class StoreInstruction extends Operator { /** * Sets the type of the lvalue (and rvalue). - * @return true if the operand types changed */ - public boolean setLValueType(Type type) { - this.lvalueType = type; - return false; + public void setLValueType(Type type) { + lvalueType = lvalueType.intersection(type); } public abstract String getLValueString(String[] operands); @@ -64,16 +62,16 @@ public abstract class StoreInstruction extends Operator { public Type getOperandType(int i) { if (i == getLValueOperandCount()) - return Type.tSubType(getLValueType()); + return getLValueType(); else return getLValueOperandType(i); } public void setOperandType(Type[] t) { - if (getLValueOperandCount() > 0) + int count = getLValueOperandCount(); + if (count > 0) setLValueOperandType(t); - setLValueType(lvalueType.intersection - (Type.tSuperType(t[getLValueOperandCount()]))); + setLValueType(t[count]); } public int getOperandCount() { diff --git a/jode/jode/type/ArrayType.java b/jode/jode/type/ArrayType.java index b35c12a..785413b 100644 --- a/jode/jode/type/ArrayType.java +++ b/jode/jode/type/ArrayType.java @@ -101,6 +101,10 @@ public class ArrayType extends Type { : tError; } + public boolean isClassType() { + return elementType.isClassType(); + } + /** * Marks this type as used, so that the class is imported. */ diff --git a/jode/jode/type/ClassInterfacesType.java b/jode/jode/type/ClassInterfacesType.java index 242eca5..5a32839 100644 --- a/jode/jode/type/ClassInterfacesType.java +++ b/jode/jode/type/ClassInterfacesType.java @@ -37,16 +37,15 @@ public class ClassInterfacesType extends Type { Class clazz; Class ifaces[]; - public final static Class cObject = new Object().getClass(); + public final static Class cObject = Object.class; public ClassInterfacesType(String clazzName) { super(TC_CLASS); try { Class clazz = Class.forName(clazzName); if (clazz.isInterface()) { - this.clazz = cObject; - ifaces = new Class[1]; - ifaces[0] = clazz; + this.clazz = null; + ifaces = new Class[] {clazz}; } else { this.clazz = clazz; ifaces = new Class[0]; @@ -59,9 +58,8 @@ public class ClassInterfacesType extends Type { public ClassInterfacesType(Class clazz) { super(TC_CLASS); if (clazz.isInterface()) { - this.clazz = cObject; - ifaces = new Class[1]; - ifaces[0] = clazz; + this.clazz = null; + ifaces = new Class[] { clazz }; } else { this.clazz = clazz; ifaces = new Class[0]; @@ -172,8 +170,7 @@ public class ClassInterfacesType extends Type { && bottom.ifaces[0] == ifaces.elementAt(0)) return bottom; - Class[] ifaceArray = - new Class[ifaces.size()]; + Class[] ifaceArray = new Class[ifaces.size()]; ifaces.copyInto(ifaceArray); return tRange(bottom, create(clazz, ifaceArray)); } @@ -322,8 +319,9 @@ public class ClassInterfacesType extends Type { iface_loop: while (!allIfaces.isEmpty()) { Class iface = (Class) allIfaces.pop(); - if (clazz != null && implementedBy(iface, clazz)) - /* We can skip this, as clazz does already imply it. + if ((clazz != null && implementedBy(iface, clazz)) + || ifaces.contains(iface)) + /* We can skip this, as clazz or ifaces already imply it. */ continue iface_loop; @@ -351,6 +349,18 @@ public class ClassInterfacesType extends Type { return create(clazz, ifaceArray); } + /** + * Marks this type as used, so that the class is imported. + */ + public void useType() { + if (!jode.Decompiler.isTypeDebugging) { + if (clazz != null && clazz != cObject) + env.useClass(clazz); + else if (ifaces.length > 0) + env.useClass(ifaces[0]); + } + } + public String toString() { if (jode.Decompiler.isTypeDebugging) { @@ -368,15 +378,21 @@ public class ClassInterfacesType extends Type { } return sb.append("}").toString(); } else { - if (clazz != null) + if (clazz != null && clazz != cObject) return env.classString(clazz); else if (ifaces.length > 0) return env.classString(ifaces[0]); + else if (clazz == cObject) + return env.classString(clazz); else return "{}"; } } + public boolean isClassType() { + return true; + } + public boolean equals(Object o) { if (o == this) return true; diff --git a/jode/jode/type/RangeType.java b/jode/jode/type/RangeType.java index b99adda..82d9975 100644 --- a/jode/jode/type/RangeType.java +++ b/jode/jode/type/RangeType.java @@ -82,14 +82,20 @@ public class RangeType extends Type { */ public void useType() { /* The topType will be printed */ - topType.useType(); + if (topType.isClassType() || bottomType == tUnknown) + topType.useType(); + else + bottomType.useType(); } public String toString() { if (jode.Decompiler.isTypeDebugging) return "<" + bottomType + "-" + topType + ">"; - return topType.toString(); + if (topType.isClassType() || bottomType == tUnknown) + return topType.toString(); + else + return bottomType.toString(); } public boolean equals(Object o) { diff --git a/jode/jode/type/Type.java b/jode/jode/type/Type.java index c237333..c0148ed 100644 --- a/jode/jode/type/Type.java +++ b/jode/jode/type/Type.java @@ -284,7 +284,7 @@ public class Type { : (type.typecode <= typecode) ? type : (type.typecode <= TC_INT || type.typecode == TC_BOOLINT) ? this - : (this == tByte && type == tBoolByte) ? this + : (type == tBoolByte) ? tByte : tError) : (typecode == TC_BOOLINT) @@ -384,7 +384,7 @@ public class Type { ? tRange(bottomType, this) : (bottomType.typecode == TC_BOOLBYTE - && bottomType == tByte) + && this == tByte) ? tByte : (bottomType.typecode == TC_BOOLINT @@ -428,6 +428,13 @@ public class Type { return result; } + /** + * Checks if this type represents a class or an array of a class + */ + public boolean isClassType() { + return false; + } + /** * Check if this and <unknown -- type&rt; are not disjunct. * @param type a simple type; this mustn't be a range type. @@ -439,6 +446,13 @@ public class Type { // return (getSpecializedType(type).equals(type)); } + /** + * Marks this type as used, so that the class is imported. + */ + public void useType() { + /* No action needed for simple types */ + } + public String toString() { switch (typecode) { case TC_BOOLINT: