*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@44 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 5a804dd214
commit 600f234a38
  1. 6
      jode/jode/bytecode/Opcodes.java
  2. 112
      jode/jode/decompiler/CodeAnalyzer.java
  3. 2
      jode/jode/decompiler/LocalVariableRangeList.java
  4. 2
      jode/jode/flow/CreateExpression.java
  5. 425
      jode/jode/flow/FlowBlock.java

@ -202,7 +202,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal
(ca, addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore],
ca.getLocalInfo(addr, stream.readUnsignedByte()),
ca.getLocalInfo(addr+2, stream.readUnsignedByte()),
Operator.ASSIGN_OP));
case opc_istore_0: case opc_istore_1:
case opc_istore_2: case opc_istore_3:
@ -217,7 +217,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal
(ca, addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4],
ca.getLocalInfo(addr, (opcode-opc_istore_0) & 3),
ca.getLocalInfo(addr+1, (opcode-opc_istore_0) & 3),
Operator.ASSIGN_OP));
case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore:
@ -481,7 +481,7 @@ public abstract class Opcodes implements RuntimeConstants {
(ca, addr, 4,
new LocalStoreOperator
(types[0][opcode-opc_istore],
ca.getLocalInfo(addr, stream.readUnsignedShort()),
ca.getLocalInfo(addr+4, stream.readUnsignedShort()),
Operator.ASSIGN_OP));
case opc_iinc: {
int local = stream.readUnsignedShort();

@ -107,7 +107,7 @@ public class CodeAnalyzer implements Analyzer, Constants {
+ (method.mdef.isStatic() ? 0 : 1);
param = new jode.flow.VariableSet();
for (int i=0; i<paramCount; i++)
param.addElement(getLocalInfo(-1, i));
param.addElement(getLocalInfo(0, i));
}
public void dumpSource(TabbedPrintWriter writer)
@ -137,117 +137,9 @@ public class CodeAnalyzer implements Analyzer, Constants {
return (LocalInfo) param.elementAt(slot);
}
static jode.flow.Transformation[] exprTrafos = {
new jode.flow.RemoveEmpty(),
new jode.flow.CreateExpression(),
new jode.flow.CreatePostIncExpression(),
new jode.flow.CreateAssignExpression(),
new jode.flow.CreateNewConstructor(),
new jode.flow.CombineIfGotoExpressions(),
new jode.flow.CreateIfThenElseOperator(),
new jode.flow.CreateConstantArray(),
new jode.flow.SimplifyExpression()
};
public void analyze()
{
/* XXX optimize */
Stack todo = new Stack();
FlowBlock flow = methodHeader;
try {
jode.TabbedPrintWriter writer = null;
if (Decompiler.isFlowDebugging) {
writer = new jode.TabbedPrintWriter(System.err, " ");
}
analyzation:
while (true) {
if (Decompiler.isFlowDebugging) {
writer.println("before Transformation: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
/* First do some non flow transformations. */
int i=0;
while (i < exprTrafos.length) {
if (exprTrafos[i].transform(flow))
i = 0;
else
i++;
}
if (Decompiler.isFlowDebugging) {
writer.println("after Transformation: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
if (flow.doT2(todo)) {
if (Decompiler.isFlowDebugging) {
writer.println("after T2: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
/* T2 transformation succeeded. This may
* make another T1 analysis in the previous
* block possible.
*/
if (!todo.isEmpty())
flow = (FlowBlock) todo.pop();
}
FlowBlock succ = flow.getSuccessor();
while (true) {
if (succ == null) {
/* the Block has no successor where t1 is applicable.
*
* If everything is okay the stack should be empty now,
* and the program is transformed correctly.
*/
if (todo.isEmpty())
break analyzation;
/* Otherwise pop the last flow block from stack and
* try another successor.
*/
succ = flow;
flow = (FlowBlock) todo.pop();
} else if (flow.doT1(succ)) {
/* T1 transformation succeeded. */
if (Decompiler.isFlowDebugging) {
writer.println("after T1: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
if (Decompiler.isVerbose)
System.err.print(".");
continue analyzation;
} else if (!todo.contains(succ) && succ != flow) {
/* succ wasn't tried before, succeed with
* successor and put flow on the stack.
*/
todo.push(flow);
flow = succ;
continue analyzation;
}
/* Try the next successor.
*/
succ = flow.getSuccessor(succ);
}
}
} catch (java.io.IOException ioex) {
}
methodHeader.analyze();
}
public String getTypeString(Type type) {

@ -64,7 +64,7 @@ public class LocalVariableRangeList implements LocalVariable {
MyLocalInfo li = list;
while (li != null && addr >= li.start+li.length)
li = li.next;
if (li == null || li.start > addr+2/*XXX*/) {
if (li == null || li.start > addr+1 /* XXX weired XXX */) {
LocalInfo temp = new LocalInfo(slot);
return temp;
}

@ -105,7 +105,7 @@ public class CreateExpression implements Transformation {
} catch (ClassCastException ex) {
return false;
}
if(jode.Decompiler.isVerbose && params > 0)
if(jode.Decompiler.isVerbose)
System.err.print("x");
((InstructionContainer) flow.lastModified).setInstruction

@ -22,6 +22,7 @@ import java.util.*;
import jode.TabbedPrintWriter;
import jode.Expression;
import jode.CodeAnalyzer;
import jode.Decompiler;
/**
* A flow block is the structure of which the flow graph consists. A
@ -533,42 +534,8 @@ public class FlowBlock {
* return_n
*/
/**
* Search for an apropriate successor.
* @param prevSucc The successor, that was previously tried.
* @return the successor with smallest address greater than prevSucc
* or null if there isn't any further successor at all.
*/
public FlowBlock getSuccessor(FlowBlock prevSucc) {
/* search successor with smallest addr. */
Enumeration enum = successors.elements();
FlowBlock succ = null;
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null)
continue;
FlowBlock fb = jump.destination;
if (prevSucc != null && fb.addr <= prevSucc.addr)
continue;
if (succ == null || fb.addr < succ.addr) {
// System.err.println("trying "+fb.getLabel());
succ = fb;
}
}
return succ;
}
/**
* Search for an apropriate successor.
* @return the successor with smallest address
* or null if there isn't a successor at all.
*/
public FlowBlock getSuccessor() {
return getSuccessor(null);
}
public void checkConsistent() {
if (!jode.Decompiler.doChecks)
if (!Decompiler.doChecks)
return;
if (block.outer != null || block.flowBlock != this) {
throw new RuntimeException("Inconsistency");
@ -878,7 +845,7 @@ public class FlowBlock {
return true;
}
public boolean doT2(Vector triedBlocks) {
public boolean doT2(int start, int end /* Vector triedBlocks */) {
/* If there are no jumps to the beginning of this flow block
* or if this block has other predecessors with a higher
* address, return false. The second condition make sure that
@ -890,7 +857,8 @@ public class FlowBlock {
while (preds.hasMoreElements()) {
FlowBlock predFlow = (FlowBlock) preds.nextElement();
if (predFlow != null && predFlow != this
&& !triedBlocks.contains(predFlow)) {
&& predFlow.addr >= start && predFlow.addr < end
/*&& !triedBlocks.contains(predFlow)*/) {
// System.err.println("refusing T2 on: "+getLabel()+
// " because of "+predFlow.getLabel());
/* XXX Is this enough to refuse T2 trafo ??? */
@ -1023,6 +991,389 @@ public class FlowBlock {
return true;
}
/**
* Do a T1 transformation with the end_of_method block.
*/
public void mergeEndBlock() {
try{
checkConsistent();
} catch (RuntimeException ex) {
ex.printStackTrace();
try {
jode.TabbedPrintWriter writer =
new jode.TabbedPrintWriter(System.err, " ");
writer.tab();
block.dumpSource(writer);
} catch (java.io.IOException ioex) {
}
}
/* First find the innermost block that contains all jumps to the
* END_OF_METHOD block.
*/
Enumeration enum = successors.elements();
StructuredBlock appendBlock = lastModified;
while(enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != END_OF_METHOD)
continue;
while (!appendBlock.contains(jump.prev)) {
appendBlock = appendBlock.outer;
if (appendBlock instanceof SequentialBlock
&& appendBlock.getSubBlocks()[0]
instanceof RawTryCatchBlock) {
/* We leave the catch block of a raw-try-catch-block.
* We shall now create the Catch- resp. FinallyBlock.
*/
appendBlock =
createCatchBlock((SequentialBlock)appendBlock);
}
}
/* appendBlock can't be null now, because the
* outermost block contains every structured block.
*/
}
/* Try to eliminate as many jumps as possible.
*/
appendBlock = optimizeJumps(END_OF_METHOD, appendBlock);
enum = successors.elements();
next_jump:
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != END_OF_METHOD ||
jump.prev == appendBlock)
continue;
BreakableBlock breakToBlock = null;
for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null && surrounder != appendBlock.outer;
surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
if (surrounder.getNextFlowBlock() == END_OF_METHOD)
breakToBlock = (BreakableBlock) surrounder;
/* We don't want labeled breaks, because we can
* simply return. */
break;
}
}
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
if (breakToBlock == null)
/* The successor is the dummy return instruction, so
* replace the jump with a return.
*/
prevBlock.appendBlock(new ReturnBlock());
else
prevBlock.appendBlock
(new BreakBlock(breakToBlock, false));
}
/* Now remove the jump of the appendBlock if it points to
* successor.
*/
if (appendBlock.jump != null
&& appendBlock.jump.destination == END_OF_METHOD)
appendBlock.removeJump();
/* transformation succeeded */
try {
checkConsistent();
} catch (RuntimeException ex) {
ex.printStackTrace();
try {
jode.TabbedPrintWriter writer =
new jode.TabbedPrintWriter(System.err, " ");
writer.tab();
block.dumpSource(writer);
} catch (java.io.IOException ioex) {
}
}
}
static Transformation[] exprTrafos = {
new RemoveEmpty(),
new CreateExpression(),
new CreatePostIncExpression(),
new CreateAssignExpression(),
new CreateNewConstructor(),
new CombineIfGotoExpressions(),
new CreateIfThenElseOperator(),
new CreateConstantArray(),
new SimplifyExpression()
};
/**
* Search for an apropriate successor.
* @param prevSucc The successor, that was previously tried.
* @param start The minimum address.
* @param end The maximum address + 1.
* @return the successor with smallest address greater than prevSucc
* or null if there isn't any further successor at all.
*/
FlowBlock getSuccessor(int start, int end) {
/* search successor with smallest addr. */
Enumeration enum = successors.elements();
FlowBlock succ = null;
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump == null)
continue;
FlowBlock fb = jump.destination;
if (fb.addr < start || fb.addr >= end || fb == this)
continue;
if (succ == null || fb.addr < succ.addr) {
// System.err.println("trying "+fb.getLabel());
succ = fb;
}
}
return succ;
}
/**
* The main analyzation. This calls doT1 and doT2 on apropriate
* regions.
*/
public void analyze() {
analyze(0, Integer.MAX_VALUE);
mergeEndBlock();
}
// /**
// * The main analyzation. This calls doT1 and doT2 on apropriate
// * regions. Only blocks whose address lies in the given address
// * range are considered.
// * @param start the start of the address range.
// * @param end the end of the address range.
// */
// public void analyze(int start, int end) {
// /* XXX optimize */
// Stack todo = new Stack();
// FlowBlock flow = this;
// try {
// jode.TabbedPrintWriter writer = null;
// if (Decompiler.isFlowDebugging) {
// writer = new jode.TabbedPrintWriter(System.err, " ");
// }
// analyzation:
// while (true) {
// if (Decompiler.isFlowDebugging) {
// writer.println("before Transformation: ");
// writer.tab();
// flow.dumpSource(writer);
// writer.untab();
// }
// /* First do some non flow transformations. */
// int i=0;
// while (i < exprTrafos.length) {
// if (exprTrafos[i].transform(flow))
// i = 0;
// else
// i++;
// }
// if (Decompiler.isFlowDebugging) {
// writer.println("after Transformation: ");
// writer.tab();
// flow.dumpSource(writer);
// writer.untab();
// }
// if (flow.doT2(todo)) {
// if (Decompiler.isFlowDebugging) {
// writer.println("after T2: ");
// writer.tab();
// flow.dumpSource(writer);
// writer.untab();
// }
// /* T2 transformation succeeded. This may
// * make another T1 analysis in the previous
// * block possible.
// */
// if (!todo.isEmpty())
// flow = (FlowBlock) todo.pop();
// }
// FlowBlock succ = flow.getSuccessor(start, end);
// while (true) {
// if (succ == null) {
// /* the Block has no successor where t1 is applicable.
// *
// * If everything is okay the stack should be empty now,
// * and the program is transformed correctly.
// */
// if (todo.isEmpty())
// break analyzation;
// /* Otherwise pop the last flow block from stack and
// * try another successor.
// */
// succ = flow;
// flow = (FlowBlock) todo.pop();
// } else {
// if (succ.block instanceof RawTryCatchBlock) {
// int subStart = succ.addr;
// int subEnd = (subStart >= addr)? end : addr;
// succ.analyze(subStart, subEnd);
// }
// if (flow.doT1(succ)) {
// /* T1 transformation succeeded. */
// if (Decompiler.isFlowDebugging) {
// writer.println("after T1: ");
// writer.tab();
// flow.dumpSource(writer);
// writer.untab();
// }
// if (Decompiler.isVerbose)
// System.err.print(".");
// continue analyzation;
// } else if (!todo.contains(succ) && succ != flow) {
// /* succ wasn't tried before, succeed with
// * successor and put flow on the stack.
// */
// todo.push(flow);
// flow = succ;
// continue analyzation;
// }
// }
// /* Try the next successor.
// */
// succ = flow.getSuccessor(succ.addr+1, end);
// }
// }
// } catch (java.io.IOException ioex) {
// }
// }
/**
* The main analyzation. This calls doT1 and doT2 on apropriate
* regions. Only blocks whose address lies in the given address
* range are considered.
* @param start the start of the address range.
* @param end the end of the address range.
*/
public boolean analyze(int start, int end) {
try {
jode.TabbedPrintWriter writer = null;
if (Decompiler.isFlowDebugging)
writer = new jode.TabbedPrintWriter(System.err, " ");
boolean changed = false;
while (true) {
if (Decompiler.isFlowDebugging) {
writer.println("before Transformation: ");
writer.tab();
dumpSource(writer);
writer.untab();
}
/* First do some non flow transformations. */
int i=0;
while (i < exprTrafos.length) {
if (exprTrafos[i].transform(this))
i = 0;
else
i++;
}
if (Decompiler.isFlowDebugging) {
writer.println("after Transformation: ");
writer.tab();
dumpSource(writer);
writer.untab();
}
if (doT2(start, end)) {
if (Decompiler.isFlowDebugging) {
writer.println("after T2: ");
writer.tab();
dumpSource(writer);
writer.untab();
}
/* T2 transformation succeeded. This may
* make another T1 analysis in the previous
* block possible.
*/
if (addr != 0)
return true;
}
FlowBlock succ = getSuccessor(start, end);
while (true) {
if (succ == null) {
/* the Block has no successor where t1 is applicable.
* Finish this analyzation.
*/
return changed;
} else {
if (succ.block instanceof RawTryCatchBlock) {
int subStart = succ.addr;
int subEnd = (subStart > addr)? end : addr;
succ.analyze(subStart, subEnd);
}
/* Only do T1 transformation if the blocks are
* adjacent. */
if ((succ.addr == addr+length
|| succ.addr+succ.length == addr)
&& doT1(succ)) {
/* T1 transformation succeeded. */
changed = true;
if (Decompiler.isFlowDebugging) {
writer.println("after T1: ");
writer.tab();
dumpSource(writer);
writer.untab();
}
break;
} else {
/* analyze succ, the new region is the
* continous region of
* [start,end) \cap \compl [addr, addr+length)
* where succ.addr lies in.
*/
int newStart = (succ.addr > addr)
? addr+length : start;
int newEnd = (succ.addr > addr)
? end : addr;
if (succ.analyze(newStart, newEnd))
break;
}
}
/* Try the next successor.
*/
succ = getSuccessor(succ.addr+1, end);
}
}
} catch (java.io.IOException ioex) {
return false;
}
}
/**
* Resolves the destinations of all jumps.
*/

Loading…
Cancel
Save