diff --git a/jode/jode/decompiler/LocalVariableTable.java b/jode/jode/decompiler/LocalVariableTable.java index af7a422..0b16d93 100644 --- a/jode/jode/decompiler/LocalVariableTable.java +++ b/jode/jode/decompiler/LocalVariableTable.java @@ -19,7 +19,6 @@ package jode; import java.util.Enumeration; -import gnu.bytecode.CpoolUtf8; import gnu.bytecode.LocalVarsAttr; import gnu.bytecode.Variable; import gnu.bytecode.Spy; diff --git a/jode/jode/expr/ComplexExpression.java b/jode/jode/expr/ComplexExpression.java index 9cdc6fd..eedf982 100644 --- a/jode/jode/expr/ComplexExpression.java +++ b/jode/jode/expr/ComplexExpression.java @@ -88,11 +88,12 @@ public class ComplexExpression extends Expression { } return 1; } - for (int i=0; i < subExpressions.length; i++) { - int can = subExpressions[i].canCombine(e); - if (can != 0) - return can; - } + return subExpressions[0].canCombine(e); +// for (int i=0; i < subExpressions.length; i++) { +// int can = subExpressions[i].canCombine(e); +// if (can != 0) +// return can; +// } } return 0; } @@ -120,7 +121,7 @@ public class ComplexExpression extends Expression { return this; } } - throw new AssertError("combine didn't succeed"); + return null; } public Operator getOperator() { @@ -235,37 +236,33 @@ public class ComplexExpression extends Expression { return true; } - static Expression emptyString = - new EmptyStringOperator(); - public Expression simplifyStringBuffer() { - gnu.bytecode.CpoolRef field; if (operator instanceof InvokeOperator && (((InvokeOperator)operator).getClassType() .equals(Type.tStringBuffer)) && !((InvokeOperator)operator).isStatic() && (((InvokeOperator)operator).getMethodName().equals("append")) && (((InvokeOperator)operator).getMethodType() - .getArgumentTypes().length == 1)) { + .getParameterTypes().length == 1)) { Expression e = subExpressions[0].simplifyStringBuffer(); if (e == null) return null; - if (e.getOperator() instanceof EmptyStringOperator && - subExpressions[1].getType().isOfType(Type.tString)) + if (e == EMPTYSTRING + && subExpressions[1].getType().isOfType(Type.tString)) return subExpressions[1]; return new ComplexExpression (new StringAddOperator(), new Expression[] { e, subExpressions[1] }); } - if (operator instanceof ConstructorOperator && - operator.getType().isOfType(Type.tStringBuffer)) { - if (subExpressions.length == 0) - return emptyString; - else if (subExpressions.length == 1 && - subExpressions[0].getType().isOfType(Type.tString)) + if (operator instanceof ConstructorOperator + && (((ConstructorOperator) operator).getClassType() + == Type.tStringBuffer)) { + + if (subExpressions.length == 1 && + subExpressions[0].getType().isOfType(Type.tString)) return subExpressions[0]; } return null; @@ -276,7 +273,7 @@ public class ComplexExpression extends Expression { InvokeOperator invoke = (InvokeOperator) operator; if (invoke.getMethodName().equals("toString") && !invoke.isStatic() - && (invoke.getClassType().equals(Type.tStringBuffer)) + && invoke.getClassType().equals(Type.tStringBuffer) && subExpressions.length == 1) { Expression simple = subExpressions[0].simplifyStringBuffer(); if (simple != null) @@ -292,7 +289,7 @@ public class ComplexExpression extends Expression { return new ComplexExpression (new StringAddOperator(), new Expression[] - { emptyString, subExpressions[0] }); + { EMPTYSTRING, subExpressions[0] }); } /* The pizza way (pizza is the compiler of kaffe) */ else if (invoke.getMethodName().equals("concat") @@ -304,7 +301,7 @@ public class ComplexExpression extends Expression { if (right instanceof ComplexExpression && right.getOperator() instanceof StringAddOperator && (((ComplexExpression) right).subExpressions[0] - == emptyString)) + == EMPTYSTRING)) right = ((ComplexExpression)right).subExpressions[1]; return new ComplexExpression diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index adc9718..e04cc0b 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -46,13 +46,17 @@ public class ConstOperator extends NoArgOperator { return "false"; else if (value.equals("1")) return "true"; - } if (type == Type.tChar) { - char i = (char) Integer.parseInt(value); - switch (i) { + } if (type.getBottom() == Type.tChar) { + char c = (char) Integer.parseInt(value); + switch (c) { + case '\0': + return "\'\\0\'"; case '\t': return "\'\\t\'"; case '\n': return "\'\\n\'"; + case '\r': + return "\'\\r\'"; case '\\': return "\'\\\\\'"; case '\"': @@ -60,8 +64,16 @@ public class ConstOperator extends NoArgOperator { case '\'': return "\'\\\'\'"; } - if (i >= 32 && i <128) - return "\'"+i+"\'"; + if (c < 32) { + String oct = Integer.toOctalString(c); + return "\'\\000".substring(0, 5-oct.length())+oct+"\'"; + } + if (c >= 32 && c < 127) + return "\'"+c+"\'"; + else { + String hex = Integer.toHexString(c); + return "\'\\u0000".substring(0, 7-hex.length())+hex+"\'"; + } } else if (parent != null) { int opindex = parent.getOperator().getOperatorIndex(); if (opindex >= OPASSIGN_OP + ADD_OP diff --git a/jode/jode/expr/ConstructorOperator.java b/jode/jode/expr/ConstructorOperator.java index 0195ed9..2ad3717 100644 --- a/jode/jode/expr/ConstructorOperator.java +++ b/jode/jode/expr/ConstructorOperator.java @@ -35,24 +35,33 @@ public class ConstructorOperator extends Operator { } public int getOperandCount() { - return methodType.getArgumentTypes().length; + return methodType.getParameterTypes().length; } public int getOperandPriority(int i) { return 0; } + public Type getClassType() { + return classType; + } + public Type getOperandType(int i) { - return methodType.getArgumentTypes()[i]; + return methodType.getParameterTypes()[i]; } public void setOperandType(Type types[]) { } + public Expression simplifyStringBuffer() { + return (getClassType() == Type.tStringBuffer) + ? EMPTYSTRING : null; + } + public String toString(String[] operands) { StringBuffer result = new StringBuffer("new ").append(classType.toString()).append("("); - for (int i=0; i < methodType.getArgumentTypes().length; i++) { + for (int i=0; i < methodType.getParameterTypes().length; i++) { if (i>0) result.append(", "); result.append(operands[i]); diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index be2215a..4e68c61 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -65,6 +65,8 @@ public abstract class Expression { * conflict was found. You may wish to check for >0. */ public int canCombine(Expression e) { + if (!e.isVoid()) + return 0; if (e instanceof IIncOperator && ((IIncOperator)e.getOperator()).matches(getOperator())) return 1; @@ -84,19 +86,30 @@ public abstract class Expression { * @return The combined expression. */ public Expression combine(Expression e) { - if (e.getOperator() instanceof IIncOperator) - ((IIncOperator)e.getOperator()).makeNonVoid(); - else - ((StoreInstruction)e.getOperator()).makeNonVoid(); - /* Do not call setType, we don't want to intersect. */ - e.type = e.getOperator().getType(); - return e; + if (e.getOperator() instanceof IIncOperator) { + if (((IIncOperator)e.getOperator()).matches(getOperator())) { + ((IIncOperator)e.getOperator()).makeNonVoid(); + /* Do not call setType, we don't want to intersect. */ + e.type = e.getOperator().getType(); + return e; + } + } else { + if (((StoreInstruction)e.getOperator()).matches(getOperator())) { + ((StoreInstruction)e.getOperator()).makeNonVoid(); + /* Do not call setType, we don't want to intersect. */ + e.type = e.getOperator().getType(); + return e; + } + } + return null; } public Expression simplify() { return this; } + static Expression EMPTYSTRING = new ConstOperator(Type.tString, "\"\""); + public Expression simplifyStringBuffer() { return null; } diff --git a/jode/jode/expr/GetFieldOperator.java b/jode/jode/expr/GetFieldOperator.java index 65c8946..24268b2 100644 --- a/jode/jode/expr/GetFieldOperator.java +++ b/jode/jode/expr/GetFieldOperator.java @@ -22,17 +22,17 @@ import gnu.bytecode.CpoolRef; public class GetFieldOperator extends Operator { boolean staticFlag; - CpoolRef field; CodeAnalyzer codeAnalyzer; + String fieldName; Type classType; - public GetFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, - CpoolRef field) { - super(Type.tType(field.getNameAndType().getType().getString()), 0); + public GetFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, + Type classType, Type type, String fieldName) { + super(type, 0); this.codeAnalyzer = codeAnalyzer; this.staticFlag = staticFlag; - this.field = field; - classType = Type.tClass(field.getCpoolClass().getName().getString()); + this.classType = classType; + this.fieldName = fieldName; if (staticFlag) classType.useType(); } @@ -57,7 +57,6 @@ public class GetFieldOperator extends Operator { } public String toString(String[] operands) { - String fieldName = field.getNameAndType().getName().getString(); return staticFlag ? (classType.equals(Type.tType(codeAnalyzer.getClazz())) ? fieldName @@ -68,7 +67,8 @@ public class GetFieldOperator extends Operator { } public boolean equals(Object o) { - return (o instanceof GetFieldOperator) && - ((GetFieldOperator)o).field == field; + return o instanceof GetFieldOperator + && ((GetFieldOperator)o).classType.equals(classType) + && ((GetFieldOperator)o).fieldName.equals(fieldName); } } diff --git a/jode/jode/expr/InvokeOperator.java b/jode/jode/expr/InvokeOperator.java index 8de1101..1a3b777 100644 --- a/jode/jode/expr/InvokeOperator.java +++ b/jode/jode/expr/InvokeOperator.java @@ -22,36 +22,27 @@ import gnu.bytecode.CpoolRef; public final class InvokeOperator extends Operator { CodeAnalyzer codeAnalyzer; - boolean staticFlag; boolean specialFlag; MethodType methodType; String methodName; Type classType; - CpoolRef field; public InvokeOperator(CodeAnalyzer codeAnalyzer, - boolean staticFlag, boolean specialFlag, - CpoolRef field) { + boolean specialFlag, Type classType, + MethodType methodType, String methodName) { super(Type.tUnknown, 0); - methodType = new MethodType(field.getNameAndType(). - getType().getString()); - methodName = field.getNameAndType().getName().getString(); - classType = Type.tClass(field.getCpoolClass().getName().getString()); + this.methodType = methodType; + this.methodName = methodName; + this.classType = classType; this.type = methodType.getReturnType(); this.codeAnalyzer = codeAnalyzer; - this.staticFlag = staticFlag; this.specialFlag = specialFlag; - this.field = field; - if (staticFlag) + if (methodType.isStatic()) classType.useType(); } public boolean isStatic() { - return staticFlag; - } - - public CpoolRef getField() { - return field; + return methodType.isStatic(); } public MethodType getMethodType() { @@ -71,22 +62,23 @@ public final class InvokeOperator extends Operator { } public int getOperandCount() { - return (staticFlag?0:1) + methodType.getArgumentTypes().length; + return (methodType.isStatic()?0:1) + + methodType.getParameterTypes().length; } public int getOperandPriority(int i) { - if (!staticFlag && i == 0) + if (!methodType.isStatic() && i == 0) return 950; return 0; } public Type getOperandType(int i) { - if (!staticFlag) { + if (!methodType.isStatic()) { if (i == 0) return getClassType(); i--; } - return methodType.getArgumentTypes()[i]; + return methodType.getParameterTypes()[i]; } public void setOperandType(Type types[]) { @@ -98,7 +90,7 @@ public final class InvokeOperator extends Operator { public String toString(String[] operands) { String object = - staticFlag + methodType.isStatic() ? (classType.equals(Type.tType(codeAnalyzer.getClazz())) ? "" : classType.toString()) @@ -110,7 +102,7 @@ public final class InvokeOperator extends Operator { : "") : operands[0]); - int arg = staticFlag ? 0 : 1; + int arg = methodType.isStatic() ? 0 : 1; String method; if (isConstructor()) method = (object.length() == 0 ? "this" : object); @@ -118,7 +110,7 @@ public final class InvokeOperator extends Operator { method = (object.length() == 0 ? "" : object + ".") + methodName; StringBuffer params = new StringBuffer(); - for (int i=0; i < methodType.getArgumentTypes().length; i++) { + for (int i=0; i < methodType.getParameterTypes().length; i++) { if (i>0) params.append(", "); params.append(operands[arg++]); @@ -127,9 +119,10 @@ public final class InvokeOperator extends Operator { } public boolean equals(Object o) { - return (o instanceof InvokeOperator) && - ((InvokeOperator)o).field == field && - ((InvokeOperator)o).staticFlag == staticFlag && + return o instanceof InvokeOperator && + ((InvokeOperator)o).classType.equals(classType) && + ((InvokeOperator)o).methodName.equals(methodName) && + ((InvokeOperator)o).methodType.equals(methodType) && ((InvokeOperator)o).specialFlag == specialFlag; } } diff --git a/jode/jode/expr/PutFieldOperator.java b/jode/jode/expr/PutFieldOperator.java index 389dc34..a8bb80e 100644 --- a/jode/jode/expr/PutFieldOperator.java +++ b/jode/jode/expr/PutFieldOperator.java @@ -23,23 +23,24 @@ import gnu.bytecode.CpoolRef; public class PutFieldOperator extends StoreInstruction { CodeAnalyzer codeAnalyzer; boolean staticFlag; - CpoolRef field; + String fieldName; Type classType; public PutFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag, - CpoolRef field) { - super(Type.tType(field.getNameAndType().getType().getString()), ASSIGN_OP); + Type classType, Type type, String fieldName) { + super(type, ASSIGN_OP); this.codeAnalyzer = codeAnalyzer; this.staticFlag = staticFlag; - this.field = field; - classType = Type.tClass(field.getCpoolClass().getName().getString()); + this.fieldName = fieldName; + this.classType = classType; if (staticFlag) classType.useType(); } public boolean matches(Operator loadop) { - return loadop instanceof GetFieldOperator && - ((GetFieldOperator)loadop).field == field; + return loadop instanceof GetFieldOperator + && ((GetFieldOperator)loadop).classType.equals(classType) + && ((GetFieldOperator)loadop).fieldName.equals(fieldName); } public int getLValueOperandCount() { @@ -58,7 +59,6 @@ public class PutFieldOperator extends StoreInstruction { } public String getLValueString(String[] operands) { - String fieldName = field.getNameAndType().getName().getString(); return staticFlag ? (classType.equals(Type.tType(codeAnalyzer.getClazz())) ? fieldName @@ -69,7 +69,8 @@ public class PutFieldOperator extends StoreInstruction { } public boolean equals(Object o) { - return (o instanceof PutFieldOperator) && - ((PutFieldOperator)o).field == field; + return o instanceof PutFieldOperator + && ((PutFieldOperator)o).classType.equals(classType) + && ((PutFieldOperator)o).fieldName.equals(fieldName); } } diff --git a/jode/jode/flow/CatchBlock.java b/jode/jode/flow/CatchBlock.java index 7ada744..800e0d9 100644 --- a/jode/jode/flow/CatchBlock.java +++ b/jode/jode/flow/CatchBlock.java @@ -110,4 +110,13 @@ public class CatchBlock extends StructuredBlock { catchBlock.dumpSource(writer); writer.untab(); } + + /** + * Determines if there is a sub block, that flows through to the end + * of this block. If this returns true, you know that jump is null. + * @return true, if the jump may be safely changed. + */ + public boolean jumpMayBeChanged() { + return (catchBlock.jump != null || catchBlock.jumpMayBeChanged()); + } } diff --git a/jode/jode/flow/CombineIfGotoExpressions.java b/jode/jode/flow/CombineIfGotoExpressions.java index 73ca114..7d4cfd0 100644 --- a/jode/jode/flow/CombineIfGotoExpressions.java +++ b/jode/jode/flow/CombineIfGotoExpressions.java @@ -67,9 +67,13 @@ public class CombineIfGotoExpressions implements Transformation{ if (prevJump.destination == cb.jump.destination) { operator = BinaryOperator.LOG_AND_OP; e[0] = cbprev.getInstruction().negate(); + cb.jump.gen.unionExact(prevJump.gen); + cb.jump.kill.intersect(prevJump.kill); } else if (prevJump.destination == cb.trueBlock.jump.destination) { operator = BinaryOperator.LOG_OR_OP; e[0] = cbprev.getInstruction(); + cb.trueBlock.jump.gen.unionExact(prevJump.gen); + cb.trueBlock.jump.kill.intersect(prevJump.kill); } else return false; diff --git a/jode/jode/flow/CreateIfThenElseOperator.java b/jode/jode/flow/CreateIfThenElseOperator.java index f50d6ca..de0d8e6 100644 --- a/jode/jode/flow/CreateIfThenElseOperator.java +++ b/jode/jode/flow/CreateIfThenElseOperator.java @@ -18,6 +18,7 @@ */ package jode.flow; +import jode.Type; import jode.Expression; import jode.ComplexExpression; import jode.IfThenElseOperator; @@ -149,7 +150,8 @@ public class CreateIfThenElseOperator implements Transformation { System.err.print('?'); IfThenElseOperator iteo = new IfThenElseOperator - (e[1].getType().intersection(e[2].getType())); + (Type.tSuperType(e[1].getType()) + .intersection(Type.tSuperType(e[2].getType()))); ((InstructionBlock)ifBlock.thenBlock). setInstruction(new ComplexExpression(iteo, e)); @@ -214,7 +216,8 @@ public class CreateIfThenElseOperator implements Transformation { thenBlock.removeJump(); IfThenElseOperator iteo = new IfThenElseOperator - (e[1].getType().intersection(e[2].getType())); + (Type.tSuperType(e[1].getType()) + .intersection(Type.tSuperType(e[2].getType()))); ((InstructionBlock)flow.lastModified). setInstruction(new ComplexExpression(iteo, e)); diff --git a/jode/jode/flow/TryBlock.java b/jode/jode/flow/TryBlock.java index 5e8b9ad..c7ce4f9 100644 --- a/jode/jode/flow/TryBlock.java +++ b/jode/jode/flow/TryBlock.java @@ -100,4 +100,18 @@ public class TryBlock extends StructuredBlock { subBlocks[i].dumpSource(writer); writer.println("}"); } + + /** + * Determines if there is a sub block, that flows through to the end + * of this block. If this returns true, you know that jump is null. + * @return true, if the jump may be safely changed. + */ + public boolean jumpMayBeChanged() { + for (int i=0; i