CodeVerifier, ArrayType: merge array types whose elemTypes are incompatible

to tObject.
TransformExceptionHandlers: javac-1.3 synchronized block preliminary support.
Expresion: Show runtime exceptions.


git-svn-id: https://svn.code.sf.net/p/jode/code/branches/branch_1_1@1294 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
hoenicke 24 years ago
parent d0a70c3626
commit 344faa9265
  1. 12
      jode/ChangeLog
  2. 3
      jode/jode/expr/Expression.java.in
  3. 3
      jode/jode/flow/FlowBlock.java.in
  4. 677
      jode/jode/flow/TransformExceptionHandlers.java.in
  5. 36
      jode/jode/jvm/CodeVerifier.java.in
  6. 15
      jode/jode/type/ArrayType.java

@ -1,3 +1,15 @@
2001-02-01 Jochen Hoenicke <jochen@gnu.org>
* 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 <jochen@gnu.org> 2001-01-31 Jochen Hoenicke <jochen@gnu.org>
* jode/expr/Expression.java.in (updateParentTypes): Call setType, * jode/expr/Expression.java.in (updateParentTypes): Call setType,

@ -53,7 +53,7 @@ public abstract class Expression {
} }
public void updateParentType(Type otherType) { public void updateParentType(Type otherType) {
setType(newType); setType(otherType);
if (parent != null) if (parent != null)
parent.updateType(); parent.updateType();
} }
@ -283,6 +283,7 @@ public abstract class Expression {
dumpExpression(writer); dumpExpression(writer);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
writer.print("(RUNTIME ERROR IN EXPRESSION)"); writer.print("(RUNTIME ERROR IN EXPRESSION)");
ex.printStackTrace(GlobalOptions.err);
} }
if (needEndOp2) { if (needEndOp2) {

@ -1708,7 +1708,8 @@ public class FlowBlock {
java.io.StringWriter strw = new java.io.StringWriter(); java.io.StringWriter strw = new java.io.StringWriter();
TabbedPrintWriter writer = new TabbedPrintWriter(strw); TabbedPrintWriter writer = new TabbedPrintWriter(strw);
writer.println(super.toString() + ": "+addr+"-"+(addr+length)); 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.println("in: "+in);
} }
writer.tab(); writer.tab();

@ -109,16 +109,12 @@ public class TransformExceptionHandlers {
* | ... * | ...
* `- catch block * `- catch block
*/ */
static void analyzeCatchBlock(Type type, static void analyzeCatchBlock(Type type, FlowBlock tryFlow,
FlowBlock tryFlow, FlowBlock catchFlow) { StructuredBlock catchBlock) {
StructuredBlock catchBlock = catchFlow.block;
CatchBlock newBlock = new CatchBlock(type); CatchBlock newBlock = new CatchBlock(type);
((TryBlock)tryFlow.block).addCatchBlock(newBlock); ((TryBlock)tryFlow.block).addCatchBlock(newBlock);
newBlock.setCatchBlock(catchFlow.block); newBlock.setCatchBlock(catchBlock);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeAddr(catchFlow);
} }
/* And now the complicated parts. */ /* And now the complicated parts. */
@ -128,42 +124,82 @@ public class TransformExceptionHandlers {
* local assignment matches the final ret and then returns. * local assignment matches the final ret and then returns.
*/ */
boolean transformSubRoutine(StructuredBlock subRoutine) { boolean transformSubRoutine(StructuredBlock subRoutine) {
if (!(subRoutine instanceof SequentialBlock) if (!(subRoutine instanceof SequentialBlock))
|| !(subRoutine.getSubBlocks()[0] instanceof InstructionBlock)) return false;
return false;
SequentialBlock sequBlock = (SequentialBlock) subRoutine; SequentialBlock sequBlock = (SequentialBlock) subRoutine;
InstructionBlock instr = (InstructionBlock)sequBlock.subBlocks[0]; 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;
if (!(instr.getInstruction() instanceof StoreInstruction) /* We have now committed. Remove the first Statement which
|| !(((StoreInstruction) instr.getInstruction()).getLValue() * stores/removes the return address.
instanceof LocalStoreOperator)) */
return false; firstBlock.removeBlock();
LocalStoreOperator store = (LocalStoreOperator)
((StoreInstruction)instr.getInstruction()).getLValue();
/* 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. 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.
*/
while (sequBlock.subBlocks[1] instanceof SequentialBlock) while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
/* XXX - Check that the local isn't used for any other purposes if (sequBlock.subBlocks[1] instanceof RetBlock
* than RET and replace any RET with a flow control to end of && (((RetBlock) sequBlock.subBlocks[1]).local.equals(local))) {
* flow block. sequBlock.subBlocks[1].removeBlock();
*
* This is a complicated task which isn't needed for javac nor jikes.
*/
if (sequBlock.subBlocks[1].jump != null
&& sequBlock.subBlocks[1].jump.destination
== FlowBlock.END_OF_METHOD) {
instr.removeBlock();
return true;
} }
if (! (sequBlock.subBlocks[1] instanceof RetBlock) return true;
|| !(((RetBlock)sequBlock.subBlocks[1]) }
.local.equals(store.getLocalInfo())))
return false; /**
* Remove the locale that javac introduces to temporary store the return
instr.removeBlock(); * value, when it executes a finally block resp. monitorexit
sequBlock.subBlocks[1].removeBlock(); * @param ret the ReturnBlock.
return true; */
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 tryFlow the FlowBLock of the try block.
* @param subRoutine the FlowBlock of the sub routine. * @param subRoutine the FlowBlock of the sub routine.
*/ */
private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) { private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock,
for (Jump jumps = tryFlow.removeJumps(subRoutine); FlowBlock subRoutine) {
jumps != null; jumps = jumps.next) { Jump nextJump;
for (Jump jumps = tryFlow.getJumps(subRoutine);
jumps != null; jumps = nextJump) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
prev.removeJump(); nextJump = jumps.next;
if (prev instanceof EmptyBlock if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) { && prev.outer instanceof JsrBlock) {
if (prev.outer == catchBlock) {
/* This is the mandatory jsr in the catch block */
continue;
}
if (prev.outer.getNextFlowBlock() != null) { if (prev.outer.getNextFlowBlock() != null) {
/* The jsr is directly before a jump, okay. */ /* The jsr is directly before a jump, okay. */
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.outer.removeBlock(); prev.outer.removeBlock();
continue; continue;
} }
@ -196,6 +240,8 @@ public class TransformExceptionHandlers {
&& seq.subBlocks[1].getSubBlocks()[0] && seq.subBlocks[1].getSubBlocks()[0]
instanceof JsrBlock)) { instanceof JsrBlock)) {
/* The jsr is followed by a jsr, okay. */ /* The jsr is followed by a jsr, okay. */
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.outer.removeBlock(); prev.outer.removeBlock();
continue; continue;
} }
@ -203,33 +249,12 @@ public class TransformExceptionHandlers {
&& !(seq.subBlocks[1] instanceof ThrowBlock)) { && !(seq.subBlocks[1] instanceof ThrowBlock)) {
/* The jsr is followed by a return, okay. */ /* The jsr is followed by a return, okay. */
tryFlow.removeSuccessor(jumps);
prev.removeJump();
ReturnBlock ret = (ReturnBlock) seq.subBlocks[1]; ReturnBlock ret = (ReturnBlock) seq.subBlocks[1];
prev.outer.removeBlock(); prev.outer.removeBlock();
if (ret.outer != null removeReturnLocal(ret);
&& 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 */
}
}
continue; continue;
} }
} }
@ -239,11 +264,15 @@ public class TransformExceptionHandlers {
*/ */
DescriptionBlock msg DescriptionBlock msg
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!"); = new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.appendBlock(msg); prev.appendBlock(msg);
} }
} }
public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine, public void checkAndRemoveJSR(FlowBlock tryFlow,
StructuredBlock catchBlock,
FlowBlock subRoutine,
int startOutExit, int endOutExit) { int startOutExit, int endOutExit) {
boolean foundSub = false; boolean foundSub = false;
Iterator iter = tryFlow.getSuccessors().iterator(); Iterator iter = tryFlow.getSuccessors().iterator();
@ -336,7 +365,7 @@ public class TransformExceptionHandlers {
} }
} }
if (foundSub) if (foundSub)
removeJSR(tryFlow, subRoutine); removeJSR(tryFlow, catchBlock, subRoutine);
} }
static boolean isMonitorExit(Expression instr, LocalInfo local) { static boolean isMonitorExit(Expression instr, LocalInfo local) {
@ -366,9 +395,10 @@ public class TransformExceptionHandlers {
return false; return false;
} }
public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local, public void checkAndRemoveMonitorExit(FlowBlock tryFlow,
int startOutExit, int endOutExit, StructuredBlock catchBlock,
int startMonExit, int endMonExit) { LocalInfo local,
int start, int end) {
FlowBlock subRoutine = null; FlowBlock subRoutine = null;
Iterator succs = tryFlow.getSuccessors().iterator(); Iterator succs = tryFlow.getSuccessors().iterator();
dest_loop: dest_loop:
@ -421,8 +451,12 @@ public class TransformExceptionHandlers {
if (pred instanceof InstructionBlock) { if (pred instanceof InstructionBlock) {
Expression instr = Expression instr =
((InstructionBlock)pred).getInstruction(); ((InstructionBlock)pred).getInstruction();
if (isMonitorExit(instr, local)) if (isMonitorExit(instr, local)) {
pred.removeBlock();
if (prev instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) prev);
continue; continue;
}
} }
} }
} }
@ -448,9 +482,9 @@ public class TransformExceptionHandlers {
*/ */
if (prev instanceof JsrBlock) { if (prev instanceof JsrBlock) {
if (subRoutine == null if (subRoutine == null
&& successor.getAddr() >= startMonExit && successor.getAddr() >= start
&& successor.getNextAddr() <= endMonExit) { && successor.getNextAddr() <= end) {
successor.analyze(startMonExit, endMonExit); successor.analyze(start, end);
if (isMonitorExitSubRoutine(successor, local)) if (isMonitorExitSubRoutine(successor, local))
subRoutine = successor; subRoutine = successor;
@ -467,9 +501,9 @@ public class TransformExceptionHandlers {
* block. * block.
*/ */
if (successor.predecessors.size() == 1 if (successor.predecessors.size() == 1
&& successor.getAddr() >= startOutExit && successor.getAddr() >= start
&& successor.getNextAddr() <= endOutExit) { && successor.getNextAddr() <= end) {
successor.analyze(startOutExit, endOutExit); successor.analyze(start, end);
StructuredBlock sb = successor.block; StructuredBlock sb = successor.block;
if (sb instanceof SequentialBlock) if (sb instanceof SequentialBlock)
@ -479,9 +513,9 @@ public class TransformExceptionHandlers {
StructuredBlock jsrInner = sb.getSubBlocks()[0]; StructuredBlock jsrInner = sb.getSubBlocks()[0];
FlowBlock dest = jsrInner.jump.destination; FlowBlock dest = jsrInner.jump.destination;
if (subRoutine == null if (subRoutine == null
&& dest.getAddr() >= startMonExit && dest.getAddr() >= start
&& dest.getNextAddr() <= endMonExit) { && dest.getNextAddr() <= end) {
dest.analyze(startMonExit, endMonExit); dest.analyze(start, end);
if (isMonitorExitSubRoutine(dest, local)) if (isMonitorExitSubRoutine(dest, local))
subRoutine = dest; subRoutine = dest;
} }
@ -512,126 +546,147 @@ public class TransformExceptionHandlers {
} }
if (subRoutine != null) { if (subRoutine != null) {
removeJSR(tryFlow, subRoutine); removeJSR(tryFlow, catchBlock, subRoutine);
tryFlow.mergeAddr(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, private boolean analyzeSynchronized(FlowBlock tryFlow,
FlowBlock catchFlow, StructuredBlock catchBlock,
int endHandler) { int endHandler) {
if (!(catchFlow.block instanceof SequentialBlock StoreInstruction excStore = getExceptionStore(catchBlock);
&& catchFlow.block.getSubBlocks()[0] if (excStore != null)
catchBlock = catchBlock.getSubBlocks()[1];
if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0]
instanceof InstructionBlock)) instanceof InstructionBlock))
return false; return false;
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block;
Expression instr = Expression instr =
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction(); ((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction();
if (instr instanceof MonitorExitOperator if (!(instr instanceof MonitorExitOperator
&& instr.getFreeOperandCount() == 0 && instr.getFreeOperandCount() == 0
&& (((MonitorExitOperator)instr).getSubExpressions()[0] && (((MonitorExitOperator)instr).getSubExpressions()[0]
instanceof LocalLoadOperator) instanceof LocalLoadOperator)
&& catchBlock.subBlocks[1] instanceof ThrowBlock && catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
&& (((ThrowBlock)catchBlock.subBlocks[1]).instr return false;
instanceof NopOperator)) {
/* This is a synchronized block: Expression throwInstr =
* ((ThrowBlock)catchBlock.getSubBlocks()[1]).getInstruction();
* 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
*/
/* Now remove the jump (after the throw) from the if (excStore != null) {
* catch block so that we can forget about it. if (!(throwInstr instanceof Operator
*/ && excStore.lvalueMatches((Operator)throwInstr)))
return false;
} else {
if (!(throwInstr instanceof NopOperator))
return false;
}
catchFlow.removeSuccessor(catchBlock.subBlocks[1].jump); /* This is a synchronized block:
MonitorExitOperator monexit = (MonitorExitOperator) *
((InstructionBlock) catchBlock.subBlocks[0]).instr; * local_x = monitor object; // later
LocalInfo local = * monitorenter local_x // later
((LocalLoadOperator)monexit.getSubExpressions()[0]) * tryFlow:
.getLocalInfo(); * |- synchronized block
* | ...
if ((GlobalOptions.debuggingFlags * | every jump to outside is preceded by jsr subroutine-,
& GlobalOptions.DEBUG_ANALYZE) != 0) * | ... |
GlobalOptions.err.println * |- monitorexit local_x |
("analyzeSynchronized(" + tryFlow.getAddr() * ` jump after this block (without jsr monexit) |
+ "," + tryFlow.getNextAddr() + "," + catchFlow.getAddr() * |
+ "," + catchFlow.getNextAddr() + "," + endHandler + ")"); * catchBlock: |
* local_n = stack |
checkAndRemoveMonitorExit * monitorexit local_x |
(tryFlow, local, * throw local_n |
tryFlow.getNextAddr(), catchFlow.getAddr(), * [OR ALTERNATIVELY:] |
catchFlow.getNextAddr(), endHandler); * monitorexit local_x |
* throw stack |
tryFlow.mergeAddr(catchFlow); * optional subroutine: <-----------------------------------'
SynchronizedBlock syncBlock = new SynchronizedBlock(local); * astore_n
TryBlock tryBlock = (TryBlock) tryFlow.block; * monitorexit local_x
syncBlock.replace(tryBlock); * return_n
syncBlock.moveJump(tryBlock.jump); */
syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1
? tryBlock.subBlocks[0] : tryBlock); MonitorExitOperator monexit = (MonitorExitOperator)
tryFlow.lastModified = syncBlock; ((InstructionBlock) catchBlock.getSubBlocks()[0]).instr;
return true; LocalInfo local =
} ((LocalLoadOperator)monexit.getSubExpressions()[0])
return false; .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, private boolean analyzeFinally(FlowBlock tryFlow,
int end) { StructuredBlock catchBlock, int end) {
/* Layout of a try-finally block: /* Layout of a try-finally block:
* *
* tryFlow: * tryFlow:
* |- first instruction * |- first instruction
* | ... * | ...
* | every jump to outside is preceded by jsr finally * | every jump to outside is preceded by jsr finally
* | ... * | ...
* | jsr finally -----------------, * | jsr finally -----------------,
* `- jump after finally | * `- jump after finally |
* | * |
* catchFlow: (already checked) | * catchBlock: |
* local_n = stack v * local_n = stack v
* jsr finally ---------------->| * jsr finally ---------------->|
* throw local_n; | * throw local_n; |
* finally: <-----------------------' * finally: <-----------------------'
* astore_n * astore_n
* ... * ...
* return_n * return_n
*/ */
if (!(catchFlow.block instanceof SequentialBlock) StoreInstruction excStore = getExceptionStore(catchBlock);
|| !(catchFlow.block.getSubBlocks()[0] if (excStore == null)
instanceof InstructionBlock) return false;
|| !(catchFlow.block.getSubBlocks()[1]
instanceof SequentialBlock)) catchBlock = catchBlock.getSubBlocks()[1];
if (!(catchBlock instanceof SequentialBlock))
return false; return false;
StructuredBlock finallyBlock = null; 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 /* In case the try block has no exit (that means, it throws
* an exception), the finallyBlock was already merged with * an exception), the finallyBlock was already merged with
* the catchBlock. We have to check for this case separately: * the catchBlock. We have to check for this case separately:
@ -641,20 +696,21 @@ public class TransformExceptionHandlers {
* break; * break;
* throw local_x * throw local_x
* } while(false); * } 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 if (doWhileFalse.type == LoopBlock.DOWHILE
&& doWhileFalse.cond == LoopBlock.FALSE && doWhileFalse.cond == LoopBlock.FALSE
&& doWhileFalse.bodyBlock instanceof SequentialBlock) { && doWhileFalse.bodyBlock instanceof SequentialBlock) {
finallyBlock = catchBlock.subBlocks[1]; if (transformSubRoutine(catchBlock.getSubBlocks()[1])) {
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock; finallyBlock = catchBlock.getSubBlocks()[1];
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock;
}
} }
} }
if (!(catchBlock instanceof SequentialBlock if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock && catchBlock.getSubBlocks()[0] instanceof JsrBlock
&& instr instanceof StoreInstruction
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock)) && catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
return false; return false;
@ -663,21 +719,12 @@ public class TransformExceptionHandlers {
ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1]; ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1];
if (!(throwBlock.instr instanceof LocalLoadOperator) if (!(throwBlock.getInstruction() instanceof Operator
|| !(((StoreInstruction) instr).lvalueMatches && excStore.lvalueMatches((Operator)
((LocalLoadOperator) throwBlock.instr))) throwBlock.getInstruction())))
return false; return false;
/* Wow that was complicated :-) FlowBlock subRoutine;
* But now we know that the catch block looks
* exactly like it should:
*
* catchBlock:
* JSR
* finally
* throw local_n <- matches the local in instr.
*/
if (finallyBlock != null) { if (finallyBlock != null) {
/* Check if the jsr breaks (see two comments above). We don't /* Check if the jsr breaks (see two comments above). We don't
* need to check if it breaks to the right block, because * need to check if it breaks to the right block, because
@ -687,171 +734,124 @@ public class TransformExceptionHandlers {
return false; return false;
/* Check if the try block has no exit (except throws) /* 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 (tryFlow.getSuccessors() > 0)
if (succs.size() > 0) { // return false;
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. catchBlock = finallyBlock;
*/ subRoutine = null;
finallyBlock.replace(catchFlow.block); } else {
transformSubRoutine(finallyBlock); if (!(jsrBlock.innerBlock instanceof EmptyBlock))
return false;
catchBlock = jsrBlock;
subRoutine = jsrBlock.innerBlock.jump.destination;
checkAndRemoveJSR(tryFlow, catchBlock, subRoutine,
tryFlow.getNextAddr(), subRoutine.getAddr());
}
tryFlow.updateInOutCatch(catchFlow); /* Wow that was complicated :-)
tryFlow.mergeAddr(catchFlow); * But now we know that the catch block looks
finallyBlock = catchFlow.block; * exactly like it should:
tryFlow.mergeSuccessors(catchFlow); *
* local_n = POP
* catchBlock:
* JSR
* finally
* throw local_n
*/
} else { TryBlock tryBlock = (TryBlock) tryFlow.block;
FlowBlock subRoutine = jsrBlock.innerBlock.jump.destination; if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
checkAndRemoveJSR(tryFlow, subRoutine, /* remove the surrounding tryBlock */
tryFlow.getNextAddr(), catchFlow.getAddr()); TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock;
tryFlow.block = tryBlock;
}
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(catchBlock);
tryBlock.addCatchBlock(newBlock);
while (subRoutine.analyze(catchFlow.getNextAddr(), end)); if (subRoutine != null) {
while (subRoutine.analyze(tryFlow.getNextAddr(), end));
/* Now check if the subroutine is correct and has only the /* Now check if the subroutine is correct and has only the
* catchFlow as predecessor. * catchFlow as predecessor.
*/ */
if (subRoutine.predecessors.size() == 1 if (subRoutine.predecessors.size() == 1
&& transformSubRoutine(subRoutine.block)) { && transformSubRoutine(subRoutine.block)) {
subRoutine.mergeAddr(catchFlow);
/* 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.removeSuccessor(jsrBlock.innerBlock.jump);
tryFlow.mergeAddr(subRoutine); tryFlow.mergeAddr(subRoutine);
tryFlow.mergeSuccessors(subRoutine); tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block; subRoutine.block.replace(catchBlock);
} else { tryFlow.updateInOutCatch(subRoutine);
catchFlow.removeSuccessor(throwBlock.jump); }
throwBlock.removeJump(); }
finallyBlock = jsrBlock; return true;
}
finallyBlock.replace(catchFlow.block); private boolean analyzeSpecialFinally(FlowBlock tryFlow,
transformSubRoutine(finallyBlock); StructuredBlock catchBlock,
int end) {
StructuredBlock firstInstr =
catchBlock instanceof SequentialBlock
? catchBlock.getSubBlocks()[0]: catchBlock;
tryFlow.updateInOutCatch(catchFlow); if (!(firstInstr instanceof SpecialBlock
tryFlow.mergeAddr(catchFlow); && ((SpecialBlock)firstInstr).type == SpecialBlock.POP
finallyBlock = catchFlow.block; && ((SpecialBlock)firstInstr).count == 1))
tryFlow.mergeSuccessors(catchFlow); return false;
}
/* This may be a special try/finally-block, where
* the finally block ends with a break, return or
* similar.
*/
FlowBlock succ = null;
/* remove the pop now */
if (catchBlock instanceof SequentialBlock)
catchBlock = catchBlock.getSubBlocks()[1];
else {
catchBlock = new EmptyBlock();
catchBlock.moveJump(firstInstr.jump);
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; TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the surrounding tryBlock */ /* remove the unnecessary tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen; innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock); innerTry.replace(tryBlock);
tryBlock = innerTry; tryBlock = innerTry;
tryFlow.lastModified = tryBlock; tryFlow.lastModified = innerTry;
tryFlow.block = tryBlock;
} }
FinallyBlock newBlock = new FinallyBlock(); FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock); tryBlock.addCatchBlock(newBlock);
newBlock.setCatchBlock(catchBlock);
return true; return true;
} }
private boolean analyzeSpecialFinally(FlowBlock tryFlow,
FlowBlock catchFlow, 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.
*/
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;
}
}
}
/* remove the pop now */
firstInstr.removeBlock();
tryFlow.mergeAddr(catchFlow);
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);
/* 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;
}
/** /**
* Analyzes all exception handlers to try/catch/finally or * Analyzes all exception handlers to try/catch/finally or
* synchronized blocks. * synchronized blocks.
@ -959,16 +959,21 @@ public class TransformExceptionHandlers {
while (catchFlow.analyze(catchFlow.getAddr(), endHandler)); while (catchFlow.analyze(catchFlow.getAddr(), endHandler));
} }
/* Merge the try-block with the catch-block now */
tryFlow.updateInOutCatch(catchFlow); tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeAddr(catchFlow);
if (exc.type != null) if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow); analyzeCatchBlock(exc.type, tryFlow, catchFlow.block);
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler) else if (!analyzeSynchronized(tryFlow, catchFlow.block,
&& ! analyzeFinally(tryFlow, catchFlow, endHandler) endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow, && ! analyzeFinally(tryFlow, catchFlow.block,
endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow.block,
endHandler)) endHandler))
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow); analyzeCatchBlock(Type.tObject, tryFlow, catchFlow.block);
tryFlow.checkConsistent(); tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags

@ -207,19 +207,17 @@ public class CodeVerifier implements Opcodes {
dimensions++; dimensions++;
} }
if (c1 == '[' || c2 == '[') { // One of them is array now, the other is an object,
// Only one of them is array now, the other must be an // the common super is tObject
// object, the common super is tObject if ((c1 == '[' && c2 == 'L')
if (c1 == 'L' || c2 == 'L') { || (c1 == 'L' && c2 == '[')) {
if (dimensions == 0) if (dimensions == 0)
return tObject; return tObject;
StringBuffer result = new StringBuffer(dimensions + 18); StringBuffer result = new StringBuffer(dimensions + 18);
for (int i=0; i< dimensions; i++) for (int i=0; i< dimensions; i++)
result.append("["); result.append("[");
result.append("Ljava/lang/Object;"); result.append("Ljava/lang/Object;");
return tType(result.toString()); return tType(result.toString());
}
return tNone;
} }
if (c1 == 'L' && c2 == 'L') { if (c1 == 'L' && c2 == 'L') {
@ -240,6 +238,18 @@ public class CodeVerifier implements Opcodes {
.append(clazz1.getName().replace('.', '/')).append(";"); .append(clazz1.getName().replace('.', '/')).append(";");
return tType(result.toString()); 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; return tNone;
} }

@ -104,8 +104,9 @@ public class ArrayType extends ReferenceType {
if (type == tNull) if (type == tNull)
return this; return this;
if (type.getTypeCode() == TC_ARRAY) { if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection Type elType = elementType.intersection
(((ArrayType)type).elementType)); (((ArrayType)type).elementType);
return elType != tError ? tArray(elType) : tError;
} }
if (type.getTypeCode() == TC_CLASS) { if (type.getTypeCode() == TC_CLASS) {
ClassInterfacesType other = (ClassInterfacesType) type; ClassInterfacesType other = (ClassInterfacesType) type;
@ -124,7 +125,7 @@ public class ArrayType extends ReferenceType {
public Type getGeneralizedType(Type type) { public Type getGeneralizedType(Type type) {
/* tArray(x), tNull -> tArray(x) /* tArray(x), tNull -> tArray(x)
* tArray(x), tClass(y) -> common ifaces of tArray and tClass * 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 * tArray(x), other -> tError
*/ */
if (type.getTypeCode() == TC_RANGE) { if (type.getTypeCode() == TC_RANGE) {
@ -132,9 +133,11 @@ public class ArrayType extends ReferenceType {
} }
if (type == tNull) if (type == tNull)
return this; return this;
if (type.getTypeCode() == TC_ARRAY) if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection Type elType = elementType.intersection
(((ArrayType)type).elementType)); (((ArrayType)type).elementType);
return elType != tError ? tArray(elType) : tObject;
}
if (type.getTypeCode() == TC_CLASS) { if (type.getTypeCode() == TC_CLASS) {
ClassInterfacesType other = (ClassInterfacesType) type; ClassInterfacesType other = (ClassInterfacesType) type;
if (implementsAllIfaces(other.clazz, other.ifaces, arrayIfaces)) if (implementsAllIfaces(other.clazz, other.ifaces, arrayIfaces))

Loading…
Cancel
Save