New way to handle catch blocks, still needs finetuning

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1414 379699f6-c40d-0410-875b-85095c16579e
master
hoenicke 13 years ago
parent 744346bbcb
commit accfa1271e
  1. 20
      jode/src/net/sf/jode/decompiler/MethodAnalyzer.java
  2. 104
      jode/src/net/sf/jode/flow/FlowBlock.java
  3. 8
      jode/test/TryCatch.java

@ -458,10 +458,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
for (int i=0; i < blocks.length; i++) for (int i=0; i < blocks.length; i++)
flows[i] = new FlowBlock(this, i, i > 0 ? flows[i-1]: null); flows[i] = new FlowBlock(this, i, i > 0 ? flows[i-1]: null);
/* While we read the opcodes into FlowBlocks /* We transform every basic block into a FlowBlock
* we try to combine sequential blocks, as soon as we
* find two sequential instructions in a row, where the
* second has no predecessors.
*/ */
int count = 0; int count = 0;
for (int i=0; i < blocks.length; i++) { for (int i=0; i < blocks.length; i++) {
@ -510,22 +507,23 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
excHandlers = new TransformExceptionHandlers(flows); excHandlers = new TransformExceptionHandlers(flows);
for (int i=0; i<handlers.length; i++) { for (int i=0; i<handlers.length; i++) {
Type type = null; Type type = null;
FlowBlock start = flows[handlers[i].getStart().getBlockNr()]; int start = handlers[i].getStart().getBlockNr();
FlowBlock end = flows[handlers[i].getEnd().getBlockNr()]; int end = handlers[i].getEnd().getBlockNr();
FlowBlock handler FlowBlock handler = flows[handlers[i].getCatcher().getBlockNr()];
= flows[handlers[i].getCatcher().getBlockNr()];
if (handlers[i].getType() != null) if (handlers[i].getType() != null)
type = Type.tClass(classAnalyzer.getClassPath(), type = Type.tClass(classAnalyzer.getClassPath(),
handlers[i].getType()); handlers[i].getType());
for (int j = start; j <= end; j++) {
excHandlers.addHandler(start, end, handler, type); if (flows[j] != handler)
flows[j].addExceptionHandler(type, handler);
}
} }
} }
if (GlobalOptions.verboseLevel > 0) if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.print('-'); GlobalOptions.err.print('-');
excHandlers.analyze(); //excHandlers.analyze();
methodHeader.analyze(); methodHeader.analyze();
methodHeader.removeStartPred(); methodHeader.removeStartPred();

