diff --git a/jode/ChangeLog b/jode/ChangeLog index e69de29..c85ca93 100644 --- a/jode/ChangeLog +++ b/jode/ChangeLog @@ -0,0 +1,53 @@ +Tue Jan 30 15:35:19 2001 Jochen Hoenicke + + * jode/decompiler/TabbedPrintWriter.java: Better gnu style handling: + (openBraceClass) (closeBraceClass) + (openBraceNoIndent) (closeBraceNoIndent): new functions. + (closeBraceNoSpace): Removed. + * jode/decompiler/Options.java (GNU_SPACING): new constant. + (GNU_STYLE): changed to include GNU_SPACING. + * jode/decompiler/ClassAnalyzer.java.in (dumpSource): Use + open/closeBraceClass. + * jode/decompiler/MethodAnalyzer.java.in (dumpSource): Use + open/closeBraceNoIndent. Insert a space for GNU_SPACING. + * jode/decompiler/InvokeOperator.java.in (dumpExpression): Insert + a space for GNU_SPACING, use open/closeBraceClass for inner + classes. + * jode/decompiler/UnaryOperator.java (dumpExpression): Insert + a space for GNU_SPACING. + +Tue Jan 30 15:28:10 2001 Jochen Hoenicke + + Added pascal style from Rolf Howarth + * jode/decompiler/Options.java (PASCAL_STYLE): new constant. + (BRACE_FLUSH_LEFT): dito. + * jode/decompiler/Decompiler.java (setOption): detect pascal option. + * jode/decompiler/Main.java (main): dito. + * jode/decompiler/TabbedPrintWriter.java (openBrace, + openBraceContinue, closeBrace, closeBraceNoSpace, + closeBraceContinue): handle flush left. + +Tue Jan 30 00:28:10 2001 Jochen Hoenicke + + * jode/type/NullType.java (intersection): Removed, since the + version in ReferenceType is more correct. Before + tNull.isOfType(tRange(X,tNull)) returned false, which lead to + incorrect behaviour in InvokeOperator.needsCast. + * jode/decompiler/FieldAnalyzer.java.in (dumpSource): Removed the + "= null" hack for final fields; it was not correct, since the + field could be initialized in a constructor. + * jode/decompiler/TabbedPrintWriter.java (BreakPoint.endOp): + Simplified the code, copy options always from child. + * jode/jvm/SyntheticAnalyzer.java.in (unifyParam): new field. + (checkConstructorAccess): Allow the special Parameter, whose + purpose is to distinguish the wrapper from the real constructor + and give him a "$" in the type signature, to appear at every + position. It doesn't appear at position 1 for inner classes. + Store the position in unifyParam. + * jode/expr/InvokeOperator.java (isGetClass): Allow the method to + be declared inside an outer class: We simply check if we can get + the method analyzer. + (simplify): handle unifyParam. + * jode/expr/PopOperator.java (getBreakPenalty): return penalty of + inner expression. (dumpExpression): Call dumpExpression of + subexpression immediately without priority. diff --git a/jode/THANKS b/jode/THANKS index 57ddf76..8dfdbcf 100644 --- a/jode/THANKS +++ b/jode/THANKS @@ -1 +1,3 @@ +Rolf Howarth for pascal indentaton style. +Martin Schmitz for finding many bugs in the obfuscator. zzzeek diff --git a/jode/jode/decompiler/ClassAnalyzer.java.in b/jode/jode/decompiler/ClassAnalyzer.java.in index 298bdfa..58f292e 100644 --- a/jode/jode/decompiler/ClassAnalyzer.java.in +++ b/jode/jode/decompiler/ClassAnalyzer.java.in @@ -564,15 +564,12 @@ public class ClassAnalyzer } writer.println(); - writer.openBrace(); + writer.openBraceClass(); writer.tab(); dumpBlock(writer, pl, done, scale); writer.untab(); - if (parent instanceof MethodAnalyzer) { - /* This is a method scope class */ - writer.closeBraceNoSpace(); - } else - writer.closeBrace(); + writer.closeBraceClass(); + writer.println(); clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS); } diff --git a/jode/jode/decompiler/Decompiler.java b/jode/jode/decompiler/Decompiler.java index eb8c3c9..88574d1 100644 --- a/jode/jode/decompiler/Decompiler.java +++ b/jode/jode/decompiler/Decompiler.java @@ -103,6 +103,8 @@ public class Decompiler { Options.outputStyle = Options.GNU_STYLE; else if (value.equals("sun")) Options.outputStyle = Options.SUN_STYLE; + else if (value.equals("pascal")) + Options.outputStyle = Options.PASCAL_STYLE; else throw new IllegalArgumentException("Invalid style "+value); return; diff --git a/jode/jode/decompiler/FieldAnalyzer.java.in b/jode/jode/decompiler/FieldAnalyzer.java.in index 449a3cc..0ac9c4f 100644 --- a/jode/jode/decompiler/FieldAnalyzer.java.in +++ b/jode/jode/decompiler/FieldAnalyzer.java.in @@ -187,11 +187,6 @@ public class FieldAnalyzer implements Analyzer { writer.breakOp(); writer.print(" = "); constant.dumpExpression(writer.IMPL_PAREN, writer); - } else if ((modifiers & (Modifier.STATIC | Modifier.FINAL)) - == (Modifier.STATIC | Modifier.FINAL)) { - /* Static final fields must always be initialized */ - writer.breakOp(); - writer.print(" = null"); } writer.endOp(); writer.println(";"); diff --git a/jode/jode/decompiler/Main.java b/jode/jode/decompiler/Main.java index 137d35b..b77f2f1 100644 --- a/jode/jode/decompiler/Main.java +++ b/jode/jode/decompiler/Main.java @@ -258,6 +258,8 @@ public class Main extends Options { outputStyle = SUN_STYLE; else if ("gnu".startsWith(arg)) outputStyle = GNU_STYLE; + else if ("pascal".startsWith(arg)) + outputStyle = Options.PASCAL_STYLE; else { GlobalOptions.err.println ("jode.decompiler.Main: Unknown style `"+arg+"'."); diff --git a/jode/jode/decompiler/MethodAnalyzer.java.in b/jode/jode/decompiler/MethodAnalyzer.java.in index 8b5585c..ad29a81 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java.in +++ b/jode/jode/decompiler/MethodAnalyzer.java.in @@ -27,6 +27,7 @@ import jode.bytecode.Handler; import jode.bytecode.Instruction; import jode.bytecode.LocalVariableInfo; import jode.jvm.SyntheticAnalyzer; +import jode.decompiler.Options; import jode.type.*; import jode.expr.Expression; import jode.expr.ConstOperator; @@ -866,6 +867,8 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { writer.print(" " + methodName); } writer.breakOp(); + if ((Options.outputStyle & Options.GNU_SPACING) != 0) + writer.print(" "); writer.print("("); writer.startOp(writer.EXPL_PAREN, 0); int offset = skipParams + (isStatic() ? 0 : 1); @@ -895,11 +898,11 @@ public class MethodAnalyzer implements Scope, ClassDeclarer { } writer.endOp(); if (code != null) { - writer.openBrace(); + writer.openBraceNoIndent(); writer.tab(); methodHeader.dumpSource(writer); writer.untab(); - writer.closeBrace(); + writer.closeBraceNoIndent(); } else writer.println(";"); writer.popScope(); diff --git a/jode/jode/decompiler/Options.java b/jode/jode/decompiler/Options.java index a083181..e34f750 100644 --- a/jode/jode/decompiler/Options.java +++ b/jode/jode/decompiler/Options.java @@ -22,10 +22,13 @@ import jode.bytecode.ClassInfo; import jode.bytecode.InnerClassInfo; public class Options { - public static final int TAB_SIZE_MASK = 0x0f; - public static final int BRACE_AT_EOL = 0x10; - public static final int SUN_STYLE = 0x14; - public static final int GNU_STYLE = 0x02; + public static final int TAB_SIZE_MASK = 0x0f; + public static final int BRACE_AT_EOL = 0x10; + public static final int BRACE_FLUSH_LEFT = 0x20; + public static final int GNU_SPACING = 0x40; + public static final int SUN_STYLE = 0x14; + public static final int GNU_STYLE = 0x42; + public static final int PASCAL_STYLE = 0x24; public static final int OPTION_LVT = 0x0001; public static final int OPTION_INNER = 0x0002; diff --git a/jode/jode/decompiler/TabbedPrintWriter.java b/jode/jode/decompiler/TabbedPrintWriter.java index b8df179..15daff3 100644 --- a/jode/jode/decompiler/TabbedPrintWriter.java +++ b/jode/jode/decompiler/TabbedPrintWriter.java @@ -120,17 +120,15 @@ public class TabbedPrintWriter { public void endOp(int pos) { endPos = pos; if (childBPs.size() == 1) { - BreakPoint child = - (BreakPoint) currentBP.childBPs.elementAt(0); - if (child.startPos == -1) { - startPos = endPos = -1; - childBPs = null; - } else if (child.startPos == currentBP.startPos - && child.endPos == currentBP.endPos) { - if (options == DONT_BREAK) - options = child.options; - childBPs = child.childBPs; - } + /* There is no breakpoint in this op, replace this with + * our child, if possible. + */ + BreakPoint child = (BreakPoint) childBPs.elementAt(0); + options = child.options; + startPos = child.startPos; + endPos = child.endPos; + breakPenalty = child.breakPenalty; + childBPs = child.childBPs; } } @@ -746,12 +744,38 @@ public class TabbedPrintWriter { } else { if (currentLine.length() > 0) println(); - if (currentIndent > 0) + if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0 + && currentIndent > 0) tab(); println("{"); } } + public void openBraceClass() { + if (currentLine.length() > 0) { + if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0) + print(" "); + else + println(); + } + println("{"); + } + + /** + * Print a opening brace with the current indentation style. + * Called at the end the line of a method declaration. + */ + public void openBraceNoIndent() { + if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0) { + print(currentLine.length() > 0 ? " {" : "{"); + println(); + } else { + if (currentLine.length() > 0) + println(); + println("{"); + } + } + /** * Print a opening brace with the current indentation style. * Called at the end of the line of the instance that opens the @@ -763,7 +787,8 @@ public class TabbedPrintWriter { else { if (currentLine.length() > 0) println(); - if (currentIndent > 0) + if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0 + && currentIndent > 0) tab(); println("{"); } @@ -774,19 +799,14 @@ public class TabbedPrintWriter { print("} "); else { println("}"); - if (currentIndent > 0) + if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0 + && currentIndent > 0) untab(); } } - public void closeBraceNoSpace() { - if ((Options.outputStyle & Options.BRACE_AT_EOL) != 0) - print("}"); - else { - println("}"); - if (currentIndent > 0) - untab(); - } + public void closeBraceClass() { + print("}"); } public void closeBrace() { @@ -794,11 +814,16 @@ public class TabbedPrintWriter { println("}"); else { println("}"); - if (currentIndent > 0) + if ((Options.outputStyle & Options.BRACE_FLUSH_LEFT) == 0 + && currentIndent > 0) untab(); } } + public void closeBraceNoIndent() { + println("}"); + } + public void flush() { pw.flush(); } diff --git a/jode/jode/expr/InvokeOperator.java.in b/jode/jode/expr/InvokeOperator.java.in index 5c6b131..0f5d55e 100644 --- a/jode/jode/expr/InvokeOperator.java.in +++ b/jode/jode/expr/InvokeOperator.java.in @@ -398,12 +398,12 @@ public final class InvokeOperator extends Operator * @return true if this is the magic class$ method, false otherwise. */ public boolean isGetClass() { - if (isThis()) { - SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); - if (synth != null && synth.getKind() == SyntheticAnalyzer.GETCLASS) - return true; - } - return false; + MethodAnalyzer mana = getMethodAnalyzer(); + if (mana == null) + return false; + SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); + return (synth != null + && synth.getKind() == SyntheticAnalyzer.GETCLASS); } class Environment extends SimpleRuntimeEnvironment { @@ -572,6 +572,7 @@ public final class InvokeOperator extends Operator if (getMethodAnalyzer() != null) { SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic(); if (synth != null) { + int unifyParam = synth.getUnifyParam(); Expression op = null; switch (synth.getKind()) { case SyntheticAnalyzer.ACCESSGETFIELD: @@ -601,9 +602,9 @@ public final class InvokeOperator extends Operator synth.getReference()); break; case SyntheticAnalyzer.ACCESSCONSTRUCTOR: - if (subExpressions[1] instanceof ConstOperator + if (subExpressions[unifyParam] instanceof ConstOperator && ((ConstOperator) - subExpressions[1]).getValue() == null) { + subExpressions[unifyParam]).getValue() == null) { op = new InvokeOperator(methodAnalyzer, CONSTRUCTOR, synth.getReference()); } @@ -613,7 +614,7 @@ public final class InvokeOperator extends Operator if (op != null) { if (subExpressions != null) { for (int i=subExpressions.length; i-- > 0; ) { - if (i == 1 && synth.getKind() + if (i == unifyParam && synth.getKind() == SyntheticAnalyzer.ACCESSCONSTRUCTOR) // skip the null param. continue; @@ -675,9 +676,10 @@ public final class InvokeOperator extends Operator } for (int p = offset; p < paramTypes.length; p++) { if (!paramTypes[p] - .isOfType(Type.tSubType(otherParamTypes[p-offset]))) + .isOfType(Type.tSubType(otherParamTypes[p-offset]))){ /* No conflict here */ continue next_method; + } } /* There is a conflict that can be resolved by a cast. */ return true; @@ -1103,6 +1105,8 @@ public final class InvokeOperator extends Operator writer.endOp(); writer.breakOp(); + if ((Options.outputStyle & Options.GNU_SPACING) != 0) + writer.print(" "); writer.print("("); writer.startOp(writer.EXPL_PAREN, 0); boolean first = true; @@ -1136,11 +1140,11 @@ public final class InvokeOperator extends Operator * dump the source code of the anonymous class. */ Object state = writer.saveOps(); - writer.openBrace(); + writer.openBraceClass(); writer.tab(); clazzAna.dumpBlock(writer); writer.untab(); - writer.closeBraceNoSpace(); + writer.closeBraceClass(); writer.restoreOps(state); } } diff --git a/jode/jode/expr/PopOperator.java b/jode/jode/expr/PopOperator.java index 4fa839c..9d55640 100644 --- a/jode/jode/expr/PopOperator.java +++ b/jode/jode/expr/PopOperator.java @@ -41,8 +41,17 @@ public class PopOperator extends Operator { public void updateType() { } + public int getBreakPenalty() { + if (subExpressions[0] instanceof Operator) + return ((Operator) subExpressions[0]).getBreakPenalty(); + return 0; + } + public void dumpExpression(TabbedPrintWriter writer) throws java.io.IOException { - subExpressions[0].dumpExpression(writer, 0); + /* Don't give a priority; we can't allow parens around + * a statement. + */ + subExpressions[0].dumpExpression(writer); } } diff --git a/jode/jode/expr/UnaryOperator.java b/jode/jode/expr/UnaryOperator.java index 1722442..72c3003 100644 --- a/jode/jode/expr/UnaryOperator.java +++ b/jode/jode/expr/UnaryOperator.java @@ -19,6 +19,7 @@ package jode.expr; import jode.type.Type; +import jode.decompiler.Options; import jode.decompiler.TabbedPrintWriter; public class UnaryOperator extends Operator { @@ -57,6 +58,8 @@ public class UnaryOperator extends Operator { public void dumpExpression(TabbedPrintWriter writer) throws java.io.IOException { writer.print(getOperatorString()); + if ((Options.outputStyle & Options.GNU_SPACING) != 0) + writer.print(" "); subExpressions[0].dumpExpression(writer, 700); } } diff --git a/jode/jode/jvm/SyntheticAnalyzer.java.in b/jode/jode/jvm/SyntheticAnalyzer.java.in index 4e55ef4..add4956 100644 --- a/jode/jode/jvm/SyntheticAnalyzer.java.in +++ b/jode/jode/jvm/SyntheticAnalyzer.java.in @@ -27,6 +27,7 @@ import jode.bytecode.Instruction; import jode.bytecode.MethodInfo; import jode.bytecode.Opcodes; import jode.bytecode.Reference; +import jode.bytecode.TypeSignature; import jode.type.Type; import jode.type.MethodType; @@ -48,6 +49,7 @@ public class SyntheticAnalyzer implements Opcodes { int kind = UNKNOWN; Reference reference; MethodInfo method; + int unifyParam = -1; public SyntheticAnalyzer(MethodInfo method, boolean checkName) { this.method = method; @@ -72,6 +74,14 @@ public class SyntheticAnalyzer implements Opcodes { return reference; } + /** + * Gets the index of the dummy parameter for an ACCESSCONSTRUCTOR. + * Normally the 1 but for inner classes it may be 2. + */ + public int getUnifyParam() { + return unifyParam; + } + private static final int[] getClassOpcodes = { opc_aload, opc_invokestatic, opc_areturn, opc_astore, opc_new, opc_dup, opc_aload, @@ -325,17 +335,23 @@ public class SyntheticAnalyzer implements Opcodes { return false; Iterator iter = bytecode.getInstructions().iterator(); - Instruction instr = (Instruction) iter.next(); - if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0) - return false; - instr = (Instruction) iter.next(); - // slot begins with 2. Slot 1 contains a dummy value, that - // is used so that the constructor has a different type signature. - int params = 0, slot = 2; + Instruction instr = (Instruction) iter.next(); + int params = 0, slot = 0; while (instr.getOpcode() >= opc_iload - && instr.getOpcode() <= opc_aload - && instr.getLocalSlot() == slot) { + && instr.getOpcode() <= opc_aload) { + + if (instr.getLocalSlot() > slot + && unifyParam == -1 && params > 0 + && TypeSignature.getParameterTypes(method.getType()) + [params - 1].charAt(0) == 'L') { + unifyParam = params; + params++; + slot++; + } + if (instr.getLocalSlot() != slot) + return false; + params++; slot += (instr.getOpcode() == opc_lload || instr.getOpcode() == opc_dload) ? 2 : 1; @@ -352,13 +368,17 @@ public class SyntheticAnalyzer implements Opcodes { MethodType refType = Type.tMethod(ref.getType()); if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE || !refMethod.getName().equals("") - || refType.getParameterTypes().length != params) + || unifyParam == -1 + || refType.getParameterTypes().length != params - 2) return false; instr = (Instruction) iter.next(); if (instr.getOpcode() != opc_return) return false; - /* For valid bytecode the types matches automatically */ + /* We don't check if types matches. No problem since we only + * need to make sure, this constructor doesn't do anything + * more than relay to the real one. + */ reference = ref; kind = ACCESSCONSTRUCTOR; return true; diff --git a/jode/jode/type/NullType.java b/jode/jode/type/NullType.java index 1521b66..6fe8804 100644 --- a/jode/jode/type/NullType.java +++ b/jode/jode/type/NullType.java @@ -71,15 +71,4 @@ public class NullType extends ReferenceType { public String toString() { return "tNull"; } - - /** - * 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 == this) - return type; - return tError; - } }