|
|
@ -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]; |
|
|
|
|
|
|
|
int[] endPCs = new int[4]; |
|
|
|
|
|
|
|
Type[] types = new Type[4]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static class Handler implements Comparable { |
|
|
|
|
|
|
|
FlowBlock start; |
|
|
|
|
|
|
|
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,68 +782,119 @@ 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(); |
|
|
|
if (start >= end || handler < end) |
|
|
|
int start = exc.start.addr; |
|
|
|
throw new AssertError("ExceptionHandler order failed: not " |
|
|
|
int end = exc.endAddr; |
|
|
|
+ start + " < " + end + " <= " + |
|
|
|
int handler = exc.handler.addr; |
|
|
|
handler); |
|
|
|
if (start >= end || handler < end) |
|
|
|
if (i == 0 |
|
|
|
throw new AssertError |
|
|
|
|| trys[i-1].addr != start || endPCs[i-1] != end) { |
|
|
|
("ExceptionHandler order failed: not " |
|
|
|
/* The last handler does catch another range. */ |
|
|
|
+ start + " < " + end + " <= " + handler); |
|
|
|
if ( /*handler > end + 1 || */ |
|
|
|
if (last != null |
|
|
|
(i > 0 && end > trys[i-1].addr && end < endPCs[i-1])) |
|
|
|
&& (last.start.addr != start || last.endAddr != end)) { |
|
|
|
throw new AssertError("ExceptionHandler" |
|
|
|
/* The last handler does catch another range. |
|
|
|
+ " at wrong position: " |
|
|
|
* Due to the order: |
|
|
|
+ "end: "+end + " handler: "+handler |
|
|
|
* start < last.start.addr || end > last.end.addr |
|
|
|
+ (i>0 ? " last: ("+trys[i-1].addr |
|
|
|
*/ |
|
|
|
+", "+endPCs[i-1]+", " |
|
|
|
if (end > last.start.addr && end < last.endAddr) |
|
|
|
+catches[i-1].addr+")" |
|
|
|
throw new AssertError |
|
|
|
:"")); |
|
|
|
("Exception handlers ranges are intersecting: [" |
|
|
|
} |
|
|
|
+ last.start.addr+", "+last.endAddr+"] and [" |
|
|
|
} |
|
|
|
+ start+", "+end+"]."); |
|
|
|
|
|
|
|
} |
|
|
|
for (int i=0; i<count; i++) { |
|
|
|
last = exc; |
|
|
|
int endHandler = (i< count-1 && endPCs[i+1] > catches[i].addr) |
|
|
|
} |
|
|
|
? endPCs[i+1] |
|
|
|
} |
|
|
|
: Integer.MAX_VALUE; |
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
|
|
|
|
GlobalOptions.err.println("analyzeCatch(" + trys[i].addr + ", " |
|
|
|
|
|
|
|
+ endPCs[i] + ", " +catches[i].addr + ")"); |
|
|
|
|
|
|
|
FlowBlock tryFlow = trys[i]; |
|
|
|
|
|
|
|
tryFlow.checkConsistent(); |
|
|
|
|
|
|
|
while (tryFlow.analyze(tryFlow.addr, catches[i].addr)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i == 0 |
|
|
|
|
|
|
|
|| trys[i-1].addr != trys[i].addr || endPCs[i-1] != endPCs[i]) { |
|
|
|
|
|
|
|
/* The last handler does catch another range. |
|
|
|
|
|
|
|
* Create a new try block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
TryBlock tryBlock = new TryBlock(tryFlow); |
|
|
|
|
|
|
|
} else if (! (tryFlow.block instanceof TryBlock)) |
|
|
|
|
|
|
|
throw new AssertError("no TryBlock"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FlowBlock catchFlow = catches[i]; |
|
|
|
|
|
|
|
while (catchFlow.analyze(catchFlow.addr, endHandler)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateInOutCatch(tryFlow, catchFlow); |
|
|
|
|
|
|
|
if (types[i] != null) |
|
|
|
|
|
|
|
analyzeCatchBlock(types[i], tryFlow, catchFlow); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler) |
|
|
|
|
|
|
|
&& ! analyzeFinally(tryFlow, catchFlow, endHandler) |
|
|
|
|
|
|
|
&& ! analyzeSpecialFinally(tryFlow, catchFlow, |
|
|
|
|
|
|
|
endHandler)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tryFlow.checkConsistent(); |
|
|
|
{ |
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
Iterator i = handlers.iterator(); |
|
|
|
GlobalOptions.err.println("analyzeCatch(" + tryFlow.addr + ", " |
|
|
|
Handler exc = null; |
|
|
|
+ (tryFlow.addr + tryFlow.length) + |
|
|
|
Handler next = i.hasNext() ? (Handler) i.next() : null; |
|
|
|
") done."); |
|
|
|
while(next != null) { |
|
|
|
} |
|
|
|
Handler last = exc; |
|
|
|
|
|
|
|
exc = next; |
|
|
|
|
|
|
|
next = i.hasNext() ? (Handler) i.next() : null; |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FlowBlock tryFlow = exc.start; |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
* Create a new try block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
TryBlock tryBlock = new TryBlock(tryFlow); |
|
|
|
|
|
|
|
} else if (! (tryFlow.block instanceof TryBlock)) |
|
|
|
|
|
|
|
throw new AssertError("no TryBlock"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateInOutCatch(tryFlow, catchFlow); |
|
|
|
|
|
|
|
if (exc.type != null) |
|
|
|
|
|
|
|
analyzeCatchBlock(exc.type, tryFlow, catchFlow); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler) |
|
|
|
|
|
|
|
&& ! analyzeFinally(tryFlow, catchFlow, endHandler) |
|
|
|
|
|
|
|
&& ! analyzeSpecialFinally(tryFlow, catchFlow, |
|
|
|
|
|
|
|
endHandler)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tryFlow.checkConsistent(); |
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
|
|
|
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
|
|
|
|
GlobalOptions.err.println |
|
|
|
|
|
|
|
("analyzeCatch(" + tryFlow.addr + ", " |
|
|
|
|
|
|
|
+ (tryFlow.addr + tryFlow.length) + ") done."); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|