@ -24,6 +24,7 @@ import net.sf.jode.decompiler.MethodAnalyzer;
import net.sf.jode.decompiler.LocalInfo; import net.sf.jode.decompiler.LocalInfo;
import net.sf.jode.expr.Expression; import net.sf.jode.expr.Expression;
import net.sf.jode.expr.CombineableOperator; import net.sf.jode.expr.CombineableOperator;
import net.sf.jode.type.Type;
import net.sf.jode.util.SimpleMap; import net.sf.jode.util.SimpleMap;
///#def COLLECTIONS java.util ///#def COLLECTIONS java.util
@ -167,12 +168,18 @@ public class FlowBlock {
* The gen locals. This are the locals, which can be * The gen locals. This are the locals, which can be
* overwritten in this block on a path to the successor. That * overwritten in this block on a path to the successor. That
* means, that there exists a path form the start of the * means, that there exists a path form the start of the
* current flow block to the successor that contains a * current flow block to the successor that contains an
* assignments to this local, and that is not overwritten * assignments to this local, and that is not overwritten
* afterwards. * afterwards.
*/ */
VariableSet gen; VariableSet gen;
/**
* If this is non-null it contains an array list of all exception types
* for which the successor is the catch block.
*/
ArrayList catched;
/** /**
* The linked list of jumps. * The linked list of jumps.
*/ */
@ -216,7 +223,18 @@ public class FlowBlock {
/* We will put all jumps that we can not resolve into this /* We will put all jumps that we can not resolve into this
* linked list. * linked list.
*/ */
if (jumps == null)
return null;
Jump remainingJumps = null; Jump remainingJumps = null;
lastModified = jumps.prev;
StructuredBlock b = lastModified.outer;
while (b != null) {
if (b.outer instanceof TryBlock
&& ((TryBlock)b.outer).getSubBlocks()[0] == b) {
lastModified = b.outer;
}
b = b.outer;
}
if (lastModified.jump == null) { if (lastModified.jump == null) {
/* This can happen if lastModified is a breakable block, and /* This can happen if lastModified is a breakable block, and
@ -420,8 +438,8 @@ public class FlowBlock {
/* remove this jump if it jumps to the /* remove this jump if it jumps to the
* getNextFlowBlock(). */ * getNextFlowBlock(). */
if (jump.destination if (jump.prev.outer != null &&
== jump.prev.outer.getNextFlowBlock(jump.prev)) { jump.destination == jump.prev.outer.getNextFlowBlock(jump.prev)) {
jump.prev.removeJump(); jump.prev.removeJump();
continue; continue;
} }
@ -655,10 +673,14 @@ public class FlowBlock {
} else { } else {
myInfo.gen.addAll(hisInfo.gen); myInfo.gen.addAll(hisInfo.gen);
myInfo.kill.retainAll(hisInfo.kill); myInfo.kill.retainAll(hisInfo.kill);
Jump myJumps = myInfo.jumps; if (myInfo.jumps == null)
while (myJumps.next != null) myInfo.jumps = hisInfo.jumps;
myJumps = myJumps.next; else {
myJumps.next = hisInfo.jumps; Jump myJumps = myInfo.jumps;
while (myJumps.next != null)
myJumps = myJumps.next;
myJumps.next = hisInfo.jumps;
}
} }
} }
} }
@ -979,7 +1001,6 @@ public class FlowBlock {
} }
if (jumps.length > 0) if (jumps.length > 0)
lastModified.setSuccessors(jumps); lastModified.setSuccessors(jumps);
gen = null;
kill = null; kill = null;
checkConsistent(); checkConsistent();
} }
@ -1000,6 +1021,10 @@ public class FlowBlock {
checkConsistent(); checkConsistent();
succ.checkConsistent(); succ.checkConsistent();
/* Merge catching successors */
unifyCatchSuccessors(succ);
succ.unifyCatchSuccessors(this);
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0) & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println GlobalOptions.err.println
@ -1106,7 +1131,8 @@ public class FlowBlock {
/* Now remove the jump of the lastModified if it points to /* Now remove the jump of the lastModified if it points to
* END_OF_METHOD. * END_OF_METHOD.
*/ */
if (lastModified.jump.destination == END_OF_METHOD) if (lastModified.jump != null
&& lastModified.jump.destination == END_OF_METHOD)
lastModified.removeJump(); lastModified.removeJump();
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
@ -1306,7 +1332,7 @@ public class FlowBlock {
} }
/** /**
* Search for an apropriate successor. * Search for an appropriate successor.
* @param prevSucc The successor, that was previously tried. * @param prevSucc The successor, that was previously tried.
* @param start The minimum blockNr * @param start The minimum blockNr
* @param end The maximum blockNr + 1. * @param end The maximum blockNr + 1.
@ -1877,4 +1903,62 @@ public class FlowBlock {
return super.toString(); return super.toString();
} }
} }
public void addExceptionHandler(Type excType, FlowBlock handler) {
SuccessorInfo info = (SuccessorInfo) successors.get(handler);
if (info == null) {
info = new SuccessorInfo();
info.gen = (VariableSet) gen.clone();
successors.put(handler, info);
handler.predecessors.add(this);
}
info.kill = new SlotSet();
if (info.catched == null)
info.catched = new ArrayList();
info.catched.add(excType);
}
private void unifyCatchSuccessors(FlowBlock succ) {
Iterator iter = successors.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
FlowBlock dest = (FlowBlock) entry.getKey();
SuccessorInfo myInfo = (SuccessorInfo) entry.getValue();
if (myInfo.catched == null)
continue;
SuccessorInfo succInfo = (SuccessorInfo) succ.successors.get(dest);
Iterator catchedIter = myInfo.catched.iterator();
while (catchedIter.hasNext()) {
Type excType = (Type) catchedIter.next();
if (succInfo != null && succInfo.catched != null
&& succInfo.catched.contains(excType))
continue;
if (!(block instanceof TryBlock))
new TryBlock(this);
TryBlock tryBlock = (TryBlock) block;
if (excType != null) {
CatchBlock catchBlock = new CatchBlock(excType);
tryBlock.addCatchBlock(catchBlock);
Jump jump = new Jump(dest);
jump.next = myInfo.jumps;
myInfo.jumps = jump;
lastModified = new EmptyBlock(jump);
catchBlock.setCatchBlock(lastModified);
catchedIter.remove();
} else {
FinallyBlock catchBlock = new FinallyBlock();
tryBlock.addCatchBlock(catchBlock);
Jump jump = new Jump(dest);
jump.next = myInfo.jumps;
myInfo.jumps = jump;
lastModified = new EmptyBlock(jump);
catchBlock.setCatchBlock(lastModified);
catchedIter.remove();
}
}
if (myInfo.catched.isEmpty())
myInfo.catched = null;
}
}
} }

@ -23,7 +23,13 @@
* is try, catch, finally and synchronized. * is try, catch, finally and synchronized.
*/ */
class TryCatch { class TryCatch {
void verysimple() {
try {
foo();
} catch (RuntimeException ex) {
ex.printStackTrace();
}
}
int simple() { int simple() {
TryCatch i = null; TryCatch i = null;
try { try {

Loading…
Cancel
Save