big fixes for jikes try catch

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@212 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent f53c089094
commit b264c0e8a8
  1. 167
      jode/jode/flow/TransformExceptionHandlers.java

@ -30,15 +30,13 @@ import java.util.Enumeration;
* @author Jochen Hoenicke
*/
public class TransformExceptionHandlers {
FlowBlock[] flows;
int count;
int[] startPCs = new int[4];
FlowBlock[] trys = new FlowBlock[4];
FlowBlock[] catches = new FlowBlock[4];
int[] endPCs = new int[4];
int[] handlerPCs = new int[4];
Type[] types = new Type[4];
public TransformExceptionHandlers(FlowBlock[] flowBlocks) {
flows = flowBlocks;
public TransformExceptionHandlers() {
count = 0;
}
@ -49,63 +47,66 @@ public class TransformExceptionHandlers {
* @param handler The address of the handler.
* @param type The type of the exception, null for ALL.
*/
public void addHandler(int start, int end, int handler, Type type) {
public void addHandler(FlowBlock tryBlock, int end,
FlowBlock catchBlock, Type type) {
int offset = 0;
int start = tryBlock.addr;
int handler = catchBlock.addr;
/* First sort by start offsets, highest address first...*/
while (offset < count && start < startPCs[offset])
while (offset < count && start < trys[offset].addr)
offset++;
/* ...Second sort by end offsets, lowest address first...
* this will move the innermost blocks to the beginning. */
while (offset < count && start == startPCs[offset]
while (offset < count && start == trys[offset].addr
&& end > endPCs[offset])
offset++;
/* ...Last sort by handler offsets, lowest first */
while (offset < count && start == startPCs[offset]
&& end == endPCs[offset] && handler > handlerPCs[offset])
while (offset < count && start == trys[offset].addr
&& end == endPCs[offset] && handler > catches[offset].addr)
offset++;
if (count++ >= startPCs.length) {
if (count++ >= trys.length) {
/* We grow the arrays by 50 % */
int newSize = startPCs.length * 3 / 2;
int[] newStartPCs = new int[newSize];
int newSize = trys.length * 3 / 2;
FlowBlock[] newTrys = new FlowBlock[newSize];
int[] newEndPCs = new int[newSize];
int[] newHandlerPCs = new int[newSize];
FlowBlock[] newCatches = new FlowBlock[newSize];
Type[] newTypes = new Type[newSize];
System.arraycopy(startPCs, 0, newStartPCs, 0, offset);
System.arraycopy(trys, 0, newTrys, 0, offset);
System.arraycopy(endPCs, 0, newEndPCs, 0, offset);
System.arraycopy(handlerPCs, 0, newHandlerPCs, 0, offset);
System.arraycopy(catches, 0, newCatches, 0, offset);
System.arraycopy(types, 0, newTypes, 0, offset);
if (offset+1 < count) {
System.arraycopy(startPCs, offset, newStartPCs, offset+1,
System.arraycopy(trys, offset, newTrys, offset+1,
count-offset-1);
System.arraycopy(endPCs, offset, newEndPCs, offset+1,
count-offset-1);
System.arraycopy(handlerPCs, offset, newHandlerPCs, offset+1,
System.arraycopy(catches, offset, newCatches, offset+1,
count-offset-1);
System.arraycopy(types, offset, newTypes, offset+1,
count-offset-1);
}
startPCs = newStartPCs;
trys = newTrys;
endPCs = newEndPCs;
handlerPCs = newHandlerPCs;
catches = newCatches;
types = newTypes;
} else if (offset+1 < count) {
/* Move the tailing data one place below
*/
System.arraycopy(startPCs, offset, startPCs, offset+1,
System.arraycopy(trys, offset, trys, offset+1,
count-offset-1);
System.arraycopy(endPCs, offset, endPCs, offset+1,
count-offset-1);
System.arraycopy(handlerPCs, offset, handlerPCs, offset+1,
System.arraycopy(catches, offset, catches, offset+1,
count-offset-1);
System.arraycopy(types, offset, types, offset+1,
count-offset-1);
}
/* Insert the new handler */
startPCs[offset] = start;
trys[offset] = tryBlock;
endPCs[offset] = end;
handlerPCs[offset] = handler;
catches[offset] = catchBlock;
types[offset] = type;
}
@ -114,7 +115,17 @@ public class TransformExceptionHandlers {
* successing flow block for a try catch block. The main difference
* to updateInOut in FlowBlock is, that this function works, as if
* every instruction would have a jump. This is because every
* instruction can throw an exception and thus enter the catch block.
* instruction can throw an exception and thus enter the catch block.<br>
*
* For example this code prints <code>0</code>:
* <pre>
* int a=3;
* try {
* a = 5 / (a=0);
* } catch (DivideByZeroException ex) {
* System.err.println(a);
* }
* </pre>
*
* @param successor The flow block which is unified with this flow
* block.
@ -166,17 +177,18 @@ public class TransformExceptionHandlers {
StructuredBlock firstInstr = (catchBlock instanceof SequentialBlock)
? catchBlock.getSubBlocks()[0] : catchBlock;
if (firstInstr instanceof InstructionBlock) {
if (firstInstr instanceof SpecialBlock
&& ((SpecialBlock) firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock) firstInstr).count == 1) {
/* The exception is ignored. Create a dummy local for it */
local = new LocalInfo(-1);
local.setName("exception");
firstInstr.removeBlock();
} else if (firstInstr instanceof InstructionBlock) {
Expression instr =
((InstructionBlock) firstInstr).getInstruction();
if (instr instanceof PopOperator
&& ((PopOperator) instr).getCount() == 1) {
/* The exception is ignored. Create a dummy local for it */
local = new LocalInfo(-1);
local.setName("exception");
firstInstr.removeBlock();
} else if (instr instanceof LocalStoreOperator) {
if (instr instanceof LocalStoreOperator) {
/* The exception is stored in a local variable */
local = ((LocalStoreOperator) instr).getLocalInfo();
firstInstr.removeBlock();
@ -193,7 +205,7 @@ public class TransformExceptionHandlers {
((TryBlock)tryFlow.block).addCatchBlock(newBlock);
newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.length += catchFlow.length;
tryFlow.mergeAddr(catchFlow);
}
/* And now the complicated parts. */
@ -216,6 +228,18 @@ public class TransformExceptionHandlers {
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.
*
* 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)
|| !(((RetBlock)sequBlock.subBlocks[1])
.local.equals(store.getLocalInfo())))
@ -465,7 +489,7 @@ public class TransformExceptionHandlers {
((InstructionBlock)subRoutine.block)
.getInstruction();
if (isMonitorExit(instr, local)) {
tryFlow.length += subRoutine.length;
tryFlow.mergeAddr(subRoutine);
continue dest_loop;
}
}
@ -540,10 +564,10 @@ public class TransformExceptionHandlers {
LocalInfo local =
((LocalLoadOperator)monexit.getSubExpressions()[0])
.getLocalInfo();
tryFlow.length += catchFlow.length;
tryFlow.mergeAddr(catchFlow);
checkAndRemoveMonitorExit
(tryFlow, local, catchFlow.addr+catchFlow.length, endHandler);
(tryFlow, local, catchFlow.getNextAddr(), endHandler);
SynchronizedBlock syncBlock = new SynchronizedBlock(local);
TryBlock tryBlock = (TryBlock) tryFlow.block;
@ -613,7 +637,7 @@ public class TransformExceptionHandlers {
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock;
}
}
if (catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock
&& instr instanceof LocalStoreOperator
@ -667,7 +691,7 @@ public class TransformExceptionHandlers {
transformSubRoutine(finallyBlock);
updateInOutCatch(tryFlow, catchFlow);
tryFlow.length += catchFlow.length;
tryFlow.mergeAddr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
@ -676,16 +700,16 @@ public class TransformExceptionHandlers {
((JsrBlock)catchBlock.getSubBlocks()[0])
.innerBlock.jump.destination;
subRoutine.analyze(catchFlow.addr+catchFlow.length, end);
subRoutine.analyze(catchFlow.getNextAddr(), end);
if (!transformSubRoutine(subRoutine.block))
return false;
tryFlow.length += catchFlow.length;
tryFlow.mergeAddr(catchFlow);
checkAndRemoveJSR(tryFlow, subRoutine);
updateInOutCatch(tryFlow, subRoutine);
tryFlow.length += subRoutine.length;
tryFlow.mergeAddr(subRoutine);
tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block;
@ -722,11 +746,9 @@ public class TransformExceptionHandlers {
catchFlow.block instanceof SequentialBlock
? catchFlow.block.getSubBlocks()[0]: catchFlow.block;
if (firstInstr instanceof InstructionBlock
&& ((InstructionBlock) firstInstr).getInstruction()
instanceof PopOperator
&& ((PopOperator) ((InstructionBlock) firstInstr)
.getInstruction()).getCount() == 1) {
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
@ -756,7 +778,7 @@ public class TransformExceptionHandlers {
/* remove the pop now */
firstInstr.removeBlock();
tryFlow.length += catchFlow.length;
tryFlow.mergeAddr(catchFlow);
if (succ != null) {
Jump jumps = (Jump) tryFlow.successors.remove(succ);
@ -781,8 +803,8 @@ public class TransformExceptionHandlers {
/* try block has no successors */
if (succ != null && succ.predecessors.size() == 1) {
while (succ.analyze(catchFlow.addr+catchFlow.length, end));
tryFlow.length += succ.length;
while (succ.analyze(catchFlow.getNextAddr(), end));
tryFlow.mergeAddr(succ);
tryFlow.successors.remove(succ);
newBlock.setCatchBlock(succ.block);
tryFlow.mergeSuccessors(succ);
@ -804,43 +826,43 @@ public class TransformExceptionHandlers {
public void analyze() {
/* Check if try/catch ranges are okay. The following succeeds
* for all classes generated by the sun java compiler, but hand
* optimized classes will fail this.
* optimized classes (or generated by other compilers) will fail.
*/
for (int i=0; i<count; i++) {
int start = startPCs[i];
int start = trys[i].addr;
int end = endPCs[i];
int handler = handlerPCs[i];
int handler = catches[i].addr;
if (start >= end || handler < end)
throw new AssertError("ExceptionHandler order failed: not "
+ start + " < " + end + " <= " +
handler);
if (i == 0
|| startPCs[i-1] != start || endPCs[i-1] != end) {
|| trys[i-1].addr != start || endPCs[i-1] != end) {
/* The last handler does catch another range. */
if ( /*handler > end + 1 || */
(i > 0 && end > startPCs[i-1] && end < endPCs[i-1]))
(i > 0 && end > trys[i-1].addr && end < endPCs[i-1]))
throw new AssertError("ExceptionHandler"
+ " at wrong position: "
+ "end: "+end + " handler: "+handler
+ (i>0 ? " last: ("+startPCs[i-1]
+ (i>0 ? " last: ("+trys[i-1].addr
+", "+endPCs[i-1]+", "
+handlerPCs[i-1]+")"
+catches[i-1].addr+")"
:""));
}
}
for (int i=0; i<count; i++) {
int endHandler = (i< count-1 && endPCs[i+1] > handlerPCs[i])
int endHandler = (i< count-1 && endPCs[i+1] > catches[i].addr)
? endPCs[i+1]
: Integer.MAX_VALUE;
if (Decompiler.debugAnalyze)
Decompiler.err.println("analyzeCatch(" + startPCs[i] + ", "
+ endPCs[i] + ", " +handlerPCs[i] + ")");
FlowBlock tryFlow = flows[startPCs[i]];
while (tryFlow.analyze(startPCs[i], handlerPCs[i]));
Decompiler.err.println("analyzeCatch(" + trys[i].addr + ", "
+ endPCs[i] + ", " +catches[i].addr + ")");
FlowBlock tryFlow = trys[i];
while (tryFlow.analyze(tryFlow.addr, catches[i].addr));
if (i == 0
|| startPCs[i-1] != startPCs[i] || endPCs[i-1] != endPCs[i]) {
|| trys[i-1].addr != trys[i].addr || endPCs[i-1] != endPCs[i]) {
/* The last handler does catch another range.
* Create a new try block.
*/
@ -848,19 +870,8 @@ public class TransformExceptionHandlers {
} else if (! (tryFlow.block instanceof TryBlock))
throw new AssertError("no TryBlock");
FlowBlock catchFlow = flows[handlerPCs[i]];
while (catchFlow.analyze(handlerPCs[i], endHandler));
if (!catchFlow.predecessors.isEmpty()) {
/* This can actually happen, namely in code compiled by
* jikes. In this case the predecessor is a nop and has
* no further predecessors.
*/
if (catchFlow.predecessors.size() != 1
&& ((FlowBlock)catchFlow.predecessors.elementAt(0))
.predecessors.size() != 0)
throw new AssertError("Handler has a predecessors");
}
FlowBlock catchFlow = catches[i];
while (catchFlow.analyze(catchFlow.addr, endHandler));
updateInOutCatch(tryFlow, catchFlow);
if (types[i] != null)

Loading…
Cancel
Save