diff --git a/jode/jode/bytecode/Opcodes.java b/jode/jode/bytecode/Opcodes.java index d35a49d..8f72c1d 100644 --- a/jode/jode/bytecode/Opcodes.java +++ b/jode/jode/bytecode/Opcodes.java @@ -360,9 +360,9 @@ public abstract class Opcodes implements RuntimeConstants { } case opc_ireturn: case opc_lreturn: case opc_freturn: case opc_dreturn: case opc_areturn: { - Type retType = MyType.intersection + Type retType = MyType.tSubType(MyType.intersection (ca.getMethod().mdef.getType().getReturnType(), - types[0][opcode-opc_ireturn]); + types[0][opcode-opc_ireturn])); return createBlock (ca, addr, 1, new ReturnBlock(new NopOperator(retType))); } diff --git a/jode/jode/decompiler/ClassAnalyzer.java b/jode/jode/decompiler/ClassAnalyzer.java index 807a85b..8508665 100644 --- a/jode/jode/decompiler/ClassAnalyzer.java +++ b/jode/jode/decompiler/ClassAnalyzer.java @@ -61,6 +61,11 @@ public class ClassAnalyzer implements Analyzer { { if (cdef.getSource() != null) writer.println("/* Original source: "+cdef.getSource()+" */"); + + writer.println("package " + cdef.getName().getQualifier() + ";"); + /* XXX imports */ + writer.println(""); + String modif = Modifier.toString(cdef.getModifiers()); if (modif.length() > 0) writer.print(modif + " "); diff --git a/jode/jode/expr/CompareBinaryOperator.java b/jode/jode/expr/CompareBinaryOperator.java index 71928f5..e95b695 100644 --- a/jode/jode/expr/CompareBinaryOperator.java +++ b/jode/jode/expr/CompareBinaryOperator.java @@ -47,7 +47,9 @@ public class CompareBinaryOperator extends SimpleOperator { public void setOperandType(Type[] inputTypes) { super.setOperandType(inputTypes); Type operandType = - MyType.intersection(operandTypes[0],operandTypes[1]); + MyType.tSubType(MyType.intersection + (MyType.tSuperType(operandTypes[0]), + MyType.tSuperType(operandTypes[1]))); operandTypes[0] = operandTypes[1] = operandType; } diff --git a/jode/jode/expr/ComplexExpression.java b/jode/jode/expr/ComplexExpression.java index 0de1e24..665e803 100644 --- a/jode/jode/expr/ComplexExpression.java +++ b/jode/jode/expr/ComplexExpression.java @@ -47,6 +47,16 @@ public class ComplexExpression extends Expression { this.type = operator.getType(); } + public int getOperandCount() { + if (subExpressions.length == 0) + return 0; + else + /* The only sub expression that may have non resolved + * operands may be the first. + */ + return subExpressions[0].getOperandCount(); + } + public Expression negate() { if (operator.operator >= operator.COMPARE_OP && operator.operator < operator.COMPARE_OP+6) { @@ -182,9 +192,10 @@ public class ComplexExpression extends Expression { } if (operator instanceof ConstructorOperator && MyType.isOfType(operator.getType(), MyType.tStringBuffer)) { - if (operator.getOperandCount() == 1) + /* subExpressions[0] is always a "new StringBuffer" */ + if (subExpressions.length == 1) return emptyString; - else if (operator.getOperandCount() == 2 && + else if (subExpressions.length == 2 && MyType.isOfType(subExpressions[1].getType(), MyType.tString)) return (Expression) subExpressions[1].simplify(); @@ -281,7 +292,7 @@ public class ComplexExpression extends Expression { !((InvokeOperator)operator).isStatic() && ((InvokeOperator)operator).getField(). getClassDefinition().getType() == MyType.tStringBuffer && - operator.getOperandCount() == 1) { + subExpressions.length == 1) { Instruction simple = subExpressions[0].simplifyStringBuffer(); if (simple != null) return simple; @@ -292,7 +303,7 @@ public class ComplexExpression extends Expression { ((InvokeOperator)operator).isStatic() && ((InvokeOperator)operator).getField(). getClassDefinition().getType() == MyType.tString && - operator.getOperandCount() == 1) { + subExpressions.length == 1) { if (subExpressions[0].getType() == MyType.tString) return subExpressions[0].simplify(); else { diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index 0031d68..7d246d4 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -28,6 +28,12 @@ public abstract class Expression extends Instruction { super (type); } + /** + * Get the number of operands. + * @return The number of stack entries this expression needs. + */ + public abstract int getOperandCount(); + public Expression negate() { Operator negop = new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP); @@ -36,6 +42,17 @@ public abstract class Expression extends Instruction { } public Expression tryToCombine(Expression e) { + if (e instanceof ComplexExpression + && e.getOperator() instanceof StoreInstruction) { + ComplexExpression ce = (ComplexExpression) e; + StoreInstruction store = (StoreInstruction) e.getOperator(); + if (store.matches(getOperator()) + && ce.subExpressions.length == 1) { + return new ComplexExpression + (new AssignOperator(store.getOperatorIndex(), store), + ce.subExpressions); + } + } return null; } diff --git a/jode/jode/flow/CombineIfGotoExpressions.java b/jode/jode/flow/CombineIfGotoExpressions.java index 7939623..35ba9de 100644 --- a/jode/jode/flow/CombineIfGotoExpressions.java +++ b/jode/jode/flow/CombineIfGotoExpressions.java @@ -39,6 +39,25 @@ public class CombineIfGotoExpressions implements Transformation{ // jode.Assert.assert(sequBlock.jump == null) + e = new Expression[2]; + e[1] = (Expression)cb.getInstruction(); + while (sequBlock.subBlocks[0] instanceof InstructionBlock) { + InstructionBlock ib = + (InstructionBlock) sequBlock.subBlocks[0]; + Expression expr = (Expression) ib.getInstruction(); + if (!expr.isVoid()) + return false; + + Expression combined = e[1].tryToCombine(expr); + if (combined == null) + return false; + + cb.replace(sequBlock, cb); + cb.setInstruction(combined); + e[1] = combined; + sequBlock = (SequentialBlock) cb.outer; + } + ConditionalBlock cbprev = (ConditionalBlock) sequBlock.subBlocks[0]; @@ -48,15 +67,11 @@ public class CombineIfGotoExpressions implements Transformation{ prevJump = ((EmptyBlock) cbprev.trueBlock).jump; if (prevJump.destination == cb.jump.destination) { - e = new Expression[2]; operator = BinaryOperator.LOG_AND_OP; - e[1] = (Expression)cb.getInstruction(); e[0] = ((Expression)cbprev.getInstruction()).negate(); } else if (prevJump.destination == ((EmptyBlock) cb.trueBlock).jump.destination) { - e = new Expression[2]; operator = BinaryOperator.LOG_OR_OP; - e[1] = (Expression)cb.getInstruction(); e[0] = (Expression)cbprev.getInstruction(); } else return false; diff --git a/jode/jode/flow/CreateExpression.java b/jode/jode/flow/CreateExpression.java index b329baa..01c2465 100644 --- a/jode/jode/flow/CreateExpression.java +++ b/jode/jode/flow/CreateExpression.java @@ -74,14 +74,20 @@ public class CreateExpression implements Transformation { (InstructionBlock) sequBlock.getSubBlocks()[0]; if (block.jump != null) return false; - exprs[i] = - (Expression) block.getInstruction(); + exprs[i] = (Expression) block.getInstruction(); + + if (i > 0 && exprs[i].getOperandCount() > 0) + /* This is a not fully resolved expression in the + * middle, we must not touch it. */ + return false; + if (exprs[i].isVoid()) { if (i == params-1) return false; Expression e = exprs[i+1].tryToCombine(exprs[i]); if (e == null) return false; + i++; SequentialBlock subExprBlock = (SequentialBlock) sequBlock.getSubBlocks()[1]; diff --git a/jode/jode/type/ClassRangeType.java b/jode/jode/type/ClassRangeType.java index a80be2a..0a177f0 100644 --- a/jode/jode/type/ClassRangeType.java +++ b/jode/jode/type/ClassRangeType.java @@ -111,8 +111,9 @@ public class ClassRangeType extends MyType { ClassDeclaration c2 = new ClassDeclaration(top.getClassName()); try { - if (c1.getClassDefinition(env).superClassOf(env, c2) || - c1.getClassDefinition(env).implementedBy(env, c2)) + if (c2.getClassDefinition(env).isInterface() + || c1.getClassDefinition(env).superClassOf(env, c2) + || c1.getClassDefinition(env).implementedBy(env, c2)) return new ClassRangeType(bottom, top); } catch (ClassNotFound ex) { } @@ -183,20 +184,18 @@ public class ClassRangeType extends MyType { * I currently only handle the simple case where one of the * two objects implements the other or is a child of it. * - * Forget the following setences, java tells us if the local - * is an interface or an object. - * * There are really complicated cases that are currently * ignored: imaging, c1 and c2 are both disjunct interfaces * and there are some object which implements them both. * There is no way for us to guess which. * + * Another possibility is that c1 is an interface and c2 + * an Object that doesn't implement c1. This is not an error, + * because it may be a sub class of c1 and c2 that implements + * c1 and c2. + * * What can we do about this? We probably need something more * powerful than a simple class range. - * But maybe this isn't needed at all. How should someone - * use an object which implements two interfaces in a local - * variable without casting? The information which object - * to use must be somewhere in the method. * * But think of this code fragment: * @@ -337,9 +336,12 @@ public class ClassRangeType extends MyType { Type newType = createRangeType(bottom,top); if (newType == tError) { + boolean oldTypeDebugging = Decompiler.isTypeDebugging; + Decompiler.isTypeDebugging = true; System.err.println("intersecting "+ this +" and "+ type + " to <" + bottom + "-" + top + "> to "); + Decompiler.isTypeDebugging = oldTypeDebugging; Thread.dumpStack(); } else if (Decompiler.isTypeDebugging) { System.err.println("intersecting "+ this +" and "+ type +