diff --git a/jode/ChangeLog b/jode/ChangeLog index 0daf342..ae45a2f 100644 --- a/jode/ChangeLog +++ b/jode/ChangeLog @@ -1,3 +1,15 @@ +2001-02-01 Jochen Hoenicke + + * jode/jvm/CodeVerifier.java.in (Type.mergeType): If array elem + types can't be merged, return tObject as common super type. + * jode/type/ArrayType.java (getGeneralizedType): If array elem + type can't be intersected, return tObject as common super type. + * jode/flow/TransformExceptionHandlers.java.in: Merged patch from + the 1.2 tree to support javac 1.3 synchronized blocks. Doesn't + handle nested synchronized blocks yet. + * jode/expr/Expression.java.in (dumpExpression): Show runtime + exception when it occurs. + 2001-01-31 Jochen Hoenicke * jode/expr/Expression.java.in (updateParentTypes): Call setType, diff --git a/jode/jode/expr/Expression.java.in b/jode/jode/expr/Expression.java.in index 4d0a4bc..ad6ed84 100644 --- a/jode/jode/expr/Expression.java.in +++ b/jode/jode/expr/Expression.java.in @@ -53,7 +53,7 @@ public abstract class Expression { } public void updateParentType(Type otherType) { - setType(newType); + setType(otherType); if (parent != null) parent.updateType(); } @@ -283,6 +283,7 @@ public abstract class Expression { dumpExpression(writer); } catch (RuntimeException ex) { writer.print("(RUNTIME ERROR IN EXPRESSION)"); + ex.printStackTrace(GlobalOptions.err); } if (needEndOp2) { diff --git a/jode/jode/flow/FlowBlock.java.in b/jode/jode/flow/FlowBlock.java.in index b7a2e83..b1e575e 100644 --- a/jode/jode/flow/FlowBlock.java.in +++ b/jode/jode/flow/FlowBlock.java.in @@ -1708,7 +1708,8 @@ public class FlowBlock { java.io.StringWriter strw = new java.io.StringWriter(); TabbedPrintWriter writer = new TabbedPrintWriter(strw); writer.println(super.toString() + ": "+addr+"-"+(addr+length)); - if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_INOUT) != 0) { writer.println("in: "+in); } writer.tab(); diff --git a/jode/jode/flow/TransformExceptionHandlers.java.in b/jode/jode/flow/TransformExceptionHandlers.java.in index 1b20429..f78e13a 100644 --- a/jode/jode/flow/TransformExceptionHandlers.java.in +++ b/jode/jode/flow/TransformExceptionHandlers.java.in @@ -109,16 +109,12 @@ public class TransformExceptionHandlers { * | ... * `- catch block */ - static void analyzeCatchBlock(Type type, - FlowBlock tryFlow, FlowBlock catchFlow) { - - StructuredBlock catchBlock = catchFlow.block; + static void analyzeCatchBlock(Type type, FlowBlock tryFlow, + StructuredBlock catchBlock) { CatchBlock newBlock = new CatchBlock(type); ((TryBlock)tryFlow.block).addCatchBlock(newBlock); - newBlock.setCatchBlock(catchFlow.block); - tryFlow.mergeSuccessors(catchFlow); - tryFlow.mergeAddr(catchFlow); + newBlock.setCatchBlock(catchBlock); } /* And now the complicated parts. */ @@ -128,42 +124,82 @@ public class TransformExceptionHandlers { * local assignment matches the final ret and then returns. */ boolean transformSubRoutine(StructuredBlock subRoutine) { - if (!(subRoutine instanceof SequentialBlock) - || !(subRoutine.getSubBlocks()[0] instanceof InstructionBlock)) - return false; + if (!(subRoutine instanceof SequentialBlock)) + return false; SequentialBlock sequBlock = (SequentialBlock) subRoutine; - InstructionBlock instr = (InstructionBlock)sequBlock.subBlocks[0]; - - if (!(instr.getInstruction() instanceof StoreInstruction) - || !(((StoreInstruction) instr.getInstruction()).getLValue() - instanceof LocalStoreOperator)) - return false; - LocalStoreOperator store = (LocalStoreOperator) - ((StoreInstruction)instr.getInstruction()).getLValue(); - - while (sequBlock.subBlocks[1] instanceof SequentialBlock) - sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; - - /* XXX - Check that the local isn't used for any other purposes - * than RET and replace any RET with a flow control to end of - * flow block. + StructuredBlock firstBlock = sequBlock.getSubBlocks()[0]; + + LocalInfo local = null; + if (firstBlock instanceof SpecialBlock) { + SpecialBlock popBlock + = (SpecialBlock) firstBlock; + if (popBlock.type != SpecialBlock.POP + || popBlock.count != 1) + return false; + } else if (firstBlock instanceof InstructionBlock) { + Expression expr + = ((InstructionBlock) firstBlock).getInstruction(); + if (expr instanceof StoreInstruction + && ((StoreInstruction) + expr).getLValue() instanceof LocalStoreOperator) { + LocalStoreOperator store = (LocalStoreOperator) + ((StoreInstruction)expr).getLValue(); + local = store.getLocalInfo(); + expr = ((StoreInstruction) expr).getSubExpressions()[1]; + } + if (!(expr instanceof NopOperator)) + return false; + } else + return false; + + /* We have now committed. Remove the first Statement which + * stores/removes the return address. + */ + firstBlock.removeBlock(); + + /* XXX - Replace any RET with a jump to end of this flow block. * - * This is a complicated task which isn't needed for javac nor jikes. + * This is a complicated task which isn't needed for javac nor + * jikes. We just check if the last instruction is a ret and + * replace this. This will never produce code with wrong semantic, + * as long as the bytecode was verified correctly. */ - if (sequBlock.subBlocks[1].jump != null - && sequBlock.subBlocks[1].jump.destination - == FlowBlock.END_OF_METHOD) { - instr.removeBlock(); - return true; + while (sequBlock.subBlocks[1] instanceof SequentialBlock) + sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; + + if (sequBlock.subBlocks[1] instanceof RetBlock + && (((RetBlock) sequBlock.subBlocks[1]).local.equals(local))) { + sequBlock.subBlocks[1].removeBlock(); } - if (! (sequBlock.subBlocks[1] instanceof RetBlock) - || !(((RetBlock)sequBlock.subBlocks[1]) - .local.equals(store.getLocalInfo()))) - return false; - - instr.removeBlock(); - sequBlock.subBlocks[1].removeBlock(); - return true; + return true; + } + + /** + * Remove the locale that javac introduces to temporary store the return + * value, when it executes a finally block resp. monitorexit + * @param ret the ReturnBlock. + */ + private void removeReturnLocal(ReturnBlock ret) { + if (ret.outer == null + || !(ret.outer instanceof SequentialBlock)) + return; + + StructuredBlock pred = ret.outer.getSubBlocks()[0]; + if (!(pred instanceof InstructionBlock)) + return; + Expression instr = ((InstructionBlock) pred).getInstruction(); + if (!(instr instanceof StoreInstruction)) + return; + + Expression retInstr = ret.getInstruction(); + if (!(retInstr instanceof LocalLoadOperator + && ((StoreInstruction) instr).lvalueMatches + ((LocalLoadOperator) retInstr))) + return; + + Expression rvalue = ((StoreInstruction) instr).getSubExpressions()[1]; + ret.setInstruction(rvalue); + ret.replace(ret.outer); } /** @@ -175,16 +211,24 @@ public class TransformExceptionHandlers { * @param tryFlow the FlowBLock of the try block. * @param subRoutine the FlowBlock of the sub routine. */ - private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) { - for (Jump jumps = tryFlow.removeJumps(subRoutine); - jumps != null; jumps = jumps.next) { + private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock, + FlowBlock subRoutine) { + Jump nextJump; + for (Jump jumps = tryFlow.getJumps(subRoutine); + jumps != null; jumps = nextJump) { StructuredBlock prev = jumps.prev; - prev.removeJump(); + nextJump = jumps.next; if (prev instanceof EmptyBlock && prev.outer instanceof JsrBlock) { + if (prev.outer == catchBlock) { + /* 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; } @@ -196,6 +240,8 @@ public class TransformExceptionHandlers { && seq.subBlocks[1].getSubBlocks()[0] instanceof JsrBlock)) { /* The jsr is followed by a jsr, okay. */ + tryFlow.removeSuccessor(jumps); + prev.removeJump(); prev.outer.removeBlock(); continue; } @@ -203,33 +249,12 @@ public class TransformExceptionHandlers { && !(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(); - if (ret.outer != null - && ret.outer instanceof SequentialBlock) { - /* Try to eliminate the local that javac uses - * in this case. - */ - try { - StoreInstruction store = (StoreInstruction) - ((InstructionBlock) - ret.outer.getSubBlocks()[0]).instr; - LocalInfo local = - ((LocalStoreOperator) store.getLValue()) - .getLocalInfo(); - if (store.lvalueMatches - ((LocalLoadOperator) - ret.getInstruction())) { - Expression expr = - store.getSubExpressions()[1]; - ret.setInstruction(expr); - ret.replace(ret.outer); - } - } catch(ClassCastException ex) { - /* didn't succeed */ - } - } + removeReturnLocal(ret); continue; } } @@ -239,11 +264,15 @@ public class TransformExceptionHandlers { */ DescriptionBlock msg = new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!"); + tryFlow.removeSuccessor(jumps); + prev.removeJump(); prev.appendBlock(msg); } } - public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine, + public void checkAndRemoveJSR(FlowBlock tryFlow, + StructuredBlock catchBlock, + FlowBlock subRoutine, int startOutExit, int endOutExit) { boolean foundSub = false; Iterator iter = tryFlow.getSuccessors().iterator(); @@ -336,7 +365,7 @@ public class TransformExceptionHandlers { } } if (foundSub) - removeJSR(tryFlow, subRoutine); + removeJSR(tryFlow, catchBlock, subRoutine); } static boolean isMonitorExit(Expression instr, LocalInfo local) { @@ -366,9 +395,10 @@ public class TransformExceptionHandlers { return false; } - public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local, - int startOutExit, int endOutExit, - int startMonExit, int endMonExit) { + public void checkAndRemoveMonitorExit(FlowBlock tryFlow, + StructuredBlock catchBlock, + LocalInfo local, + int start, int end) { FlowBlock subRoutine = null; Iterator succs = tryFlow.getSuccessors().iterator(); dest_loop: @@ -421,8 +451,12 @@ public class TransformExceptionHandlers { if (pred instanceof InstructionBlock) { Expression instr = ((InstructionBlock)pred).getInstruction(); - if (isMonitorExit(instr, local)) + if (isMonitorExit(instr, local)) { + pred.removeBlock(); + if (prev instanceof ReturnBlock) + removeReturnLocal((ReturnBlock) prev); continue; + } } } } @@ -448,9 +482,9 @@ public class TransformExceptionHandlers { */ if (prev instanceof JsrBlock) { if (subRoutine == null - && successor.getAddr() >= startMonExit - && successor.getNextAddr() <= endMonExit) { - successor.analyze(startMonExit, endMonExit); + && successor.getAddr() >= start + && successor.getNextAddr() <= end) { + successor.analyze(start, end); if (isMonitorExitSubRoutine(successor, local)) subRoutine = successor; @@ -467,9 +501,9 @@ public class TransformExceptionHandlers { * block. */ if (successor.predecessors.size() == 1 - && successor.getAddr() >= startOutExit - && successor.getNextAddr() <= endOutExit) { - successor.analyze(startOutExit, endOutExit); + && successor.getAddr() >= start + && successor.getNextAddr() <= end) { + successor.analyze(start, end); StructuredBlock sb = successor.block; if (sb instanceof SequentialBlock) @@ -479,9 +513,9 @@ public class TransformExceptionHandlers { StructuredBlock jsrInner = sb.getSubBlocks()[0]; FlowBlock dest = jsrInner.jump.destination; if (subRoutine == null - && dest.getAddr() >= startMonExit - && dest.getNextAddr() <= endMonExit) { - dest.analyze(startMonExit, endMonExit); + && dest.getAddr() >= start + && dest.getNextAddr() <= end) { + dest.analyze(start, end); if (isMonitorExitSubRoutine(dest, local)) subRoutine = dest; } @@ -512,126 +546,147 @@ public class TransformExceptionHandlers { } if (subRoutine != null) { - removeJSR(tryFlow, subRoutine); + removeJSR(tryFlow, catchBlock, subRoutine); tryFlow.mergeAddr(subRoutine); } } + private StoreInstruction getExceptionStore(StructuredBlock catchBlock) { + if (!(catchBlock instanceof SequentialBlock) + || !(catchBlock.getSubBlocks()[0] instanceof InstructionBlock)) + return null; + + Expression instr = + ((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction(); + if (!(instr instanceof StoreInstruction)) + return null; + + StoreInstruction store = (StoreInstruction) instr; + if (!(store.getLValue() instanceof LocalStoreOperator + && store.getSubExpressions()[1] instanceof NopOperator)) + return null; + + return store; + } + private boolean analyzeSynchronized(FlowBlock tryFlow, - FlowBlock catchFlow, + StructuredBlock catchBlock, int endHandler) { - if (!(catchFlow.block instanceof SequentialBlock - && catchFlow.block.getSubBlocks()[0] + StoreInstruction excStore = getExceptionStore(catchBlock); + if (excStore != null) + catchBlock = catchBlock.getSubBlocks()[1]; + + if (!(catchBlock instanceof SequentialBlock + && catchBlock.getSubBlocks()[0] instanceof InstructionBlock)) return false; - SequentialBlock catchBlock = (SequentialBlock) catchFlow.block; Expression instr = - ((InstructionBlock)catchBlock.subBlocks[0]).getInstruction(); + ((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction(); - if (instr instanceof MonitorExitOperator - && instr.getFreeOperandCount() == 0 - && (((MonitorExitOperator)instr).getSubExpressions()[0] - instanceof LocalLoadOperator) - && catchBlock.subBlocks[1] instanceof ThrowBlock - && (((ThrowBlock)catchBlock.subBlocks[1]).instr - instanceof NopOperator)) { - - /* This is a synchronized block: - * - * local_x = monitor object; // later - * monitorenter local_x // later - * tryFlow: - * |- synchronized block - * | ... - * | every jump to outside is preceded by jsr subroutine-, - * | ... | - * |- monitorexit local_x | - * ` jump after this block (without jsr monexit) | - * | - * catchFlow: | - * local_n = stack | - * monitorexit local_x | - * throw local_n | - * optional subroutine: <-----------------------------------' - * astore_n - * monitorexit local_x - * return_n - */ + if (!(instr instanceof MonitorExitOperator + && instr.getFreeOperandCount() == 0 + && (((MonitorExitOperator)instr).getSubExpressions()[0] + instanceof LocalLoadOperator) + && catchBlock.getSubBlocks()[1] instanceof ThrowBlock)) + return false; - /* Now remove the jump (after the throw) from the - * catch block so that we can forget about it. - */ - - catchFlow.removeSuccessor(catchBlock.subBlocks[1].jump); - MonitorExitOperator monexit = (MonitorExitOperator) - ((InstructionBlock) catchBlock.subBlocks[0]).instr; - LocalInfo local = - ((LocalLoadOperator)monexit.getSubExpressions()[0]) - .getLocalInfo(); - - if ((GlobalOptions.debuggingFlags - & GlobalOptions.DEBUG_ANALYZE) != 0) - GlobalOptions.err.println - ("analyzeSynchronized(" + tryFlow.getAddr() - + "," + tryFlow.getNextAddr() + "," + catchFlow.getAddr() - + "," + catchFlow.getNextAddr() + "," + endHandler + ")"); - - checkAndRemoveMonitorExit - (tryFlow, local, - tryFlow.getNextAddr(), catchFlow.getAddr(), - catchFlow.getNextAddr(), endHandler); - - tryFlow.mergeAddr(catchFlow); - SynchronizedBlock syncBlock = new SynchronizedBlock(local); - TryBlock tryBlock = (TryBlock) tryFlow.block; - syncBlock.replace(tryBlock); - syncBlock.moveJump(tryBlock.jump); - syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1 - ? tryBlock.subBlocks[0] : tryBlock); - tryFlow.lastModified = syncBlock; - return true; - } - return false; + Expression throwInstr = + ((ThrowBlock)catchBlock.getSubBlocks()[1]).getInstruction(); + + if (excStore != null) { + if (!(throwInstr instanceof Operator + && excStore.lvalueMatches((Operator)throwInstr))) + return false; + } else { + if (!(throwInstr instanceof NopOperator)) + return false; + } + + /* This is a synchronized block: + * + * local_x = monitor object; // later + * monitorenter local_x // later + * tryFlow: + * |- synchronized block + * | ... + * | every jump to outside is preceded by jsr subroutine-, + * | ... | + * |- monitorexit local_x | + * ` jump after this block (without jsr monexit) | + * | + * catchBlock: | + * local_n = stack | + * monitorexit local_x | + * throw local_n | + * [OR ALTERNATIVELY:] | + * monitorexit local_x | + * throw stack | + * optional subroutine: <-----------------------------------' + * astore_n + * monitorexit local_x + * return_n + */ + + MonitorExitOperator monexit = (MonitorExitOperator) + ((InstructionBlock) catchBlock.getSubBlocks()[0]).instr; + LocalInfo local = + ((LocalLoadOperator)monexit.getSubExpressions()[0]) + .getLocalInfo(); + + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_ANALYZE) != 0) + GlobalOptions.err.println + ("analyzeSynchronized(" + tryFlow.getAddr() + + "," + tryFlow.getNextAddr() + "," + endHandler + ")"); + + checkAndRemoveMonitorExit + (tryFlow, catchBlock, local, tryFlow.getNextAddr(), endHandler); + + SynchronizedBlock syncBlock = new SynchronizedBlock(local); + TryBlock tryBlock = (TryBlock) tryFlow.block; + syncBlock.replace(tryBlock); + syncBlock.moveJump(tryBlock.jump); + syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1 + ? tryBlock.subBlocks[0] : tryBlock); + tryFlow.lastModified = syncBlock; + return true; } - private boolean analyzeFinally(FlowBlock tryFlow, FlowBlock catchFlow, - int end) { - - /* Layout of a try-finally block: - * - * tryFlow: - * |- first instruction - * | ... - * | every jump to outside is preceded by jsr finally - * | ... - * | jsr finally -----------------, - * `- jump after finally | - * | - * catchFlow: (already checked) | - * local_n = stack v - * jsr finally ---------------->| - * throw local_n; | - * finally: <-----------------------' - * astore_n - * ... - * return_n - */ - - if (!(catchFlow.block instanceof SequentialBlock) - || !(catchFlow.block.getSubBlocks()[0] - instanceof InstructionBlock) - || !(catchFlow.block.getSubBlocks()[1] - instanceof SequentialBlock)) + private boolean analyzeFinally(FlowBlock tryFlow, + StructuredBlock catchBlock, int end) { + + /* Layout of a try-finally block: + * + * tryFlow: + * |- first instruction + * | ... + * | every jump to outside is preceded by jsr finally + * | ... + * | jsr finally -----------------, + * `- jump after finally | + * | + * catchBlock: | + * local_n = stack v + * jsr finally ---------------->| + * throw local_n; | + * finally: <-----------------------' + * astore_n + * ... + * return_n + */ + + StoreInstruction excStore = getExceptionStore(catchBlock); + if (excStore == null) + return false; + + catchBlock = catchBlock.getSubBlocks()[1]; + if (!(catchBlock instanceof SequentialBlock)) return false; StructuredBlock finallyBlock = null; - SequentialBlock catchBlock = (SequentialBlock) catchFlow.block; - Expression instr = - ((InstructionBlock)catchBlock.subBlocks[0]).getInstruction(); - catchBlock = (SequentialBlock)catchBlock.subBlocks[1]; - if (catchBlock.subBlocks[0] instanceof LoopBlock) { + if (catchBlock.getSubBlocks()[0] instanceof LoopBlock) { /* In case the try block has no exit (that means, it throws * an exception), the finallyBlock was already merged with * the catchBlock. We have to check for this case separately: @@ -641,20 +696,21 @@ public class TransformExceptionHandlers { * break; * throw local_x * } while(false); - * finallyBlock; + * finallyBlock; (starts with POP or local_y = POP) */ - LoopBlock doWhileFalse = (LoopBlock)catchBlock.subBlocks[0]; + LoopBlock doWhileFalse = (LoopBlock)catchBlock.getSubBlocks()[0]; if (doWhileFalse.type == LoopBlock.DOWHILE && doWhileFalse.cond == LoopBlock.FALSE && doWhileFalse.bodyBlock instanceof SequentialBlock) { - finallyBlock = catchBlock.subBlocks[1]; - catchBlock = (SequentialBlock) doWhileFalse.bodyBlock; + if (transformSubRoutine(catchBlock.getSubBlocks()[1])) { + finallyBlock = catchBlock.getSubBlocks()[1]; + catchBlock = (SequentialBlock) doWhileFalse.bodyBlock; + } } } if (!(catchBlock instanceof SequentialBlock && catchBlock.getSubBlocks()[0] instanceof JsrBlock - && instr instanceof StoreInstruction && catchBlock.getSubBlocks()[1] instanceof ThrowBlock)) return false; @@ -663,21 +719,12 @@ public class TransformExceptionHandlers { ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1]; - if (!(throwBlock.instr instanceof LocalLoadOperator) - || !(((StoreInstruction) instr).lvalueMatches - ((LocalLoadOperator) throwBlock.instr))) + if (!(throwBlock.getInstruction() instanceof Operator + && excStore.lvalueMatches((Operator) + throwBlock.getInstruction()))) return false; - /* Wow that was complicated :-) - * But now we know that the catch block looks - * exactly like it should: - * - * catchBlock: - * JSR - * finally - * throw local_n <- matches the local in instr. - */ - + FlowBlock subRoutine; if (finallyBlock != null) { /* Check if the jsr breaks (see two comments above). We don't * need to check if it breaks to the right block, because @@ -687,77 +734,35 @@ public class TransformExceptionHandlers { return false; /* Check if the try block has no exit (except throws) + * XXX - Unfortunately the try block already has the + * successors of catch block. */ - Set succs = tryFlow.getSuccessors(); - if (succs.size() > 0) { - if (!succs.contains(FlowBlock.END_OF_METHOD)) - return false; - Jump throwJumps - = tryFlow.getJumps(FlowBlock.END_OF_METHOD); - for (/**/; throwJumps != null; - throwJumps = throwJumps.next) { - if (!(throwJumps.prev instanceof ThrowBlock)) - /* There is a return exit in the try block */ - return false; - } - } - /* Remove the jump of the throw instruction. - */ - catchFlow.removeSuccessor(throwBlock.jump); - throwBlock.removeJump(); - - /* Replace the catchBlock with the finallyBlock. - */ - finallyBlock.replace(catchFlow.block); - transformSubRoutine(finallyBlock); - - tryFlow.updateInOutCatch(catchFlow); - tryFlow.mergeAddr(catchFlow); - finallyBlock = catchFlow.block; - tryFlow.mergeSuccessors(catchFlow); +// if (tryFlow.getSuccessors() > 0) +// return false; + catchBlock = finallyBlock; + subRoutine = null; } else { - FlowBlock subRoutine = jsrBlock.innerBlock.jump.destination; - checkAndRemoveJSR(tryFlow, subRoutine, - tryFlow.getNextAddr(), catchFlow.getAddr()); - - while (subRoutine.analyze(catchFlow.getNextAddr(), end)); + if (!(jsrBlock.innerBlock instanceof EmptyBlock)) + return false; + catchBlock = jsrBlock; + subRoutine = jsrBlock.innerBlock.jump.destination; + checkAndRemoveJSR(tryFlow, catchBlock, subRoutine, + tryFlow.getNextAddr(), subRoutine.getAddr()); + } - /* Now check if the subroutine is correct and has only the - * catchFlow as predecessor. - */ - if (subRoutine.predecessors.size() == 1 - && transformSubRoutine(subRoutine.block)) { - subRoutine.mergeAddr(catchFlow); + /* Wow that was complicated :-) + * But now we know that the catch block looks + * exactly like it should: + * + * local_n = POP + * catchBlock: + * JSR + * finally + * throw local_n + */ - /* Now remove the jump to the JSR from the catch block - * and the jump of the throw instruction. - */ - catchFlow.removeSuccessor(jsrBlock.innerBlock.jump); - jsrBlock.innerBlock.removeJump(); - catchFlow.removeSuccessor(throwBlock.jump); - throwBlock.removeJump(); - - tryFlow.updateInOutCatch(subRoutine); - tryFlow.mergeAddr(subRoutine); - tryFlow.mergeSuccessors(subRoutine); - finallyBlock = subRoutine.block; - } else { - catchFlow.removeSuccessor(throwBlock.jump); - throwBlock.removeJump(); - finallyBlock = jsrBlock; - - finallyBlock.replace(catchFlow.block); - transformSubRoutine(finallyBlock); - - tryFlow.updateInOutCatch(catchFlow); - tryFlow.mergeAddr(catchFlow); - finallyBlock = catchFlow.block; - tryFlow.mergeSuccessors(catchFlow); - } - } - - TryBlock tryBlock = (TryBlock)tryFlow.block; + TryBlock tryBlock = (TryBlock) tryFlow.block; if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { /* remove the surrounding tryBlock */ TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; @@ -768,88 +773,83 @@ public class TransformExceptionHandlers { tryFlow.block = tryBlock; } FinallyBlock newBlock = new FinallyBlock(); - newBlock.setCatchBlock(finallyBlock); + newBlock.setCatchBlock(catchBlock); tryBlock.addCatchBlock(newBlock); + + if (subRoutine != null) { + while (subRoutine.analyze(tryFlow.getNextAddr(), end)); + + /* Now check if the subroutine is correct and has only the + * catchFlow as predecessor. + */ + if (subRoutine.predecessors.size() == 1 + && transformSubRoutine(subRoutine.block)) { + + tryFlow.removeSuccessor(jsrBlock.innerBlock.jump); + tryFlow.mergeAddr(subRoutine); + tryFlow.mergeSuccessors(subRoutine); + subRoutine.block.replace(catchBlock); + tryFlow.updateInOutCatch(subRoutine); + } + } return true; } private boolean analyzeSpecialFinally(FlowBlock tryFlow, - FlowBlock catchFlow, int end) { - + StructuredBlock catchBlock, + int end) { StructuredBlock firstInstr = - catchFlow.block instanceof SequentialBlock - ? catchFlow.block.getSubBlocks()[0]: catchFlow.block; - - if (firstInstr instanceof SpecialBlock - && ((SpecialBlock)firstInstr).type == SpecialBlock.POP - && ((SpecialBlock)firstInstr).count == 1) { - - /* This is a special try/finally-block, where - * the finally block ends with a break, return or - * similar. - */ + catchBlock instanceof SequentialBlock + ? catchBlock.getSubBlocks()[0]: catchBlock; - FlowBlock succ = (firstInstr.jump != null) ? - firstInstr.jump.destination : null; - boolean hasExit = false; - Iterator iter = tryFlow.getSuccessors().iterator(); - while (iter.hasNext()) { - FlowBlock dest = (FlowBlock) iter.next(); - if (dest == succ) - continue; - if (dest != FlowBlock.END_OF_METHOD) { - /* There is another exit in the try block, bad */ - return false; - } - for (Jump throwJumps = (Jump) tryFlow.getJumps(dest); - throwJumps != null; throwJumps = throwJumps.next) { - if (!(throwJumps.prev instanceof ThrowBlock)) { - /* There is a return exit in the try block */ - return false; - } - } - } + if (!(firstInstr instanceof SpecialBlock + && ((SpecialBlock)firstInstr).type == SpecialBlock.POP + && ((SpecialBlock)firstInstr).count == 1)) + return false; - /* remove the pop now */ - firstInstr.removeBlock(); - tryFlow.mergeAddr(catchFlow); + /* This may be a special try/finally-block, where + * the finally block ends with a break, return or + * similar. + */ + FlowBlock succ = null; - if (succ != null) { - Jump jumps = tryFlow.removeJumps(succ); - /* Handle the jumps in the tryFlow. - */ - jumps = tryFlow.resolveSomeJumps(jumps, succ); - tryFlow.resolveRemaining(jumps); - } + /* remove the pop now */ + if (catchBlock instanceof SequentialBlock) + catchBlock = catchBlock.getSubBlocks()[1]; + else { + catchBlock = new EmptyBlock(); + catchBlock.moveJump(firstInstr.jump); - TryBlock tryBlock = (TryBlock)tryFlow.block; - if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { - /* remove the unnecessary tryBlock */ - TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; - innerTry.gen = tryBlock.gen; - innerTry.replace(tryBlock); - tryBlock = innerTry; - tryFlow.lastModified = innerTry; - } - FinallyBlock newBlock = new FinallyBlock(); - tryBlock.addCatchBlock(newBlock); - /* try block has no successors */ - - if (succ != null && succ.predecessors.size() == 1) { - while (succ.analyze(catchFlow.getNextAddr(), end)); - tryFlow.mergeAddr(succ); - tryFlow.removeJumps(succ); - newBlock.setCatchBlock(succ.block); - tryFlow.mergeSuccessors(succ); - } else { - /* Put the catchBlock in instead. - */ - newBlock.setCatchBlock(catchFlow.block); - tryFlow.mergeSuccessors(catchFlow); - } - return true; - } - return false; + succ = firstInstr.jump.destination; + } + +// Set trySuccs = tryFlow.getSuccessors(); +// if (trySuccs.size() > 1 +// || (trySuccs.size() == 1 +// && trySuccs.iterator().next() != succ)) +// return false; + + if (succ != null) { + Jump jumps = tryFlow.removeJumps(succ); + /* Handle the jumps in the tryFlow. + */ + jumps = tryFlow.resolveSomeJumps(jumps, succ); + tryFlow.resolveRemaining(jumps); + } + + TryBlock tryBlock = (TryBlock)tryFlow.block; + if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { + /* remove the unnecessary tryBlock */ + TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; + innerTry.gen = tryBlock.gen; + innerTry.replace(tryBlock); + tryBlock = innerTry; + tryFlow.lastModified = innerTry; + } + FinallyBlock newBlock = new FinallyBlock(); + tryBlock.addCatchBlock(newBlock); + newBlock.setCatchBlock(catchBlock); + return true; } /** @@ -958,17 +958,22 @@ public class TransformExceptionHandlers { + catchFlow.getAddr() + ", " + endHandler + ")"); while (catchFlow.analyze(catchFlow.getAddr(), endHandler)); } - + + /* Merge the try-block with the catch-block now */ tryFlow.updateInOutCatch(catchFlow); + tryFlow.mergeSuccessors(catchFlow); + tryFlow.mergeAddr(catchFlow); if (exc.type != null) - analyzeCatchBlock(exc.type, tryFlow, catchFlow); + analyzeCatchBlock(exc.type, tryFlow, catchFlow.block); - else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler) - && ! analyzeFinally(tryFlow, catchFlow, endHandler) - && ! analyzeSpecialFinally(tryFlow, catchFlow, + else if (!analyzeSynchronized(tryFlow, catchFlow.block, + endHandler) + && ! analyzeFinally(tryFlow, catchFlow.block, + endHandler) + && ! analyzeSpecialFinally(tryFlow, catchFlow.block, endHandler)) - analyzeCatchBlock(Type.tObject, tryFlow, catchFlow); + analyzeCatchBlock(Type.tObject, tryFlow, catchFlow.block); tryFlow.checkConsistent(); if ((GlobalOptions.debuggingFlags diff --git a/jode/jode/jvm/CodeVerifier.java.in b/jode/jode/jvm/CodeVerifier.java.in index 556902f..edc50d7 100644 --- a/jode/jode/jvm/CodeVerifier.java.in +++ b/jode/jode/jvm/CodeVerifier.java.in @@ -207,19 +207,17 @@ public class CodeVerifier implements Opcodes { dimensions++; } - if (c1 == '[' || c2 == '[') { - // Only one of them is array now, the other must be an - // object, the common super is tObject - if (c1 == 'L' || c2 == 'L') { - if (dimensions == 0) - return tObject; - StringBuffer result = new StringBuffer(dimensions + 18); - for (int i=0; i< dimensions; i++) - result.append("["); - result.append("Ljava/lang/Object;"); - return tType(result.toString()); - } - return tNone; + // One of them is array now, the other is an object, + // the common super is tObject + if ((c1 == '[' && c2 == 'L') + || (c1 == 'L' && c2 == '[')) { + if (dimensions == 0) + return tObject; + StringBuffer result = new StringBuffer(dimensions + 18); + for (int i=0; i< dimensions; i++) + result.append("["); + result.append("Ljava/lang/Object;"); + return tType(result.toString()); } if (c1 == 'L' && c2 == 'L') { @@ -240,6 +238,18 @@ public class CodeVerifier implements Opcodes { .append(clazz1.getName().replace('.', '/')).append(";"); return tType(result.toString()); } + + // Both were arrays, but of different primitive types. The + // common super is tObject with one dimension less. + if (dimensions > 0) { + if (dimensions == 1) + return tObject; + StringBuffer result = new StringBuffer(dimensions + 18); + for (int i=0; i< dimensions; i++) + result.append("["); + result.append("Ljava/lang/Object;"); + return tType(result.toString()); + } return tNone; } diff --git a/jode/jode/type/ArrayType.java b/jode/jode/type/ArrayType.java index 7efd78e..ddb57f5 100644 --- a/jode/jode/type/ArrayType.java +++ b/jode/jode/type/ArrayType.java @@ -104,8 +104,9 @@ public class ArrayType extends ReferenceType { if (type == tNull) return this; if (type.getTypeCode() == TC_ARRAY) { - return tArray(elementType.intersection - (((ArrayType)type).elementType)); + Type elType = elementType.intersection + (((ArrayType)type).elementType); + return elType != tError ? tArray(elType) : tError; } if (type.getTypeCode() == TC_CLASS) { ClassInterfacesType other = (ClassInterfacesType) type; @@ -124,7 +125,7 @@ public class ArrayType extends ReferenceType { public Type getGeneralizedType(Type type) { /* tArray(x), tNull -> tArray(x) * tArray(x), tClass(y) -> common ifaces of tArray and tClass - * tArray(x), tArray(y) -> tArray(x.intersection(y)) + * tArray(x), tArray(y) -> tArray(x.intersection(y)) or tObject * tArray(x), other -> tError */ if (type.getTypeCode() == TC_RANGE) { @@ -132,9 +133,11 @@ public class ArrayType extends ReferenceType { } if (type == tNull) return this; - if (type.getTypeCode() == TC_ARRAY) - return tArray(elementType.intersection - (((ArrayType)type).elementType)); + if (type.getTypeCode() == TC_ARRAY) { + Type elType = elementType.intersection + (((ArrayType)type).elementType); + return elType != tError ? tArray(elType) : tObject; + } if (type.getTypeCode() == TC_CLASS) { ClassInterfacesType other = (ClassInterfacesType) type; if (implementsAllIfaces(other.clazz, other.ifaces, arrayIfaces))