From 1f87c3817cd76f1b8ce62251ed63dbe6fe153239 Mon Sep 17 00:00:00 2001 From: hoenicke Date: Mon, 5 Feb 2001 15:24:50 +0000 Subject: [PATCH] Changed version to 1.2 Add 2001 to copyright years. Better JSR/synchronized handling (see Changelog) Better .class field handling Fixed memory usage of UnifyHash. Fixed moving of field initializers. git-svn-id: https://svn.code.sf.net/p/jode/code/branches/branch_1_1@1298 379699f6-c40d-0410-875b-85095c16579e --- jode/ChangeLog | 37 ++ jode/configure.in | 2 +- jode/jode/GlobalOptions.java.in | 4 +- jode/jode/bytecode/BytecodeInfo.java.in | 15 + jode/jode/bytecode/ClassInfo.java.in | 2 +- jode/jode/bytecode/SearchPath.java | 38 +- jode/jode/decompiler/Main.java | 2 +- jode/jode/expr/IfThenElseOperator.java | 67 ++-- jode/jode/expr/InvokeOperator.java.in | 3 +- jode/jode/flow/CatchBlock.java.in | 12 + jode/jode/flow/EmptyBlock.java | 11 + jode/jode/flow/StructuredBlock.java.in | 12 + jode/jode/flow/TransformConstructors.java | 30 +- .../flow/TransformExceptionHandlers.java.in | 371 ++++++++---------- jode/jode/obfuscator/ClassBundle.java.in | 6 +- jode/jode/obfuscator/TranslationTable.java.in | 24 +- .../modules/ModifierMatcher.java.in | 2 +- jode/jode/type/ClassInterfacesType.java | 2 + jode/jode/util/UnifyHash.java.in | 75 ++-- 19 files changed, 395 insertions(+), 320 deletions(-) diff --git a/jode/ChangeLog b/jode/ChangeLog index ae45a2f..0ac85fe 100644 --- a/jode/ChangeLog +++ b/jode/ChangeLog @@ -1,3 +1,40 @@ +2001-02-04 Jochen Hoenicke + + * jode/expr/IfThenElseOperator.java (simplify): Allow in the class$ + simplification the then and else part to be swapped. + * jode/bytecode/ClassInfo.java.in (read): Accept class version + 1.3. + * jode/type/ClassInterfacesType.java (keywords): Added the package + and import keywords. + * jode/flow/TransformExceptionHandlers.java.in: + (getPredecessor): New function. + (getMonitorExitSlot): New function. + (skipFinExitChain): New function. + (removeJSR): Replaced by ... + (removeBadJSR): ... this. + (checkAndRemoveJSR): Use the new functions. Much simpler and + handles nested synchronized blocks. It now traces the whole JSR + and monitorexit chain before a jump to the first entry via + skipFinExitChain, then checks and remove the first JSR + resp. monitorexit. JSR jumps are simply ignored now. + (checkAndRemoveMonitorExit): likewise. + * jode/flow/StructuredBlock.java.in (prependBlock): New function. + * jode/flow/CatchBlock.java.in (makeDeclaration): Generate name + of dummyLocal, since nobody else will generate it. + +2001-02-03 Jochen Hoenicke + + * jode/bytecode/BytecodeInfo.java.in (read): Remove bogus + exceptionHandlers, whose catchers just throw the exception again. + This kind of entries are inserted by an obfuscator and would break + JODE. + * jode/util/UnifyHash.java.in (iterateHashCode): Call cleanUp, + to clean unneeded references. + * jode/flow/TransformConstructors.java (transformOneField): + Changed to private. Take field number as parameter. Check that + expression doesn't contain a FieldOperator for a later field of + the same class or a PutFieldOperator. Changed all callers. + 2001-02-01 Jochen Hoenicke * jode/jvm/CodeVerifier.java.in (Type.mergeType): If array elem diff --git a/jode/configure.in b/jode/configure.in index 6d141ff..3aea654 100644 --- a/jode/configure.in +++ b/jode/configure.in @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT() -AM_INIT_AUTOMAKE(jode, 1.0.93) +AM_INIT_AUTOMAKE(jode, 1.0.94) dnl Checks for programs. dnl AC_PROG_CXX diff --git a/jode/jode/GlobalOptions.java.in b/jode/jode/GlobalOptions.java.in index de63c2f..97cd37c 100644 --- a/jode/jode/GlobalOptions.java.in +++ b/jode/jode/GlobalOptions.java.in @@ -1,4 +1,4 @@ -/* GlobalOptions Copyright (C) 1999-2000 Jochen Hoenicke. +/* GlobalOptions Copyright (C) 1999-2001 Jochen Hoenicke. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ public class GlobalOptions { public final static String version = "@VERSION@"; public final static String email = "jochen@gnu.org"; public final static String copyright = - "Jode (c) 1998-2000 Jochen Hoenicke <"+email+">"; + "Jode (c) 1998-2001 Jochen Hoenicke <"+email+">"; public final static String URL = "http://jode.sourceforge.net/"; public static PrintWriter err = new PrintWriter(System.err, true); diff --git a/jode/jode/bytecode/BytecodeInfo.java.in b/jode/jode/bytecode/BytecodeInfo.java.in index 52decfc..5bdd291 100644 --- a/jode/jode/bytecode/BytecodeInfo.java.in +++ b/jode/jode/bytecode/BytecodeInfo.java.in @@ -847,6 +847,21 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { int index = input.readUnsignedShort(); exceptionHandlers[i].type = (index == 0) ? null : cp.getClassName(index); + + if (exceptionHandlers[i].catcher.getOpcode() == opc_athrow) { + /* There is an obfuscator, which inserts bogus + * exception entries jumping directly to a throw + * instruction. Remove those handlers. + */ + handlersLength--; + i--; + } + } + if (handlersLength < exceptionHandlers.length) { + Handler[] newHandlers = new Handler[handlersLength]; + System.arraycopy(exceptionHandlers, 0, newHandlers, 0, + handlersLength); + exceptionHandlers = newHandlers; } } readAttributes(cp, input, FULLINFO); diff --git a/jode/jode/bytecode/ClassInfo.java.in b/jode/jode/bytecode/ClassInfo.java.in index 4feceeb..35adcbd 100644 --- a/jode/jode/bytecode/ClassInfo.java.in +++ b/jode/jode/bytecode/ClassInfo.java.in @@ -288,7 +288,7 @@ public class ClassInfo extends BinaryInfo { int version = input.readUnsignedShort(); version |= input.readUnsignedShort() << 16; if (version < (45 << 16 | 0) - || version > (46 << 16 | 0)) + || version > (47 << 16 | 0)) throw new ClassFormatException("Wrong class version"); /* constant pool */ diff --git a/jode/jode/bytecode/SearchPath.java b/jode/jode/bytecode/SearchPath.java index 83b864c..1fdc52e 100644 --- a/jode/jode/bytecode/SearchPath.java +++ b/jode/jode/bytecode/SearchPath.java @@ -379,26 +379,26 @@ public class SearchPath { while ((ze = zis.getNextEntry()) != null) { if (ze.getName().equals(fullname)) { ///#ifdef JDK11 - // The skip method in jdk1.1.7 ZipInputStream - // is buggy. We return a wrapper that fixes - // this. - return new FilterInputStream(zis) { - private byte[] tmpbuf = new byte[512]; - public long skip(long n) throws IOException { - long skipped = 0; - while (n > 0) { - int count = read(tmpbuf, 0, - (int)Math.min(n, 512L)); - if (count == -1) - return skipped; - skipped += count; - n -= count; - } - return skipped; - } - }; +/// // The skip method in jdk1.1.7 ZipInputStream +/// // is buggy. We return a wrapper that fixes +/// // this. +/// return new FilterInputStream(zis) { +/// private byte[] tmpbuf = new byte[512]; +/// public long skip(long n) throws IOException { +/// long skipped = 0; +/// while (n > 0) { +/// int count = read(tmpbuf, 0, +/// (int)Math.min(n, 512L)); +/// if (count == -1) +/// return skipped; +/// skipped += count; +/// n -= count; +/// } +/// return skipped; +/// } +/// }; ///#else -/// return zis; + return zis; ///#endif } zis.closeEntry(); diff --git a/jode/jode/decompiler/Main.java b/jode/jode/decompiler/Main.java index b77f2f1..cad2858 100644 --- a/jode/jode/decompiler/Main.java +++ b/jode/jode/decompiler/Main.java @@ -1,4 +1,4 @@ -/* Main Copyright (C) 1998-1999 Jochen Hoenicke. +/* Main Copyright (C) 1998-2001 Jochen Hoenicke. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/jode/jode/expr/IfThenElseOperator.java b/jode/jode/expr/IfThenElseOperator.java index 33e2e6b..1e4ad3b 100644 --- a/jode/jode/expr/IfThenElseOperator.java +++ b/jode/jode/expr/IfThenElseOperator.java @@ -59,37 +59,46 @@ public class IfThenElseOperator extends Operator { } } if (subExpressions[0] instanceof CompareUnaryOperator - && (subExpressions[1] instanceof GetFieldOperator) - && (subExpressions[2] instanceof StoreInstruction)) { - // Check for - // class$classname != null ? class$classname : - // (class$classname = class$("classname")) - // and replace with - // classname.class + && ((((CompareUnaryOperator) subExpressions[0]) + .getOperatorIndex() & ~1) == Operator.COMPARE_OP)) { CompareUnaryOperator cmp = (CompareUnaryOperator) subExpressions[0]; - GetFieldOperator get = (GetFieldOperator) subExpressions[1]; - StoreInstruction put = (StoreInstruction) subExpressions[2]; - FieldAnalyzer field; - if (cmp.getOperatorIndex() == Operator.NOTEQUALS_OP - && put.getLValue() instanceof PutFieldOperator - && ((field = ((PutFieldOperator)put.getLValue()).getField()) - != null) && field.isSynthetic() - && put.lvalueMatches(get) - && cmp.subExpressions[0] instanceof GetFieldOperator - && put.lvalueMatches((GetFieldOperator)cmp.subExpressions[0]) - && put.subExpressions[1] instanceof InvokeOperator) { - InvokeOperator invoke = (InvokeOperator) put.subExpressions[1]; - if (invoke.isGetClass() - && invoke.subExpressions[0] instanceof ConstOperator - && (invoke.subExpressions[0].getType() - .equals(Type.tString))) { - String clazz = (String) - ((ConstOperator)invoke.subExpressions[0]).getValue(); - if (field.setClassConstant(clazz)) - return new ClassFieldOperator(clazz.charAt(0) == '[' - ? Type.tType(clazz) - : Type.tClass(clazz)); + int cmpType = cmp.getOperatorIndex() & 1; + if ((subExpressions[2 - cmpType] instanceof GetFieldOperator) + && (subExpressions[1 + cmpType] instanceof StoreInstruction)) { + // Check for + // class$classname != null ? class$classname : + // (class$classname = class$("classname")) + // and replace with + // classname.class + GetFieldOperator get + = (GetFieldOperator) subExpressions[2 - cmpType]; + StoreInstruction put + = (StoreInstruction) subExpressions[1 + cmpType]; + int opIndex = cmp.getOperatorIndex(); + FieldAnalyzer field; + if (put.getLValue() instanceof PutFieldOperator + && ((field = ((PutFieldOperator)put.getLValue()) + .getField()) != null) && field.isSynthetic() + && put.lvalueMatches(get) + && (cmp.subExpressions[0] instanceof GetFieldOperator) + && put.lvalueMatches((GetFieldOperator) + cmp.subExpressions[0]) + && put.subExpressions[1] instanceof InvokeOperator) { + InvokeOperator invoke = (InvokeOperator) + put.subExpressions[1]; + if (invoke.isGetClass() + && invoke.subExpressions[0] instanceof ConstOperator + && (invoke.subExpressions[0].getType() + .equals(Type.tString))) { + String clazz = (String) + ((ConstOperator)invoke.subExpressions[0]) + .getValue(); + if (field.setClassConstant(clazz)) + return new ClassFieldOperator + (clazz.charAt(0) == '[' + ? Type.tType(clazz) : Type.tClass(clazz)); + } } } } diff --git a/jode/jode/expr/InvokeOperator.java.in b/jode/jode/expr/InvokeOperator.java.in index 75c5d54..66423db 100644 --- a/jode/jode/expr/InvokeOperator.java.in +++ b/jode/jode/expr/InvokeOperator.java.in @@ -835,7 +835,8 @@ public final class InvokeOperator extends Operator * super class and anonymousNew will be set. */ InnerClassInfo outer = getOuterClassInfo(clazz); - if (outer != null && outer.name == null) + if (outer != null && outer.name == null + && (Options.options & Options.OPTION_ANON) != 0) anonymousNew = true; clazzAna = methodAnalyzer.getClassAnalyzer(clazz); if ((~Options.options & diff --git a/jode/jode/flow/CatchBlock.java.in b/jode/jode/flow/CatchBlock.java.in index bc24007..5a39548 100644 --- a/jode/jode/flow/CatchBlock.java.in +++ b/jode/jode/flow/CatchBlock.java.in @@ -20,6 +20,7 @@ package jode.flow; import jode.type.Type; import jode.decompiler.LocalInfo; +import jode.decompiler.Declarable; import jode.expr.Expression; import jode.expr.LocalLoadOperator; import jode.expr.LocalStoreOperator; @@ -27,6 +28,7 @@ import jode.expr.StoreInstruction; import jode.util.SimpleSet; import @COLLECTIONS@.Collections; +import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Set; @@ -160,6 +162,16 @@ public class CatchBlock extends StructuredBlock { ib.appendBlock(catchBlock); catchBlock = ib; exceptionLocal = dummyLocal; + String localName = dummyLocal.guessName(); + Iterator doneIter = done.iterator(); + while (doneIter.hasNext()) { + Declarable previous = (Declarable) doneIter.next(); + if (localName.equals(previous.getName())) { + /* A name conflict happened. */ + dummyLocal.makeNameUnique(); + break; + } + } } } } diff --git a/jode/jode/flow/EmptyBlock.java b/jode/jode/flow/EmptyBlock.java index 840e56b..1099934 100644 --- a/jode/jode/flow/EmptyBlock.java +++ b/jode/jode/flow/EmptyBlock.java @@ -56,6 +56,17 @@ public class EmptyBlock extends StructuredBlock { return block; } + /** + * Prepends a block to this block. + * @return the new combined block. + */ + public StructuredBlock prependBlock(StructuredBlock block) { + /* For empty blocks: append == prepend modulo jump */ + block = appendBlock(block); + block.moveJump(this.jump); + return block; + } + public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { diff --git a/jode/jode/flow/StructuredBlock.java.in b/jode/jode/flow/StructuredBlock.java.in index ed6e754..9d6a3e3 100644 --- a/jode/jode/flow/StructuredBlock.java.in +++ b/jode/jode/flow/StructuredBlock.java.in @@ -301,6 +301,18 @@ public abstract class StructuredBlock { } } + /** + * Prepends a block to this block. + * @return the new combined block. + */ + public StructuredBlock prependBlock(StructuredBlock block) { + SequentialBlock sequBlock = new SequentialBlock(); + sequBlock.replace(this); + sequBlock.setFirst(block); + sequBlock.setSecond(this); + return sequBlock; + } + /** * Removes this block, or replaces it with an EmptyBlock. */ diff --git a/jode/jode/flow/TransformConstructors.java b/jode/jode/flow/TransformConstructors.java index 1ea93ab..5ea7fa0 100644 --- a/jode/jode/flow/TransformConstructors.java +++ b/jode/jode/flow/TransformConstructors.java @@ -1,4 +1,4 @@ -/* TransformConstructors Copyright (C) 1998-1999 Jochen Hoenicke. +/* TransformConstructors Copyright (C) 1998-2001 Jochen Hoenicke. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -573,7 +573,8 @@ public class TransformConstructors { * @param expr the initializer to check * @return the transformed initializer or null if expr is not valid. */ - public Expression transformFieldInitializer(Expression expr) { + private Expression transformFieldInitializer(int fieldSlot, + Expression expr) { if (expr instanceof LocalVarOperator) { if (!(expr instanceof LocalLoadOperator)) { if ((GlobalOptions.debuggingFlags @@ -594,11 +595,21 @@ public class TransformConstructors { +" "+outerValues); return null; } + if (expr instanceof FieldOperator) { + if (expr instanceof PutFieldOperator) + return null; + FieldOperator fo = (FieldOperator) expr; + if (fo.getClassInfo() == clazzAnalyzer.getClazz() + && clazzAnalyzer.getFieldIndex(fo.getFieldName(), + fo.getFieldType()) >= fieldSlot) + return null; + } if (expr instanceof Operator) { Operator op = (Operator) expr; Expression[] subExpr = op.getSubExpressions(); for (int i=0; i< subExpr.length; i++) { - Expression transformed = transformFieldInitializer(subExpr[i]); + Expression transformed + = transformFieldInitializer(fieldSlot, subExpr[i]); if (transformed == null) return null; if (transformed != subExpr[i]) @@ -675,7 +686,7 @@ public class TransformConstructors { break big_loop; Expression expr = store.getSubExpressions()[1]; - expr = transformFieldInitializer(expr); + expr = transformFieldInitializer(field, expr); if (expr == null) break big_loop; @@ -762,8 +773,14 @@ public class TransformConstructors { } } + int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(), + pfo.getFieldType()); + + if (field <= lastField) + return -1; + Expression expr = store.getSubExpressions()[1]; - expr = transformFieldInitializer(expr); + expr = transformFieldInitializer(field, expr); if (expr == null) return -1; @@ -772,9 +789,6 @@ public class TransformConstructors { GlobalOptions.err.println(" field " + pfo.getFieldName() + " = " + expr); - int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(), - pfo.getFieldType()); - // if field does not exists: -1 <= lastField. if (field <= lastField || !(clazzAnalyzer.getField(field).setInitializer(expr))) { diff --git a/jode/jode/flow/TransformExceptionHandlers.java.in b/jode/jode/flow/TransformExceptionHandlers.java.in index f78e13a..82d04f6 100644 --- a/jode/jode/flow/TransformExceptionHandlers.java.in +++ b/jode/jode/flow/TransformExceptionHandlers.java.in @@ -180,11 +180,7 @@ public class TransformExceptionHandlers { * @param ret the ReturnBlock. */ private void removeReturnLocal(ReturnBlock ret) { - if (ret.outer == null - || !(ret.outer instanceof SequentialBlock)) - return; - - StructuredBlock pred = ret.outer.getSubBlocks()[0]; + StructuredBlock pred = getPredecessor(ret); if (!(pred instanceof InstructionBlock)) return; Expression instr = ((InstructionBlock) pred).getInstruction(); @@ -203,15 +199,13 @@ public class TransformExceptionHandlers { } /** - * Remove the JSR's jumping to the specified subRoutine. It - * is checked if the next block is a leaving instruction, and - * otherwise the JsrBlock is not removed (to give the user a - * hint that something went wrong). This will also remove the - * local javac generates for returns. + * Remove the wrongly placed JSRs jumping to the specified + * subRoutine. The right JSRs are already removed, but we have to + * replace the wrong ones with a warning. * @param tryFlow the FlowBLock of the try block. * @param subRoutine the FlowBlock of the sub routine. */ - private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock, + private void removeBadJSR(FlowBlock tryFlow, StructuredBlock catchBlock, FlowBlock subRoutine) { Jump nextJump; for (Jump jumps = tryFlow.getJumps(subRoutine); @@ -225,64 +219,96 @@ public class TransformExceptionHandlers { /* This is the mandatory jsr in the catch block */ continue; } - if (prev.outer.getNextFlowBlock() != null) { - /* The jsr is directly before a jump, okay. */ - tryFlow.removeSuccessor(jumps); - prev.removeJump(); - prev.outer.removeBlock(); - continue; - } - if (prev.outer.outer instanceof SequentialBlock - && prev.outer.outer.getSubBlocks()[0] == prev.outer) { - SequentialBlock seq = (SequentialBlock) prev.outer.outer; - if (seq.subBlocks[1] instanceof JsrBlock - || (seq.subBlocks[1] instanceof SequentialBlock - && seq.subBlocks[1].getSubBlocks()[0] - instanceof JsrBlock)) { - /* The jsr is followed by a jsr, okay. */ - tryFlow.removeSuccessor(jumps); - prev.removeJump(); - prev.outer.removeBlock(); - continue; - } - if (seq.subBlocks[1] instanceof ReturnBlock - && !(seq.subBlocks[1] instanceof ThrowBlock)) { - - /* The jsr is followed by a return, okay. */ - tryFlow.removeSuccessor(jumps); - prev.removeJump(); - ReturnBlock ret = (ReturnBlock) seq.subBlocks[1]; - prev.outer.removeBlock(); - - removeReturnLocal(ret); - continue; - } - } + /* We have a JSR to the subroutine, which is badly placed. + * We complain here. + */ + DescriptionBlock msg + = new DescriptionBlock("ERROR: JSR FINALLY BLOCK!"); + tryFlow.removeSuccessor(jumps); + prev.removeJump(); + msg.replace(prev.outer); + } else { + /* We have a jump to the subroutine, that is wrong. + * We complain here. + */ + DescriptionBlock msg + = new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!"); + tryFlow.removeSuccessor(jumps); + prev.removeJump(); + prev.appendBlock(msg); + } + } + } + + private static StructuredBlock getPredecessor(StructuredBlock stmt) + { + if (stmt.outer instanceof SequentialBlock) { + SequentialBlock seq = (SequentialBlock) stmt.outer; + if (seq.subBlocks[1] == stmt) + return seq.subBlocks[0]; + else if (seq.outer instanceof SequentialBlock) + return seq.outer.getSubBlocks()[0]; + } + return null; + } + + /** + * Gets the slot of the monitorexit instruction instr in the + * stmt, or -1 if stmt isn't a InstructionBlock with a + * monitorexit instruction. + * @param stmt the stmt, may be null. + */ + private static int getMonitorExitSlot(StructuredBlock stmt) { + if (stmt instanceof InstructionBlock) { + Expression instr = ((InstructionBlock) stmt).getInstruction(); + if (instr instanceof MonitorExitOperator) { + MonitorExitOperator monExit = (MonitorExitOperator)instr; + if (monExit.getFreeOperandCount() == 0 + && (monExit.getSubExpressions()[0] + instanceof LocalLoadOperator)) + return ((LocalLoadOperator) monExit.getSubExpressions()[0]) + .getLocalInfo().getSlot(); } - /* Now we have a jump to the subroutine, that is wrong. - * We complain here. - */ - DescriptionBlock msg - = new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!"); - tryFlow.removeSuccessor(jumps); - prev.removeJump(); - prev.appendBlock(msg); } + return -1; } - public void checkAndRemoveJSR(FlowBlock tryFlow, - StructuredBlock catchBlock, - FlowBlock subRoutine, - int startOutExit, int endOutExit) { - boolean foundSub = false; + private boolean isMonitorExitSubRoutine(FlowBlock subRoutine, + LocalInfo local) { + if (transformSubRoutine(subRoutine.block) + && getMonitorExitSlot(subRoutine.block) == local.getSlot()) + return true; + return false; + } + + private static StructuredBlock skipFinExitChain(StructuredBlock block) + { + StructuredBlock pred, result; + if (block instanceof ReturnBlock) + pred = getPredecessor(block); + else + pred = block; + result = null; + + while (pred instanceof JsrBlock + || getMonitorExitSlot(pred) >= 0) { + result = pred; + pred = getPredecessor(pred); + } + return result; + } + + + private void checkAndRemoveJSR(FlowBlock tryFlow, + StructuredBlock catchBlock, + FlowBlock subRoutine, + int startOutExit, int endOutExit) { Iterator iter = tryFlow.getSuccessors().iterator(); dest_loop: while (iter.hasNext()) { FlowBlock dest = (FlowBlock) iter.next(); - if (dest == subRoutine) { - foundSub = true; + if (dest == subRoutine) continue dest_loop; - } boolean isFirstJump = true; for (Jump jumps = tryFlow.getJumps(dest); @@ -295,41 +321,34 @@ public class TransformExceptionHandlers { */ continue; } - if (prev instanceof JsrBlock) { - /* The jump is directly preceeded by a jsr. - * Everything okay. - */ - continue; - } - if (prev instanceof EmptyBlock && prev.outer instanceof JsrBlock) { - /* If jump is a jsr check the outer - * block instead. - */ - prev = prev.outer; - } - if ((prev instanceof ReturnBlock - || prev instanceof JsrBlock) - && prev.outer instanceof SequentialBlock) { - SequentialBlock seq = (SequentialBlock) prev.outer; - if (seq.subBlocks[1] == prev - && (seq.subBlocks[0] instanceof JsrBlock)) { - /* The jump is preceeded by another jsr, okay. - */ - continue; - } - if (seq.subBlocks[0] == prev - && seq.outer instanceof SequentialBlock - && (seq.outer.getSubBlocks()[0] instanceof JsrBlock)) { - /* Again the jump is preceeded by another jsr, okay. - */ - continue; - } + /* This jump is really a jsr, since it doesn't + * leave the block forever, we can ignore it. + */ + continue; } + StructuredBlock pred = skipFinExitChain(prev); + + if (pred instanceof JsrBlock) { + StructuredBlock jsrInner = ((JsrBlock) pred).innerBlock; + if (jsrInner instanceof EmptyBlock + && jsrInner.jump != null + && jsrInner.jump.destination == subRoutine) { + /* The jump is preceeded by the right jsr. Remove + * the jsr. + */ + tryFlow.removeSuccessor(jsrInner.jump); + jsrInner.removeJump(); + pred.removeBlock(); + if (prev instanceof ReturnBlock) + removeReturnLocal((ReturnBlock) prev); + continue; + } + } - if (isFirstJump) { - /* Now we have a jump that is not preceded by the + if (pred == null && isFirstJump) { + /* Now we have a jump that is not preceded by any * jsr. There's a last chance: the jump jumps * directly to a correct jsr instruction, which * lies outside the try/catch block. @@ -360,45 +379,21 @@ public class TransformExceptionHandlers { */ DescriptionBlock msg = new DescriptionBlock("ERROR: NO JSR TO FINALLY"); - prev.appendBlock(msg); - msg.moveJump(jumps); - } - } - if (foundSub) - removeJSR(tryFlow, catchBlock, subRoutine); - } - - static boolean isMonitorExit(Expression instr, LocalInfo local) { - if (instr instanceof MonitorExitOperator) { - MonitorExitOperator monExit = (MonitorExitOperator)instr; - if (monExit.getFreeOperandCount() == 0 - && monExit.getSubExpressions()[0] instanceof LocalLoadOperator - && (((LocalLoadOperator) monExit.getSubExpressions()[0]) - .getLocalInfo().getSlot() == local.getSlot())) { - return true; + if (pred != null) + pred.prependBlock(msg); + else { + prev.appendBlock(msg); + msg.moveJump(prev.jump); + } } } - return false; + removeBadJSR(tryFlow, catchBlock, subRoutine); } - boolean isMonitorExitSubRoutine(FlowBlock subRoutine, LocalInfo local) { - if (transformSubRoutine(subRoutine.block)) { - if (subRoutine.block instanceof InstructionBlock) { - Expression instr = - ((InstructionBlock)subRoutine.block) - .getInstruction(); - if (isMonitorExit(instr, local)) { - return true; - } - } - } - return false; - } - - public void checkAndRemoveMonitorExit(FlowBlock tryFlow, - StructuredBlock catchBlock, - LocalInfo local, - int start, int end) { + private void checkAndRemoveMonitorExit(FlowBlock tryFlow, + StructuredBlock catchBlock, + LocalInfo local, + int start, int end) { FlowBlock subRoutine = null; Iterator succs = tryFlow.getSuccessors().iterator(); dest_loop: @@ -409,91 +404,57 @@ public class TransformExceptionHandlers { jumps != null; jumps = jumps.next, isFirstJump = false) { StructuredBlock prev = jumps.prev; - if (prev instanceof ThrowBlock) { - /* The jump is a throw. We have a catch all block - * that will do the monitorexit. - */ - continue; - } - if (prev instanceof JsrBlock) { - /* The jump is directly preceeded by a jsr. + /* The jump is a throw. We have a catch-all block + * that will do the finally. */ continue; } if (prev instanceof EmptyBlock && prev.outer instanceof JsrBlock) { - /* If jump is a jsr check the outer - * block instead. - */ - prev = prev.outer; - } - - /* If the block is a jsr or a return block, check if - * it is preceeded by another jsr. - */ - if ((prev instanceof JsrBlock - || prev instanceof ReturnBlock) - && prev.outer instanceof SequentialBlock) { - SequentialBlock seq = (SequentialBlock) prev.outer; - StructuredBlock pred = null; - if (seq.subBlocks[1] == prev) - pred = seq.subBlocks[0]; - else if (seq.outer instanceof SequentialBlock) - pred = seq.outer.getSubBlocks()[0]; - - if (pred != null) { - if (pred instanceof JsrBlock) - /* The jump is preceeded by another jsr, okay. - */ - continue; - - if (pred instanceof InstructionBlock) { - Expression instr = - ((InstructionBlock)pred).getInstruction(); - if (isMonitorExit(instr, local)) { - pred.removeBlock(); - if (prev instanceof ReturnBlock) - removeReturnLocal((ReturnBlock) prev); - continue; - } - } - } - } - - if (prev instanceof InstructionBlock - && isMonitorExit(((InstructionBlock)prev).instr, local)) { - /* This is probably the last expression in the - * synchronized block, and has the right monitor exit - * attached. Remove this block. - */ - prev.removeBlock(); - continue; - } - - if (isFirstJump) { - /* This is the first jump to that destination. - * Check if the destination does the monitorExit + /* This jump is really a jsr, since it doesn't + * leave the block forever, we can ignore it. */ + continue; + } + StructuredBlock pred = skipFinExitChain(prev); + if (pred instanceof JsrBlock) { + StructuredBlock jsrInner = ((JsrBlock) pred).innerBlock; + if (jsrInner instanceof EmptyBlock + && jsrInner.jump != null) { + FlowBlock dest = jsrInner.jump.destination; - /* The block is a jsr that is not preceeded by - * another jsr. This must be the monitorexit - * subroutine. - */ - if (prev instanceof JsrBlock) { if (subRoutine == null - && successor.getAddr() >= start - && successor.getNextAddr() <= end) { - successor.analyze(start, end); - - if (isMonitorExitSubRoutine(successor, local)) - subRoutine = successor; + && dest.getAddr() >= start + && dest.getNextAddr() <= end) { + dest.analyze(start, end); + if (isMonitorExitSubRoutine(dest, local)) + subRoutine = dest; } - if (subRoutine == successor) - continue dest_loop; + if (dest == subRoutine) { + /* The jump is preceeded by the right jsr. Remove + * the jsr. + */ + tryFlow.removeSuccessor(jsrInner.jump); + jsrInner.removeJump(); + pred.removeBlock(); + if (prev instanceof ReturnBlock) + removeReturnLocal((ReturnBlock) prev); + continue; + } } + } else if (getMonitorExitSlot(pred) == local.getSlot()) { + /* The jump is preceeded by the right monitor + * exit instruction. + */ + pred.removeBlock(); + if (prev instanceof ReturnBlock) + removeReturnLocal((ReturnBlock) prev); + continue; + } + if (pred == null && isFirstJump) { /* Now we have a jump that is not preceded by a * monitorexit. There's a last chance: the jump * jumps directly to the correct monitorexit @@ -521,17 +482,15 @@ public class TransformExceptionHandlers { } if (subRoutine == dest) { + successor.removeSuccessor(jsrInner.jump); + jsrInner.removeJump(); sb.removeBlock(); continue dest_loop; } } - if (sb instanceof InstructionBlock) { - Expression instr = ((InstructionBlock)sb) - .getInstruction(); - if (isMonitorExit(instr, local)) { - sb.removeBlock(); - continue dest_loop; - } + if (getMonitorExitSlot(sb) == local.getSlot()) { + sb.removeBlock(); + continue dest_loop; } } } @@ -546,7 +505,7 @@ public class TransformExceptionHandlers { } if (subRoutine != null) { - removeJSR(tryFlow, catchBlock, subRoutine); + removeBadJSR(tryFlow, catchBlock, subRoutine); tryFlow.mergeAddr(subRoutine); } } diff --git a/jode/jode/obfuscator/ClassBundle.java.in b/jode/jode/obfuscator/ClassBundle.java.in index 361e7d3..b2ced86 100644 --- a/jode/jode/obfuscator/ClassBundle.java.in +++ b/jode/jode/obfuscator/ClassBundle.java.in @@ -38,7 +38,7 @@ import @COLLECTIONS@.TreeMap; import @COLLECTIONEXTRA@.UnsupportedOperationException; ///#ifdef JDK12 -///import @COLLECTIONS@.WeakHashMap; +import @COLLECTIONS@.WeakHashMap; ///#endif public class ClassBundle implements OptionHandler { @@ -74,9 +74,9 @@ public class ClassBundle implements OptionHandler { } ///#ifdef JDK12 -/// private static final Map aliasesHash = new WeakHashMap(); + private static final Map aliasesHash = new WeakHashMap(); ///#else - private static final Map aliasesHash = new HashMap(); +/// private static final Map aliasesHash = new HashMap(); ///#endif private static final Map clazzCache = new HashMap(); private static final Map referenceCache = new HashMap(); diff --git a/jode/jode/obfuscator/TranslationTable.java.in b/jode/jode/obfuscator/TranslationTable.java.in index 40d8574..4247046 100644 --- a/jode/jode/obfuscator/TranslationTable.java.in +++ b/jode/jode/obfuscator/TranslationTable.java.in @@ -24,7 +24,7 @@ import @COLLECTIONS@.TreeMap; import @COLLECTIONS@.Iterator; ///#ifndef JDK12 -import @COLLECTIONS@.Comparator; +///import @COLLECTIONS@.Comparator; ///#endif import java.io.InputStream; @@ -37,17 +37,17 @@ import java.io.IOException; public class TranslationTable extends TreeMap { ///#ifndef JDK12 - public TranslationTable() { - super(createStringComparator()); - } - - private static Comparator createStringComparator() { - return new Comparator() { - public int compare(Object o1, Object o2) { - return ((String) o1).compareTo((String) o2); - } - }; - } +/// public TranslationTable() { +/// super(createStringComparator()); +/// } +/// +/// private static Comparator createStringComparator() { +/// return new Comparator() { +/// public int compare(Object o1, Object o2) { +/// return ((String) o1).compareTo((String) o2); +/// } +/// }; +/// } ///#endif public void load(InputStream in) throws IOException { diff --git a/jode/jode/obfuscator/modules/ModifierMatcher.java.in b/jode/jode/obfuscator/modules/ModifierMatcher.java.in index 1c8d176..8d36c49 100644 --- a/jode/jode/obfuscator/modules/ModifierMatcher.java.in +++ b/jode/jode/obfuscator/modules/ModifierMatcher.java.in @@ -109,7 +109,7 @@ public class ModifierMatcher implements IdentifierMatcher, OptionHandler, Clonea : str.equals("NATIVE") ? Modifier.NATIVE : str.equals("STATIC") ? Modifier.STATIC ///#ifdef JDK12 -/// : str.equals("STRICT") ? Modifier.STRICT + : str.equals("STRICT") ? Modifier.STRICT ///#endif : str.equals("SYNCHRONIZED") ? Modifier.SYNCHRONIZED : str.equals("TRANSIENT") ? Modifier.TRANSIENT diff --git a/jode/jode/type/ClassInterfacesType.java b/jode/jode/type/ClassInterfacesType.java index 0f00bfe..ce24875 100644 --- a/jode/jode/type/ClassInterfacesType.java +++ b/jode/jode/type/ClassInterfacesType.java @@ -509,6 +509,8 @@ public class ClassInterfacesType extends ReferenceType { private final static Hashtable keywords = new Hashtable(); static { + keywords.put("package", Boolean.TRUE); + keywords.put("import", Boolean.TRUE); keywords.put("if", Boolean.TRUE); keywords.put("else", Boolean.TRUE); keywords.put("for", Boolean.TRUE); diff --git a/jode/jode/util/UnifyHash.java.in b/jode/jode/util/UnifyHash.java.in index 8c5104c..a5661ce 100644 --- a/jode/jode/util/UnifyHash.java.in +++ b/jode/jode/util/UnifyHash.java.in @@ -1,4 +1,4 @@ -/* UnifyHash Copyright (C) 1999 Jochen Hoenicke. +/* UnifyHash Copyright (C) 1999-2001 Jochen Hoenicke. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +19,8 @@ package jode.util; ///#ifdef JDK12 -///import java.lang.ref.WeakReference; -///import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.lang.ref.ReferenceQueue; ///#endif import @COLLECTIONS@.Comparator; @@ -40,28 +40,28 @@ public class UnifyHash extends AbstractCollection { private static final float DEFAULT_LOAD_FACTOR = 0.75F; ///#ifdef JDK12 -/// private ReferenceQueue queue = new ReferenceQueue(); + private ReferenceQueue queue = new ReferenceQueue(); ///#endif static class Bucket ///#ifdef JDK12 -/// extends WeakReference + extends WeakReference ///#endif { ///#ifdef JDK12 -/// public Bucket(Object o, ReferenceQueue q) { -/// super(o, q); -/// } -///#else - public Bucket(Object o) { - this.obj = o; - } - - Object obj; - - public Object get() { - return obj; + public Bucket(Object o, ReferenceQueue q) { + super(o, q); } +///#else +/// public Bucket(Object o) { +/// this.obj = o; +/// } +/// +/// Object obj; +/// +/// public Object get() { +/// return obj; +/// } ///#endif int hash; @@ -107,21 +107,21 @@ public class UnifyHash extends AbstractCollection { } ///#ifdef JDK12 -/// public final void cleanUp() { -/// Bucket died; -/// while ((died = (Bucket)queue.poll()) != null) { -/// int diedSlot = Math.abs(died.hash % buckets.length); -/// if (buckets[diedSlot] == died) -/// buckets[diedSlot] = died.next; -/// else { -/// Bucket b = buckets[diedSlot]; -/// while (b.next != died) -/// b = b.next; -/// b.next = died.next; -/// } -/// size--; -/// } -/// } + public final void cleanUp() { + Bucket died; + while ((died = (Bucket)queue.poll()) != null) { + int diedSlot = Math.abs(died.hash % buckets.length); + if (buckets[diedSlot] == died) + buckets[diedSlot] = died.next; + else { + Bucket b = buckets[diedSlot]; + while (b.next != died) + b = b.next; + b.next = died.next; + } + size--; + } + } ///#endif @@ -131,7 +131,7 @@ public class UnifyHash extends AbstractCollection { public Iterator iterator() { ///#ifdef JDK12 -/// cleanUp(); + cleanUp(); ///#endif return new Iterator() { @@ -182,6 +182,9 @@ public class UnifyHash extends AbstractCollection { } public Iterator iterateHashCode(final int hash) { +///#ifdef JDK12 + cleanUp(); +///#endif return new Iterator() { private int known = modCount; private Bucket nextBucket @@ -232,9 +235,9 @@ public class UnifyHash extends AbstractCollection { int slot = Math.abs(hash % buckets.length); ///#ifdef JDK12 -/// Bucket b = new Bucket(o, queue); + Bucket b = new Bucket(o, queue); ///#else - Bucket b = new Bucket(o); +/// Bucket b = new Bucket(o); ///#endif b.hash = hash; b.next = buckets[slot]; @@ -243,7 +246,7 @@ public class UnifyHash extends AbstractCollection { public Object unify(Object o, int hash, Comparator comparator) { ///#ifdef JDK12 -/// cleanUp(); + cleanUp(); ///#endif int slot = Math.abs(hash % buckets.length); for (Bucket b = buckets[slot]; b != null; b = b.next) {