big rework: sort with SortedSet, handle shared handlers

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1006 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 127778a8b3
commit d6eaa40737
  1. 244
      jode/jode/flow/TransformExceptionHandlers.java

@ -25,11 +25,16 @@ import jode.decompiler.LocalInfo;
import jode.expr.*; import jode.expr.*;
///#ifdef JDK12 ///#ifdef JDK12
///import java.util.TreeSet;
///import java.util.SortedSetSet;
///import java.util.Map; ///import java.util.Map;
///import java.util.Iterator; ///import java.util.Iterator;
///#else ///#else
import jode.util.TreeSet;
import jode.util.SortedSet;
import jode.util.Map; import jode.util.Map;
import jode.util.Iterator; import jode.util.Iterator;
import jode.util.Comparable;
///#endif ///#endif
/** /**
@ -37,14 +42,48 @@ import jode.util.Iterator;
* @author Jochen Hoenicke * @author Jochen Hoenicke
*/ */
public class TransformExceptionHandlers { public class TransformExceptionHandlers {
int count; SortedSet handlers;
FlowBlock[] trys = new FlowBlock[4];
FlowBlock[] catches = new FlowBlock[4]; static class Handler implements Comparable {
int[] endPCs = new int[4]; FlowBlock start;
Type[] types = new Type[4]; int endAddr;
FlowBlock handler;
Type type;
public Handler(FlowBlock tryBlock, int end,
FlowBlock catchBlock, Type type) {
this.start = tryBlock;
this.endAddr = end;
this.handler = catchBlock;
this.type = type;
}
public int compareTo (Object o) {
Handler second = (Handler) o;
/* First sort by start offsets, highest address first...*/
if (start.addr != second.start.addr)
/* this subtraction is save since addresses are only 16 bit */
return second.start.addr - start.addr;
/* ...Second sort by end offsets, lowest address first...
* this will move the innermost blocks to the beginning. */
if (endAddr != second.endAddr)
return endAddr - second.endAddr;
/* ...Last sort by handler offsets, lowest first */
if (handler.addr != second.handler.addr)
return handler.addr - second.handler.addr;
/* ...Last sort by typecode signature. Shouldn't happen to often.
*/
return type.getTypeSignature()
.compareTo(second.type.getTypeSignature());
}
}
public TransformExceptionHandlers() { public TransformExceptionHandlers() {
count = 0; handlers = new TreeSet();
} }
/** /**
@ -56,65 +95,7 @@ public class TransformExceptionHandlers {
*/ */
public void addHandler(FlowBlock tryBlock, int end, public void addHandler(FlowBlock tryBlock, int end,
FlowBlock catchBlock, Type type) { FlowBlock catchBlock, Type type) {
int offset = 0; handlers.add(new Handler(tryBlock, end, catchBlock, type));
int start = tryBlock.addr;
int handler = catchBlock.addr;
/* First sort by start offsets, highest address first...*/
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 == trys[offset].addr
&& end > endPCs[offset])
offset++;
/* ...Last sort by handler offsets, lowest first */
while (offset < count && start == trys[offset].addr
&& end == endPCs[offset] && handler > catches[offset].addr)
offset++;
if (count++ >= trys.length) {
/* We grow the arrays by 50 % */
int newSize = trys.length * 3 / 2;
FlowBlock[] newTrys = new FlowBlock[newSize];
int[] newEndPCs = new int[newSize];
FlowBlock[] newCatches = new FlowBlock[newSize];
Type[] newTypes = new Type[newSize];
System.arraycopy(trys, 0, newTrys, 0, offset);
System.arraycopy(endPCs, 0, newEndPCs, 0, offset);
System.arraycopy(catches, 0, newCatches, 0, offset);
System.arraycopy(types, 0, newTypes, 0, offset);
if (offset+1 < count) {
System.arraycopy(trys, offset, newTrys, offset+1,
count-offset-1);
System.arraycopy(endPCs, offset, newEndPCs, offset+1,
count-offset-1);
System.arraycopy(catches, offset, newCatches, offset+1,
count-offset-1);
System.arraycopy(types, offset, newTypes, offset+1,
count-offset-1);
}
trys = newTrys;
endPCs = newEndPCs;
catches = newCatches;
types = newTypes;
} else if (offset+1 < count) {
/* Move the tailing data one place below
*/
System.arraycopy(trys, offset, trys, offset+1,
count-offset-1);
System.arraycopy(endPCs, offset, endPCs, offset+1,
count-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 */
trys[offset] = tryBlock;
endPCs[offset] = end;
catches[offset] = catchBlock;
types[offset] = type;
} }
/** /**
@ -801,42 +782,60 @@ public class TransformExceptionHandlers {
* for all classes generated by the sun java compiler, but hand * for all classes generated by the sun java compiler, but hand
* optimized classes (or generated by other compilers) will fail. * optimized classes (or generated by other compilers) will fail.
*/ */
for (int i=0; i<count; i++) { {
int start = trys[i].addr; Handler last = null;
int end = endPCs[i]; for (Iterator i = handlers.iterator(); i.hasNext(); ) {
int handler = catches[i].addr; Handler exc = (Handler) i.next();
int start = exc.start.addr;
int end = exc.endAddr;
int handler = exc.handler.addr;
if (start >= end || handler < end) if (start >= end || handler < end)
throw new AssertError("ExceptionHandler order failed: not " throw new AssertError
+ start + " < " + end + " <= " + ("ExceptionHandler order failed: not "
handler); + start + " < " + end + " <= " + handler);
if (i == 0 if (last != null
|| trys[i-1].addr != start || endPCs[i-1] != end) { && (last.start.addr != start || last.endAddr != end)) {
/* The last handler does catch another range. */ /* The last handler does catch another range.
if ( /*handler > end + 1 || */ * Due to the order:
(i > 0 && end > trys[i-1].addr && end < endPCs[i-1])) * start < last.start.addr || end > last.end.addr
throw new AssertError("ExceptionHandler" */
+ " at wrong position: " if (end > last.start.addr && end < last.endAddr)
+ "end: "+end + " handler: "+handler throw new AssertError
+ (i>0 ? " last: ("+trys[i-1].addr ("Exception handlers ranges are intersecting: ["
+", "+endPCs[i-1]+", " + last.start.addr+", "+last.endAddr+"] and ["
+catches[i-1].addr+")" + start+", "+end+"].");
:"")); }
} last = exc;
} }
}
for (int i=0; i<count; i++) {
int endHandler = (i< count-1 && endPCs[i+1] > catches[i].addr) {
? endPCs[i+1] Iterator i = handlers.iterator();
: Integer.MAX_VALUE; Handler exc = null;
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) Handler next = i.hasNext() ? (Handler) i.next() : null;
GlobalOptions.err.println("analyzeCatch(" + trys[i].addr + ", " while(next != null) {
+ endPCs[i] + ", " +catches[i].addr + ")"); Handler last = exc;
FlowBlock tryFlow = trys[i]; exc = next;
tryFlow.checkConsistent(); next = i.hasNext() ? (Handler) i.next() : null;
while (tryFlow.analyze(tryFlow.addr, catches[i].addr)); int endHandler = Integer.MAX_VALUE;
/* If the next exception handler catches a bigger range
* it must surround the handler completely.
*/
if (next != null && next.endAddr > exc.endAddr)
endHandler = next.endAddr;
if (i == 0 FlowBlock tryFlow = exc.start;
|| trys[i-1].addr != trys[i].addr || endPCs[i-1] != endPCs[i]) { tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTry("
+ exc.start.addr + ", " + exc.endAddr+")");
while (tryFlow.analyze(tryFlow.addr, exc.endAddr));
if (last == null
|| last.start.addr != exc.start.addr
|| last.endAddr != exc.endAddr) {
/* The last handler does catch another range. /* The last handler does catch another range.
* Create a new try block. * Create a new try block.
*/ */
@ -844,12 +843,43 @@ public class TransformExceptionHandlers {
} else if (! (tryFlow.block instanceof TryBlock)) } else if (! (tryFlow.block instanceof TryBlock))
throw new AssertError("no TryBlock"); throw new AssertError("no TryBlock");
FlowBlock catchFlow = catches[i]; FlowBlock catchFlow = exc.handler;
boolean isMultiUsed = catchFlow.predecessors.size() != 0;
if (!isMultiUsed) {
for (Iterator j = handlers.tailSet(next).iterator();
j.hasNext();) {
Handler h = (Handler) j.next();
if (h.handler == catchFlow) {
isMultiUsed = true;
break;
}
}
}
if (isMultiUsed) {
/* If this exception is used in other exception handlers,
* create a new flow block, that jumps to the handler.
* This will be our new exception handler.
*/
EmptyBlock jump = new EmptyBlock(new Jump(catchFlow));
FlowBlock newFlow = new FlowBlock(catchFlow.method,
catchFlow.addr, 0);
newFlow.setBlock(jump);
catchFlow.prevByAddr.setNextByAddr(newFlow);
newFlow.setNextByAddr(catchFlow);
catchFlow = newFlow;
} else {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeCatch("
+ catchFlow.addr + ", " + endHandler + ")");
while (catchFlow.analyze(catchFlow.addr, endHandler)); while (catchFlow.analyze(catchFlow.addr, endHandler));
}
updateInOutCatch(tryFlow, catchFlow); updateInOutCatch(tryFlow, catchFlow);
if (types[i] != null) if (exc.type != null)
analyzeCatchBlock(types[i], tryFlow, catchFlow); analyzeCatchBlock(exc.type, tryFlow, catchFlow);
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler) else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler)
&& ! analyzeFinally(tryFlow, catchFlow, endHandler) && ! analyzeFinally(tryFlow, catchFlow, endHandler)
@ -859,10 +889,12 @@ public class TransformExceptionHandlers {
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow); analyzeCatchBlock(Type.tObject, tryFlow, catchFlow);
tryFlow.checkConsistent(); tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) if ((GlobalOptions.debuggingFlags
GlobalOptions.err.println("analyzeCatch(" + tryFlow.addr + ", " & GlobalOptions.DEBUG_ANALYZE) != 0)
+ (tryFlow.addr + tryFlow.length) + GlobalOptions.err.println
") done."); ("analyzeCatch(" + tryFlow.addr + ", "
+ (tryFlow.addr + tryFlow.length) + ") done.");
}
} }
} }
} }

Loading…
Cancel
Save