*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@28 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 63de7d6b8d
commit c451fada4a
  1. 19
      jode/jode/bytecode/Opcodes.java
  2. 34
      jode/jode/decompiler/CodeAnalyzer.java
  3. 21
      jode/jode/decompiler/LocalInfo.java
  4. 11
      jode/jode/decompiler/MethodAnalyzer.java
  5. 2
      jode/jode/flow/CombineIfGotoExpressions.java
  6. 36
      jode/jode/flow/ConditionalBlock.java
  7. 47
      jode/jode/flow/CreateExpression.java
  8. 4
      jode/jode/flow/CreateNewConstructor.java
  9. 111
      jode/jode/flow/FlowBlock.java
  10. 32
      jode/jode/flow/InstructionBlock.java
  11. 41
      jode/jode/flow/InstructionContainer.java
  12. 28
      jode/jode/flow/Jump.java
  13. 6
      jode/jode/flow/RemoveEmpty.java
  14. 20
      jode/jode/flow/ReturnBlock.java
  15. 103
      jode/jode/flow/StructuredBlock.java
  16. 39
      jode/jode/flow/VariableSet.java

@ -156,7 +156,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal return createNormal
(addr, 2, new LocalLoadOperator (addr, 2, new LocalLoadOperator
(types[0][opcode-opc_iload], (types[0][opcode-opc_iload],
new LocalInfo(stream.readUnsignedByte()))); ca.getLocalInfo(addr, stream.readUnsignedByte())));
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3:
case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3:
case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3:
@ -165,7 +165,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal return createNormal
(addr, 1, new LocalLoadOperator (addr, 1, new LocalLoadOperator
(types[0][(opcode-opc_iload_0)/4], (types[0][(opcode-opc_iload_0)/4],
new LocalInfo((opcode-opc_iload_0) & 3))); ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3)));
case opc_iaload: case opc_laload: case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload: case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload: case opc_baload: case opc_caload: case opc_saload:
@ -177,7 +177,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal return createNormal
(addr, 2, new LocalStoreOperator (addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore], (types[0][opcode-opc_istore],
new LocalInfo(stream.readUnsignedByte()), ca.getLocalInfo(addr, stream.readUnsignedByte()),
Operator.ASSIGN_OP)); Operator.ASSIGN_OP));
case opc_istore_0: case opc_istore_1: case opc_istore_0: case opc_istore_1:
case opc_istore_2: case opc_istore_3: case opc_istore_2: case opc_istore_3:
@ -192,7 +192,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal return createNormal
(addr, 1, new LocalStoreOperator (addr, 1, new LocalStoreOperator
(types[0][(opcode-opc_istore_0)/4], (types[0][(opcode-opc_istore_0)/4],
new LocalInfo((opcode-opc_istore_0) & 3), ca.getLocalInfo(addr, (opcode-opc_istore_0) & 3),
Operator.ASSIGN_OP)); Operator.ASSIGN_OP));
case opc_iastore: case opc_lastore: case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore: case opc_fastore: case opc_dastore: case opc_aastore:
@ -245,7 +245,7 @@ public abstract class Opcodes implements RuntimeConstants {
value = -value; value = -value;
operation = Operator.NEG_OP; operation = Operator.NEG_OP;
} }
LocalInfo li = new LocalInfo(local); LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal return createNormal
(addr, 3, new IIncOperator (addr, 3, new IIncOperator
(li, Integer.toString(value), (li, Integer.toString(value),
@ -300,7 +300,8 @@ public abstract class Opcodes implements RuntimeConstants {
// return createReturn //XXX // return createReturn //XXX
// (addr, 2, // (addr, 2,
// new LocalLoadOperator // new LocalLoadOperator
// (OBJECT_TYPE, new LocalInfo(stream.readUnsignedByte()))); // (OBJECT_TYPE,
// ca.getLocalInfo(addr, stream.readUnsignedByte())));
case opc_tableswitch: { case opc_tableswitch: {
int length = 3-(addr % 4); int length = 3-(addr % 4);
stream.skip(length); stream.skip(length);
@ -457,7 +458,7 @@ public abstract class Opcodes implements RuntimeConstants {
(addr, 4, (addr, 4,
new LocalStoreOperator new LocalStoreOperator
(types[0][opcode-opc_istore], (types[0][opcode-opc_istore],
new LocalInfo(stream.readUnsignedShort()), ca.getLocalInfo(addr, stream.readUnsignedShort()),
Operator.ASSIGN_OP)); Operator.ASSIGN_OP));
case opc_iinc: { case opc_iinc: {
int local = stream.readUnsignedShort(); int local = stream.readUnsignedShort();
@ -467,7 +468,7 @@ public abstract class Opcodes implements RuntimeConstants {
value = -value; value = -value;
operation = Operator.NEG_OP; operation = Operator.NEG_OP;
} }
LocalInfo li = new LocalInfo(local); LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal return createNormal
(addr, 6, new IIncOperator (addr, 6, new IIncOperator
(li, Integer.toString(value), (li, Integer.toString(value),
@ -478,7 +479,7 @@ public abstract class Opcodes implements RuntimeConstants {
// (addr, 4, // (addr, 4,
// new LocalLoadOperator // new LocalLoadOperator
// (INT_TYPE, // (INT_TYPE,
// new LocalInfo(stream.readUnsignedShort()))); // ca.getLocalInfo(addr, stream.readUnsignedShort())));
default: default:
throw new ClassFormatError("Invalid wide opcode "+opcode); throw new ClassFormatError("Invalid wide opcode "+opcode);
} }

@ -42,6 +42,23 @@ public class CodeAnalyzer implements Analyzer, Constants {
void readCode() void readCode()
throws ClassFormatError throws ClassFormatError
{ {
BinaryAttribute attr = bincode.getAttributes();
while (attr != null) {
if (attr.getName() == Constants.idLocalVariableTable) {
DataInputStream stream =
new DataInputStream
(new ByteArrayInputStream(attr.getData()));
try {
lvt = new LocalVariableTable(bincode.getMaxLocals());
lvt.read(env, stream);
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
}
attr = attr.getNextAttribute();
}
byte[] code = bincode.getCode(); byte[] code = bincode.getCode();
FlowBlock[] instr = new FlowBlock[code.length]; FlowBlock[] instr = new FlowBlock[code.length];
int returnCount; int returnCount;
@ -59,14 +76,6 @@ public class CodeAnalyzer implements Analyzer, Constants {
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers(); BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
for (int addr=0; addr<instr.length; ) { for (int addr=0; addr<instr.length; ) {
instr[addr].resolveJumps(instr); instr[addr].resolveJumps(instr);
//XXX
// if (instr[addr].getBlock() instanceof ReturnBlock) {
// ReturnBlock block = (ReturnBlock) instr[addr].getBlock();
// if (block.getInstruction() == null) {
// EmptyBlock empty = new EmptyBlock(dummyReturn);
// empty.replace(block);
// }
// }
addr = instr[addr].getNextAddr(); addr = instr[addr].getNextAddr();
} }
methodHeader = instr[0]; methodHeader = instr[0];
@ -96,6 +105,13 @@ public class CodeAnalyzer implements Analyzer, Constants {
readCode(); readCode();
} }
public LocalInfo getLocalInfo(int addr, int slot) {
if (lvt != null)
return lvt.getLocal(slot).getInfo(addr);
else
return new LocalInfo(slot); /*XXX*/
}
static jode.flow.Transformation[] exprTrafos = { static jode.flow.Transformation[] exprTrafos = {
new jode.flow.RemoveEmpty(), new jode.flow.RemoveEmpty(),
// new CombineCatchLocal(), // new CombineCatchLocal(),
@ -126,7 +142,7 @@ public class CodeAnalyzer implements Analyzer, Constants {
i++; i++;
} }
if (flow.doT2()) { if (flow.doT2(todo)) {
/* T2 transformation succeeded. This may /* T2 transformation succeeded. This may
* make another T1 analysis in the previous * make another T1 analysis in the previous
* block possible. * block possible.

@ -37,6 +37,7 @@ public class LocalInfo {
private Identifier name; private Identifier name;
private Type type; private Type type;
private LocalInfo shadow; private LocalInfo shadow;
private jode.flow.StructuredBlock defining;
/* The current implementation may use very much stack. This /* The current implementation may use very much stack. This
* should be changed someday. * should be changed someday.
@ -85,7 +86,7 @@ public class LocalInfo {
while (shadow.shadow != null) { while (shadow.shadow != null) {
shadow = shadow.shadow; shadow = shadow.shadow;
} }
return shadow.getLocalInfo(); return shadow;
} }
return this; return this;
} }
@ -155,8 +156,24 @@ public class LocalInfo {
return this.type; return this.type;
} }
public jode.flow.StructuredBlock getDefining() {
return getLocalInfo().defining;
}
public void setDefining(jode.flow.StructuredBlock structuredBlock) {
getLocalInfo().defining = structuredBlock;
}
public boolean isShadow() { public boolean isShadow() {
return (shadow != null); return (shadow != null);
} }
}
public boolean equals(Object obj) {
return (obj instanceof LocalInfo
&& ((LocalInfo)obj).getLocalInfo() == getLocalInfo());
}
public String toString() {
return getName().toString();
}
}

@ -38,8 +38,8 @@ public class MethodAnalyzer implements Analyzer, Constants {
new BinaryCode(bytecode, new BinaryCode(bytecode,
env.getConstantPool(), env.getConstantPool(),
env); env);
lva = new LocalVariableAnalyzer(env, mdef, bc.getMaxLocals()); // lva = new LocalVariableAnalyzer(env, mdef, bc.getMaxLocals());
lva.read(bc); // lva.read(bc);
code = new CodeAnalyzer(this, bc, env); code = new CodeAnalyzer(this, bc, env);
} }
} }
@ -68,7 +68,7 @@ public class MethodAnalyzer implements Analyzer, Constants {
if (code != null) { if (code != null) {
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
System.err.print(mdef.getName().toString()+": "); System.err.print(mdef.getName().toString()+": ");
lva.createLocalInfo(code); // lva.createLocalInfo(code);
code.analyze(); code.analyze();
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
System.err.println(""); System.err.println("");
@ -96,7 +96,8 @@ public class MethodAnalyzer implements Analyzer, Constants {
((code == null)? ((code == null)?
env.getTypeString(paramTypes[i]): env.getTypeString(paramTypes[i]):
env.getTypeString env.getTypeString
(paramTypes[i], lva.getLocal(i+offset).getName())); (paramTypes[i],
code.getLocalInfo(-1, i+offset).getName()));
} }
writer.print(")"); writer.print(")");
} }
@ -115,7 +116,7 @@ public class MethodAnalyzer implements Analyzer, Constants {
if (code != null) { if (code != null) {
writer.println(" {"); writer.println(" {");
writer.tab(); writer.tab();
lva.dumpSource(writer); // lva.dumpSource(writer);
code.dumpSource(writer); code.dumpSource(writer);
writer.untab(); writer.untab();
writer.println("}"); writer.println("}");

@ -68,7 +68,7 @@ public class CombineIfGotoExpressions implements Transformation{
Expression cond = Expression cond =
new Expression(new BinaryOperator(MyType.tBoolean, operator), e); new Expression(new BinaryOperator(MyType.tBoolean, operator), e);
cb.setInstruction(cond); cb.setInstruction(cond);
cb.replace(cb.outer); cb.replace(cb.outer, cb);
return true; return true;
} }
} }

@ -24,13 +24,7 @@ import jode.TabbedPrintWriter;
* An ConditionalBlock is the structured block representing an if * An ConditionalBlock is the structured block representing an if
* instruction. The else part may be null. * instruction. The else part may be null.
*/ */
public class ConditionalBlock extends StructuredBlock public class ConditionalBlock extends InstructionContainer {
implements InstructionContainer {
/**
* The condition. Must be of boolean type.
*/
Instruction cond;
StructuredBlock trueBlock; StructuredBlock trueBlock;
@ -39,37 +33,15 @@ public class ConditionalBlock extends StructuredBlock
* be called shortly after the creation. * be called shortly after the creation.
*/ */
public ConditionalBlock(Instruction cond, Jump condJump, Jump elseJump) { public ConditionalBlock(Instruction cond, Jump condJump, Jump elseJump) {
this.cond = cond; super(cond, elseJump);
if (cond instanceof LocalVarOperator) { if (cond instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) cond; LocalVarOperator varOp = (LocalVarOperator) cond;
if (varOp.isRead()) { condJump.out.addElement(varOp.getLocalInfo());
in.addElement(varOp.getLocalInfo());
}
out.addElement(varOp.getLocalInfo());
} }
this.jump = elseJump;
elseJump.prev = this;
trueBlock = new EmptyBlock(condJump); trueBlock = new EmptyBlock(condJump);
trueBlock.outer = this; trueBlock.outer = this;
} }
public Instruction getInstruction() {
return cond;
}
/**
* Change the underlying instruction.
* @param instr the new underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.cond = instr;
}
public Instruction getCondition(Jump forJump) {
/*XXX*/
return cond;
}
/* The implementation of getNext[Flow]Block is the standard /* The implementation of getNext[Flow]Block is the standard
* implementation * implementation
*/ */
@ -105,7 +77,7 @@ public class ConditionalBlock extends StructuredBlock
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
writer.println("IF ("+cond.toString()+")"); writer.println("IF ("+instr.toString()+")");
writer.tab(); writer.tab();
trueBlock.dumpSource(writer); trueBlock.dumpSource(writer);
writer.untab(); writer.untab();

@ -44,19 +44,18 @@ public class CreateExpression implements Transformation {
int params; int params;
StructuredBlock block; StructuredBlock block;
// try {
try { // System.err.println("Transformation on: "+flow.getLabel());
System.err.println("Transformation on: "+flow.getLabel()); // flow.checkConsistent();
flow.checkConsistent(); // } catch (RuntimeException ex) {
} catch (RuntimeException ex) { // try {
try { // jode.TabbedPrintWriter writer =
jode.TabbedPrintWriter writer = // new jode.TabbedPrintWriter(System.err, " ");
new jode.TabbedPrintWriter(System.err, " "); // writer.tab();
writer.tab(); // flow.block.dumpSource(writer);
flow.block.dumpSource(writer); // } catch (java.io.IOException ioex) {
} catch (java.io.IOException ioex) { // }
} // }
}
try { try {
SequentialBlock sequBlock; SequentialBlock sequBlock;
@ -85,7 +84,7 @@ public class CreateExpression implements Transformation {
i++; i++;
SequentialBlock subExprBlock = SequentialBlock subExprBlock =
(SequentialBlock) sequBlock.getSubBlocks()[1]; (SequentialBlock) sequBlock.getSubBlocks()[1];
subExprBlock.replace(sequBlock); subExprBlock.replace(sequBlock, subExprBlock);
sequBlock = subExprBlock; sequBlock = subExprBlock;
((InstructionContainer)subExprBlock.getSubBlocks()[0]). ((InstructionContainer)subExprBlock.getSubBlocks()[0]).
setInstruction(e); setInstruction(e);
@ -101,9 +100,27 @@ public class CreateExpression implements Transformation {
if(jode.Decompiler.isVerbose && params > 0) if(jode.Decompiler.isVerbose && params > 0)
System.err.print("x"); System.err.print("x");
// try {
// System.err.println("replacing: ");
// jode.TabbedPrintWriter writer =
// new jode.TabbedPrintWriter(System.err, " ");
// writer.tab();
// block.dumpSource(writer);
// System.err.println("with: ");
// flow.lastModified.dumpSource(writer);
// } catch (java.io.IOException ioex) {
// }
((InstructionContainer) flow.lastModified).setInstruction ((InstructionContainer) flow.lastModified).setInstruction
(new Expression(op, exprs)); (new Expression(op, exprs));
flow.lastModified.replace(block); flow.lastModified.replace(block, flow.lastModified);
// try {
// System.err.println("result: ");
// jode.TabbedPrintWriter writer =
// new jode.TabbedPrintWriter(System.err, " ");
// writer.tab();
// flow.lastModified.dumpSource(writer);
// } catch (java.io.IOException ioex) {
// }
return true; return true;
} }
} }

@ -59,7 +59,7 @@ public class CreateNewConstructor implements Transformation{
i++; i++;
SequentialBlock subExprBlock = SequentialBlock subExprBlock =
(SequentialBlock) sequBlock.getSubBlocks()[1]; (SequentialBlock) sequBlock.getSubBlocks()[1];
subExprBlock.replace(sequBlock); subExprBlock.replace(sequBlock, subExprBlock);
sequBlock = subExprBlock; sequBlock = subExprBlock;
((InstructionContainer)subExprBlock.getSubBlocks()[0]). ((InstructionContainer)subExprBlock.getSubBlocks()[0]).
setInstruction(e); setInstruction(e);
@ -89,7 +89,7 @@ public class CreateNewConstructor implements Transformation{
constrCall.getField()), constrCall.getField()),
exprs)); exprs));
flow.lastModified.replace(sequBlock); flow.lastModified.replace(sequBlock, flow.lastModified);
return true; return true;
} }
} }

@ -40,6 +40,15 @@ public class FlowBlock {
END_OF_METHOD.label = "END_OF_METHOD"; END_OF_METHOD.label = "END_OF_METHOD";
} }
/**
* The in locals. This are the locals, which are used in this
* flow block and whose values may be the result of a assignment
* outside of this flow block. That means, that there is a
* path from the start of the flow block to the instruction that
* uses that variable, on which it is never assigned
*/
VariableSet in = new VariableSet();
/** /**
* The starting address of this flow block. This is mainly used * The starting address of this flow block. This is mainly used
* to produce the source code in code order. * to produce the source code in code order.
@ -88,6 +97,7 @@ public class FlowBlock {
predecessors = new Vector(); // filled in later predecessors = new Vector(); // filled in later
successors = new Vector(); successors = new Vector();
block.setFlowBlock(this); block.setFlowBlock(this);
block.fillInSet(in);
block.fillSuccessors(successors); block.fillSuccessors(successors);
} }
@ -164,7 +174,7 @@ public class FlowBlock {
IfThenElseBlock newIfBlock = IfThenElseBlock newIfBlock =
new IfThenElseBlock(((jode.Expression)instr).negate()); new IfThenElseBlock(((jode.Expression)instr).negate());
newIfBlock.replace(sequBlock); newIfBlock.replace(sequBlock, sequBlock.getSubBlocks()[1]);
newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]); newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]);
newIfBlock.moveJump(sequBlock); newIfBlock.moveJump(sequBlock);
@ -201,7 +211,7 @@ public class FlowBlock {
if (ifBlock.getSubBlocks().length == 1) { if (ifBlock.getSubBlocks().length == 1) {
elseBlock.outer.removeJump(); elseBlock.outer.removeJump();
ifBlock.replace(elseBlock.outer); ifBlock.replace(elseBlock.outer, elseBlock);
if (appendBlock == elseBlock.outer) if (appendBlock == elseBlock.outer)
appendBlock = ifBlock; appendBlock = ifBlock;
ifBlock.moveJump(jump.prev); ifBlock.moveJump(jump.prev);
@ -217,7 +227,7 @@ public class FlowBlock {
SequentialBlock sequBlock = new SequentialBlock(); SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.prev; StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump(); prevBlock.removeJump();
sequBlock.replace(prevBlock); sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock); sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ReturnBlock()); sequBlock.setSecond(new ReturnBlock());
continue next_jump; continue next_jump;
@ -254,7 +264,8 @@ public class FlowBlock {
else else
cb.outer.getSubBlocks()[1].moveJump(cb.outer); cb.outer.getSubBlocks()[1].moveJump(cb.outer);
} }
cb.outer.getSubBlocks()[1].replace(cb.outer); cb.outer.getSubBlocks()[1].replace
(cb.outer, cb.outer.getSubBlocks()[1]);
/* cb and cb.outer are not used any more */ /* cb and cb.outer are not used any more */
/* Note that cb.outer != appendBlock because /* Note that cb.outer != appendBlock because
* appendBlock contains loopBlock * appendBlock contains loopBlock
@ -277,7 +288,7 @@ public class FlowBlock {
loopBlock.setCondition(((Expression)instr).negate()); loopBlock.setCondition(((Expression)instr).negate());
EmptyBlock empty = new EmptyBlock(); EmptyBlock empty = new EmptyBlock();
empty.replace(cb); empty.replace(cb, null);
/* cb is not used any more */ /* cb is not used any more */
continue next_jump; continue next_jump;
} }
@ -309,7 +320,7 @@ public class FlowBlock {
else else
prevBlock.removeJump(); prevBlock.removeJump();
sequBlock.replace(prevBlock); sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock); sequBlock.setFirst(prevBlock);
sequBlock.setSecond sequBlock.setSecond
(new BreakBlock((BreakableBlock) surrounder, (new BreakBlock((BreakableBlock) surrounder,
@ -330,8 +341,9 @@ public class FlowBlock {
* successing flow block simultanous to a T1 transformation. * successing flow block simultanous to a T1 transformation.
* @param successor The flow block which is unified with this flow * @param successor The flow block which is unified with this flow
* block. * block.
* @return The variables that must be defined in this block.
*/ */
void updateInOut (FlowBlock successor, boolean t1Transformation) { VariableSet updateInOut (FlowBlock successor, boolean t1Transformation) {
/* First get the out vectors of all jumps to successor and /* First get the out vectors of all jumps to successor and
* calculate the intersection. * calculate the intersection.
*/ */
@ -343,33 +355,39 @@ public class FlowBlock {
if (jump == null || jump.destination != successor) if (jump == null || jump.destination != successor)
continue; continue;
allOuts.union(jump.prev.out); allOuts.union(jump.out);
if (intersectOut == null) if (intersectOut == null)
intersectOut = jump.prev.out; intersectOut = jump.out;
else else
intersectOut = intersectOut.intersect(jump.prev.out); intersectOut = intersectOut.intersect(jump.out);
} }
/* Now work on each block of the successor */
Stack todo = new Stack();
todo.push(successor.block);
while (!todo.empty()) {
StructuredBlock block = (StructuredBlock) todo.pop();
StructuredBlock[] subBlocks = block.getSubBlocks();
for (int i=0; i<subBlocks.length; i++)
todo.push(subBlocks[i]);
/* Merge the locals used in successing block with those written
* by this blocks
*/
block.in.merge(allOuts);
if (t1Transformation) { System.err.println("UpdateInOut: allOuts : "+allOuts);
/* Now update in and out set of successing block */ System.err.println(" intersectOut: "+intersectOut);
block.in.subtract(intersectOut);
block.out.add(intersectOut); /* Merge the locals used in successing block with those written
* by this blocks
*/
VariableSet defineHere = successor.in.merge(allOuts);
defineHere.subtractIdentical(in);
System.err.println(" defineHere : "+defineHere);
if (t1Transformation) {
/* Now update in and out set of successing block */
successor.in.subtract(intersectOut);
/* The out set must be updated for every jump in the block */
enum = successor.successors.elements();
while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement();
if (jump != null)
jump.out.add(intersectOut);
} }
} }
System.err.println(" successor.in: "+successor.in);
in.union(successor.in);
System.err.println(" in : "+in);
/* XXX - do something with defineHere */
return defineHere; /*XXX - correct???*/
} }
@ -518,8 +536,10 @@ public class FlowBlock {
try{ try{
System.err.println("doing T1 analysis on: "+getLabel()); System.err.println("doing T1 analysis on: "+getLabel());
System.err.println("***in: "+in);
checkConsistent(); checkConsistent();
System.err.println("and "+succ.getLabel()); System.err.println("and "+succ.getLabel());
System.err.println("+++in: "+succ.in);
succ.checkConsistent(); succ.checkConsistent();
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
try { try {
@ -550,8 +570,7 @@ public class FlowBlock {
} }
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
updateInOut(succ, true); VariableSet defineHere = updateInOut(succ, true);
/* The switch "fall through" case: if the appendBlock is a /* The switch "fall through" case: if the appendBlock is a
* switch, and the successor is the address of a case, and all * switch, and the successor is the address of a case, and all
@ -573,6 +592,7 @@ public class FlowBlock {
/* Do the following modifications on the struct block. */ /* Do the following modifications on the struct block. */
appendBlock = precedingcase; appendBlock = precedingcase;
succ.block.setFlowBlock(this); succ.block.setFlowBlock(this);
switchBlock.define(defineHere);
} else { } else {
@ -595,10 +615,11 @@ public class FlowBlock {
*/ */
SequentialBlock sequBlock = SequentialBlock sequBlock =
new SequentialBlock(); new SequentialBlock();
sequBlock.replace(appendBlock); sequBlock.replace(appendBlock, appendBlock);
sequBlock.setFirst(appendBlock); sequBlock.setFirst(appendBlock);
sequBlock.setSecond(succ.block); sequBlock.setSecond(succ.block);
succ.block.setFlowBlock(this); succ.block.setFlowBlock(this);
sequBlock.define(defineHere);
} }
/* Merge the sucessors from the successing flow block /* Merge the sucessors from the successing flow block
@ -683,13 +704,13 @@ public class FlowBlock {
StructuredBlock prevBlock = jump.prev; StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump(); prevBlock.removeJump();
sequBlock.replace(prevBlock); sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock); sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1)); sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1));
} }
if (doWhileFalse != null) { if (doWhileFalse != null) {
doWhileFalse.replace(appendBlock); doWhileFalse.replace(appendBlock, appendBlock);
doWhileFalse.setBody(appendBlock); doWhileFalse.setBody(appendBlock);
} }
@ -714,6 +735,7 @@ public class FlowBlock {
/* T1 transformation succeeded */ /* T1 transformation succeeded */
try { try {
System.err.println("T1 succeeded:"); System.err.println("T1 succeeded:");
System.err.println("===in: "+in);
checkConsistent(); checkConsistent();
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
try { try {
@ -727,7 +749,7 @@ public class FlowBlock {
return true; return true;
} }
public boolean doT2() { public boolean doT2(Vector triedBlocks) {
/* If there are no jumps to the beginning of this flow block /* If there are no jumps to the beginning of this flow block
* or if this block has other predecessors with a higher * or if this block has other predecessors with a higher
* address, return false. The second condition make sure that * address, return false. The second condition make sure that
@ -738,7 +760,8 @@ public class FlowBlock {
Enumeration preds = predecessors.elements(); Enumeration preds = predecessors.elements();
while (preds.hasMoreElements()) { while (preds.hasMoreElements()) {
FlowBlock predFlow = (FlowBlock) preds.nextElement(); FlowBlock predFlow = (FlowBlock) preds.nextElement();
if (predFlow != null && predFlow.addr > addr) { if (predFlow != null && predFlow != this
&& !triedBlocks.contains(predFlow)) {
System.err.println("refusing T2 on: "+getLabel()+ System.err.println("refusing T2 on: "+getLabel()+
" because of "+predFlow.getLabel()); " because of "+predFlow.getLabel());
/* XXX Is this enough to refuse T2 trafo ??? */ /* XXX Is this enough to refuse T2 trafo ??? */
@ -760,7 +783,7 @@ public class FlowBlock {
} }
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
updateInOut(this, false); VariableSet defineHere = updateInOut(this, false);
/* If there is only one jump to the beginning and it is the /* If there is only one jump to the beginning and it is the
* last jump and (there is a do/while(0) block surrounding * last jump and (there is a do/while(0) block surrounding
@ -789,8 +812,9 @@ public class FlowBlock {
LoopBlock whileBlock = LoopBlock whileBlock =
new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE); new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE);
whileBlock.replace(bodyBlock); whileBlock.replace(bodyBlock, bodyBlock);
whileBlock.setBody(bodyBlock); whileBlock.setBody(bodyBlock);
whileBlock.define(defineHere);
/* Try to eliminate as many jumps as possible. /* Try to eliminate as many jumps as possible.
*/ */
@ -825,7 +849,7 @@ public class FlowBlock {
StructuredBlock prevBlock = jump.prev; StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump(); prevBlock.removeJump();
sequBlock.replace(prevBlock); sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock); sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ContinueBlock(whileBlock, sequBlock.setSecond(new ContinueBlock(whileBlock,
continuelevel > 1)); continuelevel > 1));
@ -899,6 +923,17 @@ public class FlowBlock {
writer.println(label+":"); writer.println(label+":");
writer.tab(); writer.tab();
} }
if (jode.Decompiler.isDebugging) {
writer.print("in: ");
java.util.Enumeration enum = in.elements();
while(enum.hasMoreElements()) {
writer.print(((jode.LocalInfo)enum.nextElement()).getName()
+ " ");
}
writer.println("");
}
block.dumpSource(writer); block.dumpSource(writer);
FlowBlock succ = getSuccessor(); FlowBlock succ = getSuccessor();
if (succ != null) if (succ != null)

@ -21,40 +21,14 @@ import jode.*;
/** /**
* This is the structured block for atomic instructions. * This is the structured block for atomic instructions.
*/ */
public class InstructionBlock extends StructuredBlock public class InstructionBlock extends InstructionContainer {
implements InstructionContainer {
Instruction instr;
public InstructionBlock(Instruction instr) { public InstructionBlock(Instruction instr) {
this.instr = instr; super(instr);
if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr;
if (varOp.isRead()) {
in.addElement(varOp.getLocalInfo());
}
out.addElement(varOp.getLocalInfo());
}
} }
public InstructionBlock(Instruction instr, Jump jump) { public InstructionBlock(Instruction instr, Jump jump) {
this(instr); super(instr, jump);
setJump(jump);
}
/**
* Get the underlying instruction.
* @return the underlying instruction.
*/
public Instruction getInstruction() {
return instr;
}
/**
* Change the underlying instruction.
* @param instr the new underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.instr = instr;
} }
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)

@ -16,19 +16,54 @@
* $Id$ * $Id$
*/ */
package jode.flow; package jode.flow;
import jode.Instruction;
import jode.LocalVarOperator;
/** /**
* This is a method for block containing a single instruction. * This is a method for block containing a single instruction.
*/ */
public interface InstructionContainer { public abstract class InstructionContainer extends StructuredBlock {
Instruction instr;
public InstructionContainer(Instruction instr) {
this.instr = instr;
}
public InstructionContainer(Instruction instr, Jump jump) {
this.instr = instr;
if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr;
jump.out.addElement(varOp.getLocalInfo());
}
setJump(jump);
}
/**
* Fill all in variables into the given VariableSet.
* @param in The VariableSet, the in variables should be stored to.
*/
public void fillInSet(VariableSet in) {
if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr;
if (varOp.isRead()) {
in.addElement(varOp.getLocalInfo());
}
}
}
/** /**
* Get the contained instruction. * Get the contained instruction.
* @return the contained instruction. * @return the contained instruction.
*/ */
public jode.Instruction getInstruction(); public Instruction getInstruction() {
return instr;
}
/** /**
* Set the contained instruction. * Set the contained instruction.
* @param instr the new instruction. * @param instr the new instruction.
*/ */
public void setInstruction(jode.Instruction instr); public void setInstruction(Instruction instr) {
this.instr = instr;
}
} }

@ -35,6 +35,14 @@ public class Jump {
*/ */
int destAddr; int destAddr;
/**
* The out locals. This are the locals, which must be overwritten
* in this block on every path to this jump. That means, that all
* paths form the start of the current flow block to this jump
* contain (unconditional) assignments to this local.
*/
VariableSet out = new VariableSet();
public Jump (int destAddr) { public Jump (int destAddr) {
this.destAddr = destAddr; this.destAddr = destAddr;
} }
@ -56,4 +64,24 @@ public class Jump {
String describeAttachments() { String describeAttachments() {
return ""; return "";
} }
/**
* Print the source code for this structured block. This handles
* everything that is unique for all structured blocks and calls
* dumpInstruction afterwards.
* @param writer The tabbed print writer, where we print to.
*/
public void dumpSource(jode.TabbedPrintWriter writer)
throws java.io.IOException
{
if (jode.Decompiler.isDebugging) {
writer.println("out: "+ out.toString());
}
writer.println("Attachments: "+describeAttachments());
if (destination == null)
writer.println ("GOTO null-ptr!!!!!");
else
writer.println("GOTO "+destination.getLabel());
}
} }

@ -52,7 +52,7 @@ public class RemoveEmpty implements Transformation {
return false; return false;
} }
((InstructionContainer)block).setInstruction(instr); ((InstructionContainer)block).setInstruction(instr);
block.replace(sequBlock); block.replace(sequBlock, block);
flow.lastModified = block; flow.lastModified = block;
return true; return true;
} }
@ -64,7 +64,7 @@ public class RemoveEmpty implements Transformation {
lastBlock.outer.getSubBlocks()[1] == lastBlock) { lastBlock.outer.getSubBlocks()[1] == lastBlock) {
StructuredBlock block = lastBlock.outer.getSubBlocks()[0]; StructuredBlock block = lastBlock.outer.getSubBlocks()[0];
block.replace(block.outer); block.replace(block.outer, block);
if (block.jump == null) if (block.jump == null)
block.moveJump(lastBlock); block.moveJump(lastBlock);
else else
@ -76,7 +76,7 @@ public class RemoveEmpty implements Transformation {
lastBlock.outer.getSubBlocks()[0] instanceof EmptyBlock && lastBlock.outer.getSubBlocks()[0] instanceof EmptyBlock &&
lastBlock.outer.getSubBlocks()[0].jump == null) { lastBlock.outer.getSubBlocks()[0].jump == null) {
lastBlock.replace(lastBlock.outer); lastBlock.replace(lastBlock.outer, lastBlock);
flow.lastModified = lastBlock; flow.lastModified = lastBlock;
return true; return true;
} }

@ -24,13 +24,29 @@ import jode.Instruction;
/** /**
* This is the structured block for an Return block. * This is the structured block for an Return block.
*/ */
public class ReturnBlock extends StructuredBlock { public class ReturnBlock extends InstructionContainer {
Instruction instr = null;
public ReturnBlock() { public ReturnBlock() {
super(null);
} }
public ReturnBlock(Instruction instr) { public ReturnBlock(Instruction instr) {
super(instr);
}
/**
* Get the underlying instruction.
* @return the underlying instruction.
*/
public Instruction getInstruction() {
return instr;
}
/**
* Change the underlying instruction.
* @param instr the new underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.instr = instr; this.instr = instr;
} }

@ -19,6 +19,7 @@
package jode.flow; package jode.flow;
import jode.TabbedPrintWriter; import jode.TabbedPrintWriter;
import jode.LocalInfo;
/** /**
* A structured block is the building block of the source programm. * A structured block is the building block of the source programm.
@ -59,24 +60,6 @@ public abstract class StructuredBlock {
* or outer.getNextFlowBlock(this) != null * or outer.getNextFlowBlock(this) != null
*/ */
/**
* The in locals. This are the locals, which are used in this
* block and whose values may be the result of a assignment
* outside of the whole flow block. That means, that there is a
* path from the start of the current flow block, on which the
* local variable is never assigned
*/
VariableSet in = new VariableSet();
/**
* The out locals. This are the locals, which must be overwritten
* until the end of this block. That means, that all paths form
* the start of the current flow block to the end of this
* structured block contain a (unconditional) assignment to this
* local
*/
VariableSet out = new VariableSet();
/** /**
* The variable set containing all variables that must be defined * The variable set containing all variables that must be defined
* in this block (or maybe an outer block, this changes as the * in this block (or maybe an outer block, this changes as the
@ -205,16 +188,48 @@ public abstract class StructuredBlock {
} }
} }
/**
* This will move the definitions of sb and childs to this block,
* but only descend to sub and not further. It is assumed that
* sub will become a sub block of this block, but may not yet.
*
* @param sb The structured block that should be replaced.
* @param sub The uppermost sub block of structured block, that
* will be moved to this block (may be this).
*/
void moveDefinitions(StructuredBlock from, StructuredBlock sub) {
if (from != sub && from != this) {
/* define(...) will not move from blocks, that are not sub blocks,
* so we do it by hand.
*/
java.util.Enumeration enum = from.defineHere.elements();
while (enum.hasMoreElements()) {
LocalInfo var =
((LocalInfo) enum.nextElement()).getLocalInfo();
defineHere.addElement(var);
var.setDefining(this);
}
from.defineHere.removeAllElements();
StructuredBlock[] subs = from.getSubBlocks();
for (int i=0; i<subs.length; i++)
moveDefinitions(subs[i], sub);
}
}
/** /**
* This function replaces sb with this block. It copies outer and * This function replaces sb with this block. It copies outer and
* from sb, and updates the outer block, so it knows that sb was * from sb, and updates the outer block, so it knows that sb was
* replaced. You have to replace sb.outer or mustn't use sb * replaced. You have to replace sb.outer or mustn't use sb
* anymore. * anymore. <p>
* @param sb The structured block that should be replaced. */ * It will also move the definitions of sb and childs to this block,
public void replace(StructuredBlock sb) { * but only descend to sub and not further. It is assumed that
in = sb.in; * sub will become a sub block of this block.
out = sb.out; * @param sb The structured block that should be replaced.
defineHere = sb.defineHere; * @param sub The uppermost sub block of structured block,
* that will be moved to this block (may be this).
*/
public void replace(StructuredBlock sb, StructuredBlock sub) {
moveDefinitions(sb, sub);
outer = sb.outer; outer = sb.outer;
flowBlock = sb.flowBlock; flowBlock = sb.flowBlock;
@ -247,6 +262,21 @@ public abstract class StructuredBlock {
return false; return false;
} }
public void define(VariableSet vars) {
java.util.Enumeration enum = vars.elements();
while (enum.hasMoreElements()) {
LocalInfo var = ((LocalInfo) enum.nextElement()).getLocalInfo();
StructuredBlock previous = var.getDefining();
if (previous != null) {
if (previous == this || !contains(previous))
continue;
previous.defineHere.removeElement(var);
}
defineHere.addElement(var);
var.setDefining(this);
}
}
public void checkConsistent() { public void checkConsistent() {
StructuredBlock[] subs = getSubBlocks(); StructuredBlock[] subs = getSubBlocks();
for (int i=0; i<subs.length; i++) { for (int i=0; i<subs.length; i++) {
@ -278,6 +308,14 @@ public abstract class StructuredBlock {
} }
} }
/**
* Fill all in variables into the given VariableSet.
* @param in The VariableSet, the in variables should be stored to.
*/
public void fillInSet(VariableSet in) {
/* overwritten by InstructionContainer */
}
/** /**
* Put all the successors of this block and all subblocks into * Put all the successors of this block and all subblocks into
* the given vector. * the given vector.
@ -298,22 +336,17 @@ public abstract class StructuredBlock {
* dumpInstruction afterwards. * dumpInstruction afterwards.
* @param writer The tabbed print writer, where we print to. * @param writer The tabbed print writer, where we print to.
*/ */
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(jode.TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
// if (!defineHere.isEmpty())
writer.println("defining: "+defineHere);
/* XXX declare variables needed in this block */ /* XXX declare variables needed in this block */
dumpInstruction(writer); dumpInstruction(writer);
if (jump != null) {
if (jump.destination == null)
writer.println ("GOTO null-ptr!!!!!");
else {
writer.println("GOTO "+jump.destination.getLabel());
if (jump.prev != this)
writer.println("GOTO has wrong prev");
}
}
}
if (jump != null)
jump.dumpSource(writer);
}
/** /**
* Print the instruction expressing this structured block. * Print the instruction expressing this structured block.

@ -48,18 +48,25 @@ public class VariableSet extends java.util.Vector {
* Merges the current VariableSet with another. For all slots occuring * Merges the current VariableSet with another. For all slots occuring
* in both variable sets, all corresponding LocalInfos are merged. * in both variable sets, all corresponding LocalInfos are merged.
* The variable sets are not changed (use union for this). * The variable sets are not changed (use union for this).
* @return The merged variables.
* @param vs the other variable set. * @param vs the other variable set.
*/ */
public void merge(VariableSet vs) { public VariableSet merge(VariableSet vs) {
VariableSet merged = new VariableSet();
for (int i=0; i<elementCount; i++) { for (int i=0; i<elementCount; i++) {
LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo(); LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo();
boolean didMerge = false;
for (int j=0; j<vs.elementCount; j++) { for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo(); LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo();
if (li1.getSlot() == li2.getSlot()) { if (li1.getSlot() == li2.getSlot()) {
li1.combineWith(li2); li1.combineWith(li2);
didMerge = true;
} }
} }
if (didMerge)
merged.addElement(li1);
} }
return merged;
} }
/** /**
@ -124,7 +131,7 @@ public class VariableSet extends java.util.Vector {
} }
/** /**
* Substract the other variable set from this one. This removes * Subtract the other variable set from this one. This removes
* every variable from this set, that uses a slot in the other * every variable from this set, that uses a slot in the other
* variable set. * variable set.
* @param vs The other variable set. * @param vs The other variable set.
@ -150,6 +157,34 @@ public class VariableSet extends java.util.Vector {
/* Now set the new size */ /* Now set the new size */
setSize(newCount); setSize(newCount);
} }
/**
* Subtract the other variable set from this one. This removes
* every variable from this set, that is in the other
* variable set.
* @param vs The other variable set.
*/
public void subtractIdentical(VariableSet vs) {
/* We count from top to bottom to have easier reorganization.
* Note, that the variables have not to be in any particular
* order. */
int newCount = elementCount;
for (int i=newCount-1; i>=0; i--) {
LocalInfo li1 = (LocalInfo) elementData[i];
for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = (LocalInfo) vs.elementData[j];
if (li1.getLocalInfo() == li2.getLocalInfo()) {
/* remove the element from this variable list. */
newCount--;
elementData[i] = elementData[newCount];
/* break the j-loop */
break;
}
}
}
/* Now set the new size */
setSize(newCount);
}
} }

Loading…
Cancel
Save