From 704a534731eba02019efdf6bdea1808bfc808618 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 25 Sep 1998 21:48:53 +0000 Subject: [PATCH] Initial revision git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@36 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/flow/CatchBlock.java | 147 ++++++++++++ jode/jode/flow/CreateAssignExpression.java | 115 ++++++++++ jode/jode/flow/CreateIfThenElseOperator.java | 221 +++++++++++++++++++ jode/jode/flow/CreatePostIncExpression.java | 149 +++++++++++++ 4 files changed, 632 insertions(+) create mode 100644 jode/jode/flow/CatchBlock.java create mode 100644 jode/jode/flow/CreateAssignExpression.java create mode 100644 jode/jode/flow/CreateIfThenElseOperator.java create mode 100644 jode/jode/flow/CreatePostIncExpression.java diff --git a/jode/jode/flow/CatchBlock.java b/jode/jode/flow/CatchBlock.java new file mode 100644 index 0000000..08874de --- /dev/null +++ b/jode/jode/flow/CatchBlock.java @@ -0,0 +1,147 @@ +/* CatchBlock Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.flow; +import jode.LocalInfo; +import sun.tools.java.Identifier; + +/** + * + * @author Jochen Hoenicke + */ +public class CatchBlock extends StructuredBlock { + + /** + * The try block. This may be another CatchBlock! + */ + StructuredBlock tryBlock; + + /** + * The catch block. + */ + StructuredBlock catchBlock; + + /** + * The type of the exception. + */ + sun.tools.java.Type exceptionType; + + /** + * The local containing the exception. + */ + LocalInfo exceptionLocal; + + public CatchBlock(RawTryCatchBlock rawBlock) { + exceptionType = rawBlock.type; + this.tryBlock = rawBlock.tryBlock; + tryBlock.outer = this; + } + + static int serialno=0; + + /** + * Sets the catch block. + * @param catchBlock the catch block. + */ + public void setCatchBlock(StructuredBlock catchBlock) { + if (catchBlock instanceof SequentialBlock + && catchBlock.getSubBlocks()[0] instanceof InstructionBlock) { + + InstructionBlock localBlock = + (InstructionBlock) catchBlock.getSubBlocks()[0]; + jode.Instruction instr = localBlock.getInstruction(); + + if (instr instanceof jode.PopOperator) { + exceptionLocal = new LocalInfo(99); + exceptionLocal.setName + (Identifier.lookup("exception_"+(serialno++)+"_")); + catchBlock = catchBlock.getSubBlocks()[1]; + } else if (instr instanceof jode.LocalStoreOperator) { + exceptionLocal = + ((jode.LocalStoreOperator) instr).getLocalInfo(); + catchBlock = catchBlock.getSubBlocks()[1]; + } + } + if (exceptionLocal == null) { + exceptionLocal = new LocalInfo(99); + exceptionLocal.setName(Identifier.lookup("ERROR!!!")); + } + this.catchBlock = catchBlock; + catchBlock.outer = this; + catchBlock.setFlowBlock(flowBlock); + } + + /* The implementation of getNext[Flow]Block is the standard + * implementation */ + + /** + * Replaces the given sub block with a new block. + * @param oldBlock the old sub block. + * @param newBlock the new sub block. + * @return false, if oldBlock wasn't a direct sub block. + */ + public boolean replaceSubBlock(StructuredBlock oldBlock, + StructuredBlock newBlock) { + if (tryBlock == oldBlock) + tryBlock = newBlock; + else if (catchBlock == oldBlock) + catchBlock = newBlock; + else + return false; + return true; + } + + /** + * Returns all sub block of this structured block. + */ + public StructuredBlock[] getSubBlocks() { + StructuredBlock[] result = { tryBlock, catchBlock }; + return result; + } + + /** + * Determines if there is a sub block, that flows through to the end + * of this block. If this returns true, you know that jump is null. + * @return true, if the jump may be safely changed. + */ + public boolean jumpMayBeChanged() { + return ( tryBlock.jump != null || tryBlock.jumpMayBeChanged()) + && (catchBlock.jump != null || catchBlock.jumpMayBeChanged()); + } + + public void dumpInstruction(jode.TabbedPrintWriter writer) + throws java.io.IOException { + /* avoid ugly nested tries */ + if (!(outer instanceof CatchBlock + /* XXX || outer instanceof FinallyBlock*/)) { + writer.println("try {"); + writer.tab(); + } + tryBlock.dumpInstruction(writer); + writer.untab(); + writer.println("} catch ("+/*XXX*/exceptionType.typeString + (exceptionLocal.getName().toString())+") {"); + writer.tab(); + catchBlock.dumpSource(writer); + if (!(outer instanceof CatchBlock + /* XXX || outer instanceof FinallyBlock*/)) { + writer.untab(); + writer.println("}"); + } + } +} diff --git a/jode/jode/flow/CreateAssignExpression.java b/jode/jode/flow/CreateAssignExpression.java new file mode 100644 index 0000000..9d6bd61 --- /dev/null +++ b/jode/jode/flow/CreateAssignExpression.java @@ -0,0 +1,115 @@ +/* + * CreateAssignExpression (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.*; + +public class CreateAssignExpression implements Transformation{ + + public boolean transform(FlowBlock flow) { + return (createAssignOp(flow) || createAssignExpression(flow)); + } + + public boolean createAssignOp(FlowBlock flow) { + Expression rightHandSide; + StoreInstruction store; + BinaryOperator binop; + InstructionContainer lastBlock; + SequentialBlock rhsBlock; + SequentialBlock sequBlock; + try { + InstructionBlock ib; + lastBlock = (InstructionContainer) flow.lastModified; + store = (StoreInstruction) lastBlock.getInstruction(); + + sequBlock = (SequentialBlock) lastBlock.outer; + if (sequBlock.subBlocks[1] != lastBlock) + return false; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + binop = (BinaryOperator) ib.getInstruction(); + if (binop.getOperator() < binop.ADD_OP || + binop.getOperator() >= binop.ASSIGN_OP) + return false; + + sequBlock = (SequentialBlock) sequBlock.outer; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + rightHandSide = (Expression) ib.getInstruction(); + if (rightHandSide.isVoid()) + return false; /* XXX */ + + rhsBlock = (SequentialBlock) sequBlock.outer; + ib = (InstructionBlock) rhsBlock.subBlocks[0]; + + Operator load = (Operator) ib.getInstruction(); + if (!store.matches(load)) + return false; + + sequBlock = (SequentialBlock) rhsBlock.outer; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + DupOperator dup = (DupOperator) ib.getInstruction(); + if (dup.getDepth() != 0 && + dup.getCount() != store.getLValueOperandCount()) + return false; + } catch (ClassCastException ex) { + return false; + } catch (NullPointerException ex) { + return false; + } + ((InstructionBlock)rhsBlock.subBlocks[0]) + .setInstruction(rightHandSide); + rhsBlock.replace(sequBlock, rhsBlock); + + store.setOperator(store.OPASSIGN_OP+binop.getOperator()); + store.setLValueType(MyType.intersection(binop.getType(), + store.getLValueType())); + lastBlock.setInstruction(store); + lastBlock.replace(rhsBlock.subBlocks[1], lastBlock); + return true; + } + + public boolean createAssignExpression(FlowBlock flow) { + StoreInstruction store; + InstructionContainer lastBlock; + SequentialBlock sequBlock; + try { + lastBlock = (InstructionContainer) flow.lastModified; + store = (StoreInstruction) lastBlock.getInstruction(); + + sequBlock = (SequentialBlock) lastBlock.outer; + InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0]; + + DupOperator dup = (DupOperator) ib.getInstruction(); + if (dup.getDepth() != store.getLValueOperandCount() && + dup.getCount() != store.getLValueType().stackSize()) + return false; + } catch (NullPointerException ex) { + return false; + } catch (ClassCastException ex) { + return false; + } + lastBlock.setInstruction + (new AssignOperator(Operator.ASSIGN_OP, store)); + lastBlock.replace(sequBlock, lastBlock); + return true; + + } +} diff --git a/jode/jode/flow/CreateIfThenElseOperator.java b/jode/jode/flow/CreateIfThenElseOperator.java new file mode 100644 index 0000000..114758f --- /dev/null +++ b/jode/jode/flow/CreateIfThenElseOperator.java @@ -0,0 +1,221 @@ +/* + * CreateIfThenElseOperator (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.Expression; +import jode.IfThenElseOperator; +import jode.MyType; +import jode.CompareUnaryOperator; +import java.util.Enumeration; +import java.util.Vector; + +public class CreateIfThenElseOperator implements Transformation { + + /** + * This handles the more complicated form of the ?-:-operator used + * in a conditional block. The simplest case is: + *
+     *   if (cond)
+     *       push e1
+     *   else {
+     *       IF (c2)
+     *           GOTO flow_2_
+     *       push 0
+     *   }
+     * ->IF (stack_0 == 0)
+     *     GOTO flow_1_
+     *   GOTO flow_2_
+     * 
+ * is transformed to + *
+     *   push cond ? e1 : c2
+     * ->IF (stack_0 == 0)
+     *     GOTO flow_1_
+     *   GOTO flow_2_
+     * 
+ * + * The -> points to the lastModified block. Note + * that both the if and the then part may contain this + * condition+push0-block. There may be even stack if-then-else-blocks + * for very complicated nested ?-:-Operators.

+ * + * Also note that the produced code is suboptimal: The push-0 could + * sometimes be better replaced with a correct jump. + * @param flow The FlowBlock that is transformed + */ + public boolean createFunny(FlowBlock flow) { + + Expression[] e = new Expression[3]; + IfThenElseBlock ifBlock; + try { + ConditionalBlock conditional = + (ConditionalBlock) flow.lastModified; + + if (!(conditional.trueBlock instanceof EmptyBlock) + || conditional.trueBlock.jump == null + || conditional.jump == null) + return false; + + CompareUnaryOperator compare = + (CompareUnaryOperator) conditional.getInstruction(); + + FlowBlock trueDestination; + if (compare.getOperator() == compare.EQUALS_OP) + trueDestination = conditional.jump.destination; + else if (compare.getOperator() == compare.NOTEQUALS_OP) + trueDestination = conditional.trueBlock.jump.destination; + else + return false; + + SequentialBlock sequBlock = + (SequentialBlock) conditional.outer; + + ifBlock = (IfThenElseBlock) sequBlock.subBlocks[0]; + + while (true) { + if (ifBlock.thenBlock instanceof IfThenElseBlock) + ifBlock = (IfThenElseBlock) ifBlock.thenBlock; + else if (ifBlock.elseBlock instanceof IfThenElseBlock) + ifBlock = (IfThenElseBlock) ifBlock.elseBlock; + else + break; + } + + e[0] = (Expression) ifBlock.cond; + + StructuredBlock[] subBlocks = ifBlock.getSubBlocks(); + if (subBlocks.length != 2) + return false; + + for (int i=0; i< 2; i++) { + if (subBlocks[i] instanceof InstructionBlock) { + e[i+1] = (Expression) + ((InstructionBlock)subBlocks[i]).getInstruction(); + continue; + } + + sequBlock = (SequentialBlock) subBlocks[i]; + ConditionalBlock condBlock = + (ConditionalBlock) sequBlock.subBlocks[0]; + InstructionBlock pushBlock = + (InstructionBlock) sequBlock.subBlocks[1]; + + Expression zeroExpr = + (Expression) pushBlock.getInstruction(); + jode.ConstOperator zero = + (jode.ConstOperator) zeroExpr.getOperator(); + if (!zero.getValue().equals("0")) + return false; + + if (!(condBlock.trueBlock instanceof EmptyBlock) + || condBlock.trueBlock.jump == null + || condBlock.jump != null + || condBlock.trueBlock.jump.destination + != trueDestination) + return false; + + Expression cond = (Expression) condBlock.getInstruction(); + condBlock.trueBlock.removeJump(); + pushBlock.setInstruction(cond); + pushBlock.replace(sequBlock, pushBlock); + e[i+1] = cond; + } + } catch (ClassCastException ex) { + return false; + } catch (NullPointerException ex) { + return false; + } + + if (jode.Decompiler.isVerbose) + System.err.print("?"); + + IfThenElseOperator iteo = new IfThenElseOperator + (MyType.intersection(e[1].getType(),e[2].getType())); + + ((InstructionBlock)ifBlock.thenBlock). + setInstruction(new Expression(iteo, e)); + ifBlock.thenBlock.replace(ifBlock, ifBlock.thenBlock); + return true; + } + + /** + * This handles the normal form of the ?-:-operator: + *

+     *   if (cond)
+     *       push e1
+     *       GOTO flow_1_
+     * ->push e2
+     *   GOTO flow_2
+     * 
+ * is transformed to + *
+     * ->push cond ? e1 : e2
+     * 
+ * The -> points to the lastModified block. + * @param flow The FlowBlock that is transformed + */ + public boolean create(FlowBlock flow) { + Expression e[] = new Expression[3]; + try { + InstructionBlock elseBlock = (InstructionBlock) flow.lastModified; + + SequentialBlock sequBlock = (SequentialBlock)elseBlock.outer; + if (sequBlock.subBlocks[1] != elseBlock) + return false; + + IfThenElseBlock ifBlock = (IfThenElseBlock)sequBlock.subBlocks[0]; + if (ifBlock.elseBlock != null) + return false; + + InstructionBlock thenBlock = (InstructionBlock) ifBlock.thenBlock; + + if (thenBlock.jump.destination != elseBlock.jump.destination) + return false; + + e[1] = (Expression) thenBlock.getInstruction(); + if (e[1].isVoid()) + return false; + e[2] = (Expression) elseBlock.getInstruction(); + if (e[2].isVoid()) + return false; + e[0] = (Expression) ifBlock.cond; + + thenBlock.removeJump(); + } catch (ClassCastException ex) { + return false; + } catch (NullPointerException ex) { + return false; + } + + if (jode.Decompiler.isVerbose) + System.err.print("?"); + + IfThenElseOperator iteo = new IfThenElseOperator + (MyType.intersection(e[1].getType(),e[2].getType())); + + ((InstructionBlock)flow.lastModified). + setInstruction(new Expression(iteo, e)); + flow.lastModified.replace(flow.lastModified.outer, flow.lastModified); + return true; + } + + public boolean transform(FlowBlock flow) { + return createFunny(flow) || create(flow); + } +} diff --git a/jode/jode/flow/CreatePostIncExpression.java b/jode/jode/flow/CreatePostIncExpression.java new file mode 100644 index 0000000..cc5ce6e --- /dev/null +++ b/jode/jode/flow/CreatePostIncExpression.java @@ -0,0 +1,149 @@ +/* + * CreatePostIncExpression (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 sun.tools.java.Type; +import jode.*; + +public class CreatePostIncExpression implements Transformation { + + public boolean transform(FlowBlock flow) + { + return (createLocalPostInc(flow) || createPostInc(flow)); + } + + public boolean createLocalPostInc(FlowBlock flow) { + IIncOperator iinc; + int op; + InstructionContainer lastBlock; + Type type; + try { + lastBlock = (InstructionContainer) flow.lastModified; + Expression iincExpr = (Expression) lastBlock.getInstruction(); + iinc = (IIncOperator) iincExpr.getOperator(); + if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP) + op = Operator.INC_OP; + else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP) + op = Operator.DEC_OP; + else + return false; + if (!iinc.getValue().equals("1") && + !iinc.getValue().equals("-1")) + return false; + if (iinc.getValue().equals("-1")) + op ^= 1; + + SequentialBlock sequBlock = (SequentialBlock)lastBlock.outer; + if (sequBlock.subBlocks[1] != lastBlock) + return false; + + InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0]; + Expression loadExpr = (Expression) ib.getInstruction(); + LocalLoadOperator load = + (LocalLoadOperator)loadExpr.getOperator(); + if (!iinc.matches(load)) + return false; + + type = MyType.intersection(load.getType(), MyType.tUInt); + } catch (NullPointerException ex) { + return false; + } catch (ClassCastException ex) { + return false; + } + Operator postop = new LocalPostFixOperator(type, op, iinc); + lastBlock.setInstruction(postop); + lastBlock.replace(lastBlock.outer, lastBlock); + return true; + } + + public boolean createPostInc(FlowBlock flow) { + StoreInstruction store; + int op; + Type type; + InstructionBlock lastBlock; + SequentialBlock sequBlock; + try { + lastBlock = (InstructionBlock) flow.lastModified; + store = (StoreInstruction) lastBlock.getInstruction(); + + sequBlock = (SequentialBlock) lastBlock.outer; + if (sequBlock.subBlocks[1] != lastBlock) + return false; + + InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0]; + BinaryOperator binOp = (BinaryOperator) ib.getInstruction(); + if (binOp.getOperator() == store.ADD_OP) + op = Operator.INC_OP; + else if (store.getOperator() == store.NEG_OP) + op = Operator.DEC_OP; + else + return false; + + sequBlock = (SequentialBlock) sequBlock.outer; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + Expression expr = (Expression) ib.getInstruction(); + ConstOperator constOp = (ConstOperator) expr.getOperator(); + if (!constOp.getValue().equals("1") && + !constOp.getValue().equals("-1")) + return false; + if (constOp.getValue().equals("-1")) + op ^= 1; + + sequBlock = (SequentialBlock) sequBlock.outer; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + DupOperator dup = (DupOperator) ib.getInstruction(); + if (dup.getCount() != store.getLValueType().stackSize() || + dup.getDepth() != store.getLValueOperandCount()) + return false; + + sequBlock = (SequentialBlock) sequBlock.outer; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + Instruction instr = ib.getInstruction(); + if (instr instanceof Expression + && ((Expression)instr).getSubExpressions().length == 0) + instr = ((Expression)instr).getOperator(); + + Operator load = (Operator) instr; + if (!store.matches(load)) + return false; + + if (store.getLValueOperandCount() > 0) { + sequBlock = (SequentialBlock) sequBlock.outer; + ib = (InstructionBlock) sequBlock.subBlocks[0]; + + DupOperator dup2 = (DupOperator) ib.getInstruction(); + if (dup2.getCount() != store.getLValueOperandCount() || + dup2.getDepth() != 0) + return false; + } + type = MyType.intersection(load.getType(), store.getLValueType()); + } catch (NullPointerException ex) { + return false; + } catch (ClassCastException ex) { + return false; + } + Operator postop = new PostFixOperator(type, op, store); + lastBlock.setInstruction(postop); + lastBlock.replace(sequBlock, lastBlock); + return true; + } +}