From de468af3b84511b0d33c4653610946925534b593 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 23 Sep 1998 11:29:00 +0000 Subject: [PATCH] mainly fixing... git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@26 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/decompiler/CodeAnalyzer.java | 40 +++-- jode/jode/flow/CombineIfGotoExpressions.java | 74 +++++++++ jode/jode/flow/CreateExpression.java | 18 +- jode/jode/flow/CreateNewConstructor.java | 95 +++++++++++ jode/jode/flow/FlowBlock.java | 165 +++++++++++++------ jode/jode/flow/SimplifyExpression.java | 30 ++++ jode/jode/flow/StructuredBlock.java | 3 +- 7 files changed, 347 insertions(+), 78 deletions(-) create mode 100644 jode/jode/flow/CombineIfGotoExpressions.java create mode 100644 jode/jode/flow/CreateNewConstructor.java create mode 100644 jode/jode/flow/SimplifyExpression.java diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index a1d846d..7d43922 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -70,6 +70,7 @@ public class CodeAnalyzer implements Analyzer, Constants { addr = instr[addr].getNextAddr(); } methodHeader = instr[0]; + methodHeader.makeStartBlock(); /* XXX do something with handlers */ } @@ -101,11 +102,11 @@ public class CodeAnalyzer implements Analyzer, Constants { new jode.flow.CreateExpression(), // new CreatePostIncExpression(), // new CreateAssignExpression(), -// new CreateNewConstructor(), -// new CombineIfGotoExpressions(), + new jode.flow.CreateNewConstructor(), + new jode.flow.CombineIfGotoExpressions(), // new CreateIfThenElseOperator(), // new CreateConstantArray(), -// new SimplifyExpression() + new jode.flow.SimplifyExpression() }; public void analyze() @@ -113,6 +114,7 @@ public class CodeAnalyzer implements Analyzer, Constants { /* XXX optimize */ Stack todo = new Stack(); FlowBlock flow = methodHeader; + analyzation: while (true) { /* First do some non flow transformations. */ @@ -134,31 +136,37 @@ public class CodeAnalyzer implements Analyzer, Constants { } FlowBlock succ = flow.getSuccessor(); - if (succ != null) { + while (succ != null && !flow.doT1(succ)) { - if (!flow.doT1(succ)) { - - /* T1 transformation failed, now succeed with + /* T1 transformation failed. */ + if (!todo.contains(succ) && succ != flow) { + /* succ wasn't tried before, succeed with * successor and put flow on the stack. */ - if (todo.contains(succ)) { - /* This is a sign that the flow graph is not - * reducible. We give up immediately! - */ - break; - } todo.push(flow); flow = succ; + continue analyzation; } - } else { - /* Block has no successor. + + /* Try the next successor. + */ + succ = flow.getSuccessor(succ); + } + if (succ == null) { + /* the Block has no successor where t1 is applicable. * * If everything is okay the stack should be empty now, * and the program is transformed correctly. * * Otherwise flow transformation didn't succeeded. */ - break; + System.err.println("breaking analyzation; flow: " + + flow.getLabel()); + while (!todo.isEmpty()) { + System.err.println("on Stack: " + + ((FlowBlock)todo.pop()).getLabel()); + } + break analyzation; } } } diff --git a/jode/jode/flow/CombineIfGotoExpressions.java b/jode/jode/flow/CombineIfGotoExpressions.java new file mode 100644 index 0000000..a8a6e0c --- /dev/null +++ b/jode/jode/flow/CombineIfGotoExpressions.java @@ -0,0 +1,74 @@ +/* + * CombineIfGotoExpressions (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import java.util.Vector; +import jode.Expression; +import jode.MyType; +import jode.BinaryOperator; + +public class CombineIfGotoExpressions implements Transformation{ + + public boolean transform(FlowBlock flow) { + Expression[] e; + ConditionalBlock cb; + Jump prevJump; + int operator; + try { + cb = (ConditionalBlock) flow.lastModified; + SequentialBlock sequBlock = (SequentialBlock) cb.outer; + if (sequBlock.subBlocks[1] != cb) + return false; + + // jode.Assert.assert(sequBlock.jump == null) + + ConditionalBlock cbprev = + (ConditionalBlock) sequBlock.subBlocks[0]; + + if (cbprev.jump != null) + return false; + + prevJump = ((EmptyBlock) cbprev.trueBlock).jump; + + if (prevJump.destination == cb.jump.destination) { + e = new Expression[2]; + operator = BinaryOperator.LOG_AND_OP; + e[1] = (Expression)cb.getInstruction(); + e[0] = ((Expression)cbprev.getInstruction()).negate(); + } else if (prevJump.destination + == ((EmptyBlock) cb.trueBlock).jump.destination) { + e = new Expression[2]; + operator = BinaryOperator.LOG_OR_OP; + e[1] = (Expression)cb.getInstruction(); + e[0] = (Expression)cbprev.getInstruction(); + } else + return false; + } catch (ClassCastException ex) { + return false; + } catch (NullPointerException ex) { + return false; + } + prevJump.prev.removeJump(); + Expression cond = + new Expression(new BinaryOperator(MyType.tBoolean, operator), e); + cb.setInstruction(cond); + cb.replace(cb.outer); + return true; + } +} diff --git a/jode/jode/flow/CreateExpression.java b/jode/jode/flow/CreateExpression.java index 427c996..d6714b8 100644 --- a/jode/jode/flow/CreateExpression.java +++ b/jode/jode/flow/CreateExpression.java @@ -44,16 +44,20 @@ public class CreateExpression implements Transformation { int params; StructuredBlock block; + try { - jode.TabbedPrintWriter writer = - new jode.TabbedPrintWriter(System.err, " "); - writer.tab(); System.err.println("Transformation on: "+flow.getLabel()); - flow.block.dumpSource(writer); flow.checkConsistent(); - System.err.println("; lastModified is: "); - flow.lastModified.dumpSource(writer); - } catch (java.io.IOException ex) {} + } 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; block = flow.lastModified; diff --git a/jode/jode/flow/CreateNewConstructor.java b/jode/jode/flow/CreateNewConstructor.java new file mode 100644 index 0000000..17f74b2 --- /dev/null +++ b/jode/jode/flow/CreateNewConstructor.java @@ -0,0 +1,95 @@ +/* + * CreateNewConstructor (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import jode.InvokeOperator; +import jode.Expression; +import jode.ConstructorOperator; +import jode.DupOperator; +import jode.NewOperator; + +public class CreateNewConstructor implements Transformation{ + + public boolean transform(FlowBlock flow) { + SequentialBlock sequBlock; + InvokeOperator constrCall; + Expression exprs[]; + try { + InstructionBlock block; + block = (InstructionBlock) flow.lastModified; + constrCall = (InvokeOperator) block.getInstruction(); + if (!constrCall.isConstructor()) + return false; + int params = constrCall.getOperandCount(); + exprs = new Expression[params]; + + sequBlock = (SequentialBlock) block.outer; + if (sequBlock.getSubBlocks()[1] != block) + return false; + + for (int i = params-1; i>0; i--) { + + block = (InstructionBlock) sequBlock.getSubBlocks()[0]; + if (block.jump != null) + return false; + + exprs[i] = (Expression) block.getInstruction(); + if (exprs[i].isVoid()) { + if (i == params-1) + return false; + Expression e = exprs[i+1].tryToCombine(exprs[i]); + if (e == null) + return false; + i++; + SequentialBlock subExprBlock = + (SequentialBlock) sequBlock.getSubBlocks()[1]; + subExprBlock.replace(sequBlock); + sequBlock = subExprBlock; + ((InstructionContainer)subExprBlock.getSubBlocks()[0]). + setInstruction(e); + exprs[i] = e; + } + sequBlock = (SequentialBlock)sequBlock.outer; + } + block = (InstructionBlock) sequBlock.getSubBlocks()[0]; + DupOperator dup = (DupOperator) block.getInstruction(); + if (dup.getCount() != 1 && dup.getDepth() != 0) + return false; + sequBlock = (SequentialBlock)sequBlock.outer; + block = (InstructionBlock) sequBlock.getSubBlocks()[0]; + exprs[0] = (Expression) block.getInstruction(); + if (exprs[0].isVoid()) + return false; + NewOperator op = (NewOperator) exprs[0].getOperator(); + if (constrCall.getClassType() != op.getType()) + return false; + } catch (ClassCastException ex) { + return false; + } catch (NullPointerException ex) { + return false; + } + ((InstructionContainer) flow.lastModified).setInstruction + (new Expression(new ConstructorOperator(constrCall.getClassType(), + constrCall.getField()), + exprs)); + + flow.lastModified.replace(sequBlock); + return true; + } +} diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index 095c84a..00db7ad 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -70,6 +70,9 @@ public class FlowBlock { * This is a vector of flow blocks, which reference this block. * Only if this vector contains exactly one element, it can be * moved into the preceding flow block. + * + * If this vectors contains the null element, this is the first + * flow block in a method. */ Vector predecessors; @@ -436,10 +439,11 @@ public class FlowBlock { /** * Search for an apropriate successor. - * @return the successor with smallest address - * or null if there isn't a successor at all. + * @param prevSucc The successor, that was previously tried. + * @return the successor with smallest address greater than prevSucc + * or null if there isn't any further successor at all. */ - public FlowBlock getSuccessor() { + public FlowBlock getSuccessor(FlowBlock prevSucc) { /* search successor with smallest addr. */ Enumeration enum = successors.elements(); FlowBlock succ = null; @@ -448,13 +452,25 @@ public class FlowBlock { if (jump == null) continue; FlowBlock fb = jump.destination; + if (prevSucc != null && fb.addr <= prevSucc.addr) + continue; if (succ == null || fb.addr < succ.addr) { + System.err.println("trying "+fb.getLabel()); succ = fb; } } return succ; } + /** + * Search for an apropriate successor. + * @return the successor with smallest address + * or null if there isn't a successor at all. + */ + public FlowBlock getSuccessor() { + return getSuccessor(null); + } + public void checkConsistent() { if (block.outer != null || block.flowBlock != this) { throw new RuntimeException("Inconsistency"); @@ -500,18 +516,21 @@ public class FlowBlock { succ.predecessors.elementAt(0) != this)) return false; - try { - TabbedPrintWriter writer = - new TabbedPrintWriter(System.err, " "); - writer.tab(); + try{ System.err.println("doing T1 analysis on: "+getLabel()); - block.dumpSource(writer); checkConsistent(); System.err.println("and "+succ.getLabel()); - succ.block.dumpSource(writer); succ.checkConsistent(); - } catch (java.io.IOException ex) {} - + } catch (RuntimeException ex) { + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + succ.block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } /* First find the innermost block that contains all jumps to this * successor and the last modified block. @@ -599,29 +618,36 @@ public class FlowBlock { } try { - TabbedPrintWriter writer = - new TabbedPrintWriter(System.err, " "); - writer.tab(); System.err.println("before optimizeJump: "+getLabel()); - block.dumpSource(writer); - checkConsistent(); - } catch (java.io.IOException ex) {} checkConsistent(); + } catch (RuntimeException ex) { + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } + /* Try to eliminate as many jumps as possible. */ appendBlock = optimizeJumps(succ, appendBlock); try { - TabbedPrintWriter writer = - new TabbedPrintWriter(System.err, " "); - writer.tab(); System.err.println("after optimizeJump: "+getLabel()); - block.dumpSource(writer); - checkConsistent(); - } catch (java.io.IOException ex) {} - System.err.println("XXX"); checkConsistent(); + } catch (RuntimeException ex) { + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } + /* Now remove the jump of the appendBlock if it points to successor. */ if (appendBlock.jump != null && @@ -687,34 +713,51 @@ public class FlowBlock { /* T1 transformation succeeded */ try { - TabbedPrintWriter writer = - new TabbedPrintWriter(System.err, " "); - writer.tab(); System.err.println("T1 succeeded:"); - block.dumpSource(writer); checkConsistent(); - } catch (java.io.IOException ex) {} + } catch (RuntimeException ex) { + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } return true; } public boolean doT2() { /* If there are no jumps to the beginning of this flow block - * or if this block has other predecessors which weren't - * considered yet, return false. The second condition make - * sure that the while isn't created up to the first continue. - */ - if (!predecessors.contains(this) - /* || complicated second condition XXX */ ) + * or if this block has other predecessors with a higher + * address, return false. The second condition make sure that + * the while isn't created up to the first continue. */ + if (!predecessors.contains(this)) return false; + Enumeration preds = predecessors.elements(); + while (preds.hasMoreElements()) { + FlowBlock predFlow = (FlowBlock) preds.nextElement(); + if (predFlow != null && predFlow.addr > addr) { + System.err.println("refusing T2 on: "+getLabel()+ + " because of "+predFlow.getLabel()); + /* XXX Is this enough to refuse T2 trafo ??? */ + return false; + } + } + try { - TabbedPrintWriter writer = - new TabbedPrintWriter(System.err, " "); - writer.tab(); System.err.println("doing T2 analysis on: "+getLabel()); - block.dumpSource(writer); checkConsistent(); - } catch (java.io.IOException ex) {} + } catch (RuntimeException ex) { + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } /* Update the in/out-Vectors now */ updateInOut(this, false); @@ -796,13 +839,17 @@ public class FlowBlock { /* T2 analysis succeeded */ try { - TabbedPrintWriter writer = - new TabbedPrintWriter(System.err, " "); - writer.tab(); - System.err.println("T2 succeded:"); - block.dumpSource(writer); + System.err.println("T2 succeeded:"); checkConsistent(); - } catch (java.io.IOException ex) {} + } catch (RuntimeException ex) { + try { + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(System.err, " "); + writer.tab(); + block.dumpSource(writer); + } catch (java.io.IOException ioex) { + } + } return true; } @@ -814,15 +861,24 @@ public class FlowBlock { Enumeration enum = successors.elements(); while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); - if (jump.destAddr == -1) - jump.destination = END_OF_METHOD; - else - jump.destination = instr[jump.destAddr]; - if (!jump.destination.predecessors.contains(this)) - jump.destination.predecessors.addElement(this); + if (jump != null) { + if (jump.destAddr == -1) + jump.destination = END_OF_METHOD; + else + jump.destination = instr[jump.destAddr]; + if (!jump.destination.predecessors.contains(this)) + jump.destination.predecessors.addElement(this); + } } } + /** + * Mark the flow block as first flow block in a method. + */ + public void makeStartBlock() { + predecessors.addElement(null); + } + public void removeSuccessor(Jump jump) { successors.setElementAt(null, successors.indexOf(jump)); } @@ -837,7 +893,8 @@ public class FlowBlock { public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { - if (label != null) { + if (predecessors.size() != 1 || + predecessors.elementAt(0) != null) { writer.untab(); writer.println(label+":"); writer.tab(); @@ -864,7 +921,7 @@ public class FlowBlock { */ public String getLabel() { if (label == null) - label = "flow_"+(serialno++)+"_"; + label = "flow_"+addr+"_"+(serialno++)+"_"; return label; } } diff --git a/jode/jode/flow/SimplifyExpression.java b/jode/jode/flow/SimplifyExpression.java new file mode 100644 index 0000000..df6cbaf --- /dev/null +++ b/jode/jode/flow/SimplifyExpression.java @@ -0,0 +1,30 @@ +/* + * SimplifyExpression (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; + +public class SimplifyExpression implements Transformation { + public boolean transform(FlowBlock flow) { + if (flow.lastModified instanceof InstructionContainer) { + InstructionContainer ic = (InstructionContainer) flow.lastModified; + ic.setInstruction(ic.getInstruction().simplify()); + } + return false; + } +} diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index 67563e9..77882c6 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -284,7 +284,8 @@ public abstract class StructuredBlock { * @param succs The vector, the successors should be stored to. */ public void fillSuccessors(java.util.Vector succs) { - succs.addElement(jump); + if (jump != null) + succs.addElement(jump); StructuredBlock[] subs = getSubBlocks(); for (int i=0; i