*** 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
(addr, 2, new LocalLoadOperator
(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_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:
@ -165,7 +165,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal
(addr, 1, new LocalLoadOperator
(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_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
@ -177,7 +177,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal
(addr, 2, new LocalStoreOperator
(types[0][opcode-opc_istore],
new LocalInfo(stream.readUnsignedByte()),
ca.getLocalInfo(addr, stream.readUnsignedByte()),
Operator.ASSIGN_OP));
case opc_istore_0: case opc_istore_1:
case opc_istore_2: case opc_istore_3:
@ -192,7 +192,7 @@ public abstract class Opcodes implements RuntimeConstants {
return createNormal
(addr, 1, new LocalStoreOperator
(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));
case opc_iastore: case opc_lastore:
case opc_fastore: case opc_dastore: case opc_aastore:
@ -245,7 +245,7 @@ public abstract class Opcodes implements RuntimeConstants {
value = -value;
operation = Operator.NEG_OP;
}
LocalInfo li = new LocalInfo(local);
LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal
(addr, 3, new IIncOperator
(li, Integer.toString(value),
@ -300,7 +300,8 @@ public abstract class Opcodes implements RuntimeConstants {
// return createReturn //XXX
// (addr, 2,
// new LocalLoadOperator
// (OBJECT_TYPE, new LocalInfo(stream.readUnsignedByte())));
// (OBJECT_TYPE,
// ca.getLocalInfo(addr, stream.readUnsignedByte())));
case opc_tableswitch: {
int length = 3-(addr % 4);
stream.skip(length);
@ -457,7 +458,7 @@ public abstract class Opcodes implements RuntimeConstants {
(addr, 4,
new LocalStoreOperator
(types[0][opcode-opc_istore],
new LocalInfo(stream.readUnsignedShort()),
ca.getLocalInfo(addr, stream.readUnsignedShort()),
Operator.ASSIGN_OP));
case opc_iinc: {
int local = stream.readUnsignedShort();
@ -467,7 +468,7 @@ public abstract class Opcodes implements RuntimeConstants {
value = -value;
operation = Operator.NEG_OP;
}
LocalInfo li = new LocalInfo(local);
LocalInfo li = ca.getLocalInfo(addr, local);
return createNormal
(addr, 6, new IIncOperator
(li, Integer.toString(value),
@ -478,7 +479,7 @@ public abstract class Opcodes implements RuntimeConstants {
// (addr, 4,
// new LocalLoadOperator
// (INT_TYPE,
// new LocalInfo(stream.readUnsignedShort())));
// ca.getLocalInfo(addr, stream.readUnsignedShort())));
default:
throw new ClassFormatError("Invalid wide opcode "+opcode);
}

@ -42,6 +42,23 @@ public class CodeAnalyzer implements Analyzer, Constants {
void readCode()
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();
FlowBlock[] instr = new FlowBlock[code.length];
int returnCount;
@ -59,14 +76,6 @@ public class CodeAnalyzer implements Analyzer, Constants {
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
for (int addr=0; addr<instr.length; ) {
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();
}
methodHeader = instr[0];
@ -96,6 +105,13 @@ public class CodeAnalyzer implements Analyzer, Constants {
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 = {
new jode.flow.RemoveEmpty(),
// new CombineCatchLocal(),
@ -126,7 +142,7 @@ public class CodeAnalyzer implements Analyzer, Constants {
i++;
}
if (flow.doT2()) {
if (flow.doT2(todo)) {
/* T2 transformation succeeded. This may
* make another T1 analysis in the previous
* block possible.

@ -37,6 +37,7 @@ public class LocalInfo {
private Identifier name;
private Type type;
private LocalInfo shadow;
private jode.flow.StructuredBlock defining;
/* The current implementation may use very much stack. This
* should be changed someday.
@ -85,7 +86,7 @@ public class LocalInfo {
while (shadow.shadow != null) {
shadow = shadow.shadow;
}
return shadow.getLocalInfo();
return shadow;
}
return this;
}
@ -155,8 +156,24 @@ public class LocalInfo {
return this.type;
}
public jode.flow.StructuredBlock getDefining() {
return getLocalInfo().defining;
}
public void setDefining(jode.flow.StructuredBlock structuredBlock) {
getLocalInfo().defining = structuredBlock;
}
public boolean isShadow() {
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,
env.getConstantPool(),
env);
lva = new LocalVariableAnalyzer(env, mdef, bc.getMaxLocals());
lva.read(bc);
// lva = new LocalVariableAnalyzer(env, mdef, bc.getMaxLocals());
// lva.read(bc);
code = new CodeAnalyzer(this, bc, env);
}
}
@ -68,7 +68,7 @@ public class MethodAnalyzer implements Analyzer, Constants {
if (code != null) {
if (Decompiler.isVerbose)
System.err.print(mdef.getName().toString()+": ");
lva.createLocalInfo(code);
// lva.createLocalInfo(code);
code.analyze();
if (Decompiler.isVerbose)
System.err.println("");
@ -96,7 +96,8 @@ public class MethodAnalyzer implements Analyzer, Constants {
((code == null)?
env.getTypeString(paramTypes[i]):
env.getTypeString
(paramTypes[i], lva.getLocal(i+offset).getName()));
(paramTypes[i],
code.getLocalInfo(-1, i+offset).getName()));
}
writer.print(")");
}
@ -115,7 +116,7 @@ public class MethodAnalyzer implements Analyzer, Constants {
if (code != null) {
writer.println(" {");
writer.tab();
lva.dumpSource(writer);
// lva.dumpSource(writer);
code.dumpSource(writer);
writer.untab();
writer.println("}");

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

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

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

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

@ -40,6 +40,15 @@ public class FlowBlock {
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
* to produce the source code in code order.
@ -88,6 +97,7 @@ public class FlowBlock {
predecessors = new Vector(); // filled in later
successors = new Vector();
block.setFlowBlock(this);
block.fillInSet(in);
block.fillSuccessors(successors);
}
@ -164,7 +174,7 @@ public class FlowBlock {
IfThenElseBlock newIfBlock =
new IfThenElseBlock(((jode.Expression)instr).negate());
newIfBlock.replace(sequBlock);
newIfBlock.replace(sequBlock, sequBlock.getSubBlocks()[1]);
newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]);
newIfBlock.moveJump(sequBlock);
@ -201,7 +211,7 @@ public class FlowBlock {
if (ifBlock.getSubBlocks().length == 1) {
elseBlock.outer.removeJump();
ifBlock.replace(elseBlock.outer);
ifBlock.replace(elseBlock.outer, elseBlock);
if (appendBlock == elseBlock.outer)
appendBlock = ifBlock;
ifBlock.moveJump(jump.prev);
@ -217,7 +227,7 @@ public class FlowBlock {
SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ReturnBlock());
continue next_jump;
@ -254,7 +264,8 @@ public class FlowBlock {
else
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 */
/* Note that cb.outer != appendBlock because
* appendBlock contains loopBlock
@ -277,7 +288,7 @@ public class FlowBlock {
loopBlock.setCondition(((Expression)instr).negate());
EmptyBlock empty = new EmptyBlock();
empty.replace(cb);
empty.replace(cb, null);
/* cb is not used any more */
continue next_jump;
}
@ -309,7 +320,7 @@ public class FlowBlock {
else
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond
(new BreakBlock((BreakableBlock) surrounder,
@ -330,8 +341,9 @@ public class FlowBlock {
* successing flow block simultanous to a T1 transformation.
* @param successor The flow block which is unified with this flow
* 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
* calculate the intersection.
*/
@ -343,33 +355,39 @@ public class FlowBlock {
if (jump == null || jump.destination != successor)
continue;
allOuts.union(jump.prev.out);
allOuts.union(jump.out);
if (intersectOut == null)
intersectOut = jump.prev.out;
intersectOut = jump.out;
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) {
/* Now update in and out set of successing block */
block.in.subtract(intersectOut);
block.out.add(intersectOut);
System.err.println("UpdateInOut: allOuts : "+allOuts);
System.err.println(" intersectOut: "+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{
System.err.println("doing T1 analysis on: "+getLabel());
System.err.println("***in: "+in);
checkConsistent();
System.err.println("and "+succ.getLabel());
System.err.println("+++in: "+succ.in);
succ.checkConsistent();
} catch (RuntimeException ex) {
try {
@ -550,8 +570,7 @@ public class FlowBlock {
}
/* Update the in/out-Vectors now */
updateInOut(succ, true);
VariableSet defineHere = updateInOut(succ, true);
/* The switch "fall through" case: if the appendBlock is a
* 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. */
appendBlock = precedingcase;
succ.block.setFlowBlock(this);
switchBlock.define(defineHere);
} else {
@ -595,10 +615,11 @@ public class FlowBlock {
*/
SequentialBlock sequBlock =
new SequentialBlock();
sequBlock.replace(appendBlock);
sequBlock.replace(appendBlock, appendBlock);
sequBlock.setFirst(appendBlock);
sequBlock.setSecond(succ.block);
succ.block.setFlowBlock(this);
sequBlock.define(defineHere);
}
/* Merge the sucessors from the successing flow block
@ -683,13 +704,13 @@ public class FlowBlock {
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1));
}
if (doWhileFalse != null) {
doWhileFalse.replace(appendBlock);
doWhileFalse.replace(appendBlock, appendBlock);
doWhileFalse.setBody(appendBlock);
}
@ -714,6 +735,7 @@ public class FlowBlock {
/* T1 transformation succeeded */
try {
System.err.println("T1 succeeded:");
System.err.println("===in: "+in);
checkConsistent();
} catch (RuntimeException ex) {
try {
@ -727,7 +749,7 @@ public class FlowBlock {
return true;
}
public boolean doT2() {
public boolean doT2(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
@ -738,7 +760,8 @@ public class FlowBlock {
Enumeration preds = predecessors.elements();
while (preds.hasMoreElements()) {
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()+
" because of "+predFlow.getLabel());
/* XXX Is this enough to refuse T2 trafo ??? */
@ -760,7 +783,7 @@ public class FlowBlock {
}
/* 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
* last jump and (there is a do/while(0) block surrounding
@ -789,8 +812,9 @@ public class FlowBlock {
LoopBlock whileBlock =
new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE);
whileBlock.replace(bodyBlock);
whileBlock.replace(bodyBlock, bodyBlock);
whileBlock.setBody(bodyBlock);
whileBlock.define(defineHere);
/* Try to eliminate as many jumps as possible.
*/
@ -825,7 +849,7 @@ public class FlowBlock {
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
sequBlock.replace(prevBlock);
sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ContinueBlock(whileBlock,
continuelevel > 1));
@ -899,6 +923,17 @@ public class FlowBlock {
writer.println(label+":");
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);
FlowBlock succ = getSuccessor();
if (succ != null)

@ -21,40 +21,14 @@ import jode.*;
/**
* This is the structured block for atomic instructions.
*/
public class InstructionBlock extends StructuredBlock
implements InstructionContainer {
Instruction instr;
public class InstructionBlock extends InstructionContainer {
public InstructionBlock(Instruction instr) {
this.instr = instr;
if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr;
if (varOp.isRead()) {
in.addElement(varOp.getLocalInfo());
}
out.addElement(varOp.getLocalInfo());
}
super(instr);
}
public InstructionBlock(Instruction instr, Jump jump) {
this(instr);
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;
super(instr, jump);
}
public void dumpInstruction(TabbedPrintWriter writer)

@ -16,19 +16,54 @@
* $Id$
*/
package jode.flow;
import jode.Instruction;
import jode.LocalVarOperator;
/**
* 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.
* @return the contained instruction.
*/
public jode.Instruction getInstruction();
public Instruction getInstruction() {
return instr;
}
/**
* Set the contained 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;
/**
* 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) {
this.destAddr = destAddr;
}
@ -56,4 +64,24 @@ public class Jump {
String describeAttachments() {
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;
}
((InstructionContainer)block).setInstruction(instr);
block.replace(sequBlock);
block.replace(sequBlock, block);
flow.lastModified = block;
return true;
}
@ -64,7 +64,7 @@ public class RemoveEmpty implements Transformation {
lastBlock.outer.getSubBlocks()[1] == lastBlock) {
StructuredBlock block = lastBlock.outer.getSubBlocks()[0];
block.replace(block.outer);
block.replace(block.outer, block);
if (block.jump == null)
block.moveJump(lastBlock);
else
@ -76,7 +76,7 @@ public class RemoveEmpty implements Transformation {
lastBlock.outer.getSubBlocks()[0] instanceof EmptyBlock &&
lastBlock.outer.getSubBlocks()[0].jump == null) {
lastBlock.replace(lastBlock.outer);
lastBlock.replace(lastBlock.outer, lastBlock);
flow.lastModified = lastBlock;
return true;
}

@ -24,13 +24,29 @@ import jode.Instruction;
/**
* This is the structured block for an Return block.
*/
public class ReturnBlock extends StructuredBlock {
Instruction instr = null;
public class ReturnBlock extends InstructionContainer {
public ReturnBlock() {
super(null);
}
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;
}

@ -19,6 +19,7 @@
package jode.flow;
import jode.TabbedPrintWriter;
import jode.LocalInfo;
/**
* A structured block is the building block of the source programm.
@ -59,24 +60,6 @@ public abstract class StructuredBlock {
* 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
* 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
* 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
* anymore.
* @param sb The structured block that should be replaced. */
public void replace(StructuredBlock sb) {
in = sb.in;
out = sb.out;
defineHere = sb.defineHere;
* anymore. <p>
* It will also 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.
* @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).
*/
public void replace(StructuredBlock sb, StructuredBlock sub) {
moveDefinitions(sb, sub);
outer = sb.outer;
flowBlock = sb.flowBlock;
@ -247,6 +262,21 @@ public abstract class StructuredBlock {
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() {
StructuredBlock[] subs = getSubBlocks();
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
* the given vector.
@ -298,22 +336,17 @@ public abstract class StructuredBlock {
* dumpInstruction afterwards.
* @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
{
// if (!defineHere.isEmpty())
writer.println("defining: "+defineHere);
/* XXX declare variables needed in this block */
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.

@ -48,18 +48,25 @@ public class VariableSet extends java.util.Vector {
* Merges the current VariableSet with another. For all slots occuring
* in both variable sets, all corresponding LocalInfos are merged.
* The variable sets are not changed (use union for this).
* @return The merged variables.
* @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++) {
LocalInfo li1 = ((LocalInfo) elementData[i]).getLocalInfo();
boolean didMerge = false;
for (int j=0; j<vs.elementCount; j++) {
LocalInfo li2 = ((LocalInfo) vs.elementData[j]).getLocalInfo();
if (li1.getSlot() == li2.getSlot()) {
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
* variable set.
* @param vs The other variable set.
@ -150,6 +157,34 @@ public class VariableSet extends java.util.Vector {
/* Now set the new size */
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