diff --git a/jode/jode/bytecode/Opcodes.java b/jode/jode/bytecode/Opcodes.java index 01a48ca..929db50 100644 --- a/jode/jode/bytecode/Opcodes.java +++ b/jode/jode/bytecode/Opcodes.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); } diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 7d43922..18b6865 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -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 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; } } diff --git a/jode/jode/flow/CreateNewConstructor.java b/jode/jode/flow/CreateNewConstructor.java index 17f74b2..784a47b 100644 --- a/jode/jode/flow/CreateNewConstructor.java +++ b/jode/jode/flow/CreateNewConstructor.java @@ -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; } } diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index 00db7ad..5a059dc 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -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 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) diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java index 7cd4206..4c70a24 100644 --- a/jode/jode/flow/InstructionBlock.java +++ b/jode/jode/flow/InstructionBlock.java @@ -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) diff --git a/jode/jode/flow/InstructionContainer.java b/jode/jode/flow/InstructionContainer.java index 1a85217..e9c8328 100644 --- a/jode/jode/flow/InstructionContainer.java +++ b/jode/jode/flow/InstructionContainer.java @@ -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; + } } diff --git a/jode/jode/flow/Jump.java b/jode/jode/flow/Jump.java index ad02af2..fb9bf56 100644 --- a/jode/jode/flow/Jump.java +++ b/jode/jode/flow/Jump.java @@ -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()); + } } + diff --git a/jode/jode/flow/RemoveEmpty.java b/jode/jode/flow/RemoveEmpty.java index 1c51d6a..dbbdf0c 100644 --- a/jode/jode/flow/RemoveEmpty.java +++ b/jode/jode/flow/RemoveEmpty.java @@ -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; } diff --git a/jode/jode/flow/ReturnBlock.java b/jode/jode/flow/ReturnBlock.java index 1dfa518..4ae22e0 100644 --- a/jode/jode/flow/ReturnBlock.java +++ b/jode/jode/flow/ReturnBlock.java @@ -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; } diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index 77882c6..a942b97 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -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 + * 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=0; i--) { + LocalInfo li1 = (LocalInfo) elementData[i]; + for (int j=0; j