From 83e1e75c5d8f92c3699e5e88a9faf635ad822c93 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 16 Sep 1998 11:08:14 +0000 Subject: [PATCH] Initial revision git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@13 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/flow/EmptyBlock.java | 50 ++++++ jode/jode/flow/FinallyBlock.java | 32 ++++ jode/jode/flow/FlowBlock.java | 252 +++++++++++++++++++++++++++ jode/jode/flow/InstructionBlock.java | 46 +++++ jode/jode/flow/RawTryCatchBlock.java | 59 +++++++ jode/jode/flow/StructuredBlock.java | 174 ++++++++++++++++++ 6 files changed, 613 insertions(+) create mode 100644 jode/jode/flow/EmptyBlock.java create mode 100644 jode/jode/flow/FinallyBlock.java create mode 100644 jode/jode/flow/FlowBlock.java create mode 100644 jode/jode/flow/InstructionBlock.java create mode 100644 jode/jode/flow/RawTryCatchBlock.java create mode 100644 jode/jode/flow/StructuredBlock.java diff --git a/jode/jode/flow/EmptyBlock.java b/jode/jode/flow/EmptyBlock.java new file mode 100644 index 0000000..a4f5a08 --- /dev/null +++ b/jode/jode/flow/EmptyBlock.java @@ -0,0 +1,50 @@ +/* + * EmptyBlock (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; + +/** + * This is the structured block for an empty block. + */ +public class EmptyBlock extends StructuredBlock { + Instruction instr; + + SimpleInstruction(Instruction instr) { + in = new Vector(); + out = new Vector(); + this.instr = instr; + if (instr instanceof LocalVarOperator) { + LocalVarOperator varOp = (LocalVarOperator) instr; + if (varOp.isRead()) + in.addElement(varOp.getLocalInfo()); + else /* if (varOp.isWrite()) */ + out.addElement(varOp.getLocalInfo()); + } + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (!(instr instanceof NopOperator)) { + if (instr.getType() != MyType.tVoid) + writer.print("push "); + writer.println(instr.toString()+";"); + } + } +} diff --git a/jode/jode/flow/FinallyBlock.java b/jode/jode/flow/FinallyBlock.java new file mode 100644 index 0000000..3f844c0 --- /dev/null +++ b/jode/jode/flow/FinallyBlock.java @@ -0,0 +1,32 @@ +/* jode.flow.FinallyBlock (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; + +/** + * A FinallyBlock represents the instructions and try catch regions + * that are generated by javac when you write a finally block. + * + * We detect such a block when we look at the exception table. There + * is always an "any"-exception region (exception class is null) that + * surrounds the first block. The synchronized-blocks create the same + * region, so we have to take care of this. + */ + +public FinallyBlock extends StructuredBlock { +} diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java new file mode 100644 index 0000000..e158e49 --- /dev/null +++ b/jode/jode/flow/FlowBlock.java @@ -0,0 +1,252 @@ +/* + * FlowBlock (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; + +/** + * A flow block is the structure of which the flow graph consists. A + * flow block contains structured code together with some conditional + * or unconditional jumps to the head of other flow blocks. + * + * We do a T1/T2 analysis to combine all flow blocks to a single. If + * the graph isn't reducible that doesn't work, but java can only + * produce reducible flow graphs. + */ +public class FlowBlock { + + /** + * The starting address of this flow block. This is mainly used + * to produce the source code in code order. + */ + int addr; + + /** + * The outermost structructed block in this flow block. + */ + StructuredBlock block; + + /** + * The last modified structured block. + */ + StructuredBlock lastModified; + + /** + * All jumps that this flow block contains. + */ + Vector successors; + + /** + * 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. + */ + Vector predecessors; + + public void optimizeJumps(FlowBlock successor) { + /* remove all unconditional jumps to the successor which have the + * end of the block as normal successor. + */ + + /* replace all conditional jumps to the successor, which are followed + * by a block which has the end of the block as normal successor, + * with "if (not condition) block". + */ + + /* if there are jumps in a while block, which has the end of + * the block as normal successor or is followed by a + * unconditional jump to successor, replace jumps with breaks + * to the while block. If the condition of the while is true, + * and the first instruction is converted to a conditional break + * remove that break and use the condition in the while block. + */ + + + /* if there are jumps in an switch block, which has as normal + * successor the end of this FlowBlock, replace them with a + * break to the switch block. + * if there successor isn't the end of this FlowBlock, but + * there are many, or the next rule could work (some more + * heuristics?) and there is currently no flow to the end of + * the switch block, replace all such successors with a break + * and add a new unconditional jump after the switch block. */ + + /* if there are unconditional jumps in an if-then block, which + * have as normal successor the end of the if-then block, and + * the if-then block is followed by a single block, which has + * as normal successor the end of the block, then replace + * the if-then block with a if-then-else block and remove the + * unconditional jumps. + */ + } + + + /* Special cases: + * + * try-header + * |- first instruction + * | ... + * | last instruction + * |- optional jump (last+1) + * | ... + * `- catch block + * + * A try block may have many try-headers with different catch blocks + * and there may be a finally block: + * + * try-header any + * | try-header + * |--|- first instruction + * | | ... + * | | every jump to outside is preceded by jsr finally + * | | ... + * | | last instruction + * | |- optional jump after catch block (last+1) + * | | ... | + * | `- catch block | + * | ... | + * | ,-----------------' + * | |-jump after all catch blocks + * | v + * | jsr finally -----------------, + * |- jump after finally | + * `- catch any (local_n) v + * jsr finally ---------------->| + * throw local_n; | + * finally: <-----------------------' + * astore_n + * ... + * return_n + * + * + * flow-block + * finally-block + * ---> try-header + * finally { + * ---> first-finally-instruction + * + * A synchronized block uses a similar technique: + * + * local_x = monitor object; + * monitorenter local_x + * try-header any + * |- syncronized block + * | ... + * | every jump to outside is preceded by jsr monexit ---, + * | ... | + * |- monitorexit local_x | + * | jump after this block (without jsr monexit) | + * `- catch any (local_n) | + * monitorexit local_x | + * throw local_n | + * monexit: <-----------------------------------------------' + * astore_n + * monitorexit local_x + * return_n + */ + + public boolean doT1 { + /* search successor with smallest addr. */ + + /* check if this successor has only this block as predecessor. */ + /* if not, return false. */ + + /* The switch case: if the last instruction in this block is a + * switch block, and all jumps to successor lie in a single case, + * or if all jumps + * which doesn't have the end of the block as normal + * successor, combine the successor with that block. But this + * doesn't catch all cases. + */ + + optimizeJumps(successor); + + /* if the successor is the dummy return instruction, replace all + * jumps with a return. + */ + + /* If there are further jumps, put a do/while(0) block around + * current block and replace every necessary jump with a break + * to the do/while block. Then combine the block with a + * sequential composition. */ + } + + 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. + */ + + /* If there is only one jump to the beginning and it is the + * last jump and (there is a do/while(0) block surrounding + * everything but the last instruction, or the last + * instruction is a increase/decrease statement), replace the + * do/while(0) with a for(;;last_instr) resp. create a new one + * and replace breaks to do/while with continue. + */ + { + /* Otherwise: */ + optimizeJumps(this); + + /* create a new while(true) block. + */ + } + + /* if there are further jumps to this, replace every jump with a + * continue to while block and return true. + */ + } +} + +/** + * A structured block describes a structured program. There may be a + * Jump after a block (even after a inner structured block), but the + * goal is, to remove all such jumps and make a single flow block.

+ * + * There are following types of structured blocks:

+ */ +public class StructuredBlock { + /** The surrounding block, or null if this is the outermost block in a + * flow block. + */ + StructuredBlock parent; + + /** The flow block to which this structured block belongs. + */ + FlowBlock flow; + +} + +public class ConditionalJump extends Jump { + Expression condition; + StructuredBlock prev; + FlowBlock parent; + FlowBlock jump, nojump; +} + +public class UnconditionalJump extends Jump { + StructuredBlock prev; + FlowBlock parent; + FlowBlock jump; +} diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java new file mode 100644 index 0000000..2a9a96f --- /dev/null +++ b/jode/jode/flow/InstructionBlock.java @@ -0,0 +1,46 @@ +/* InstructionBlock (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; + +/** + * This is the structured block for atomic instructions. + */ +public class InstructionBlock extends StructuredBlock { + Instruction instr; + + InstructionBlock(Instruction instr) { + in = new Vector(); + out = new Vector(); + this.instr = instr; + if (instr instanceof LocalVarOperator) { + LocalVarOperator varOp = (LocalVarOperator) instr; + if (varOp.isRead()) + in.addElement(varOp.getLocalInfo()); + else /* if (varOp.isWrite()) */ + out.addElement(varOp.getLocalInfo()); + } + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + writer.println("/* empty */"); + } +} diff --git a/jode/jode/flow/RawTryCatchBlock.java b/jode/jode/flow/RawTryCatchBlock.java new file mode 100644 index 0000000..c18bfff --- /dev/null +++ b/jode/jode/flow/RawTryCatchBlock.java @@ -0,0 +1,59 @@ +/* jode.flow.RawTryCatchBlock (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; + +/** + * A RawTryCatchBlock is created for each exception in the + * ExceptionHandlers-Attribute.

+ * + * For each catch block (there may be more than one catch block + * appending a single try block) and for each finally and each + * synchronized block such a RawTryCatchBlock is created. The + * finally/synchronized-blocks have a null exception type so that they + * are easily distinguishable from the catch blocks.

+ * + * A RawTryCatchBlock is an intermediate representation that gets + * converted later to a CatchBlock, a FinallyBlock or a + * SynchronizedBlock (after the body is parsed). + * + * @date 1998/09/16 + * @author Jochen Hoenicke + * @see CatchBlock + * @see FinallyBlock + * @see SynchronizedBlock + */ + +public RawTryCatchBlock extends StructuredBlock { + + /** + * An unconditional jump to the EndBlock. + */ + Jump EndBlock; + + /** + * An unconditional jump to the CatchBlock. + */ + Jump CatchBlock; + + /** + * The type of the exception that is catched. This is null for a + * synchronized/finally block + */ + Type type; +} diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java new file mode 100644 index 0000000..5e56dcf --- /dev/null +++ b/jode/jode/flow/StructuredBlock.java @@ -0,0 +1,174 @@ +/* + * StructuredBlock (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; + +/** + * A structured block is the building block of the source programm. + * For every program construct like if, while, try, or blocks there is + * a corresponding structured block. + * + * Some of these Block are only intermediate representation, that get + * converted to another block later. + * + * Every block has to handle the local variables that it contains. + * This is done by the in/out vectors and the local variable structure + * themself. Every local variable used in this structured block is + * either in or out. + * + * There are following types of structured blocks: + *

+ */ + +public abstract class StructuredBlock { + /* Invariants: + * in.intersection(out) = empty + * outer != null => flowblock = outer.flowblock + * outer == null => flowblock.block = this + * jump == null => outer != null + * either getNextBlock() != null + * or getNextFlowBlock() != null or outer == null + * either outer.getNextBlock(this) != null + * or outer.getNextFlowBlock(this) != null + */ + + /** + * The in locals. This are the locals, which are used in this + * block and whose values may be the result of a assignment + * outside of the whole flow block. That means, that there is a + * path from the start of the current flow block, on which the + * local variable is never assigned + */ + Vector in; + + /** + * 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 + */ + Vector out; + + /** + * The surrounding structured block. If this is the outermost + * block in a flow block, outer is null. + */ + StructuredBlock outer; + + /** + * The flow block in which this structured block lies. + */ + FlowBlock flowblock; + + /** + * The jump that follows on this block, or null if there is no + * jump, but the control flows normal (only allowed if + * getNextBlock != null). + */ + Jump jump; + + /** + * Returns the block where the control will normally flow to, when + * this block is finished (ignoring the jump after this block). + */ + StructuredBlock getNextBlock() { + if (outer != null) + outer.getNextBlock(this); + else + return null; + } + + /** + * Returns the flow block where the control will normally flow to, + * when this block is finished (ignoring the jump after this + * block). + * @return null, if the control flows into a non empty structured + * block or if this is the outermost block. + */ + FlowBlock getNextFlowBlock() { + if (outer != null) + outer.getNextFlowBlock(this); + else + return null; + } + + /** + * Checks if the jump to the outside has correct monitorexit and + * jsr instructions attached. + * @return null, if everything is okay, and a diagnostic message that + * should be put in a comment otherwise. + */ + String checkJump(Jump jump) { + if (outer != null) + return outer.checkJump(jump); + else if (jump.hasAttachments()) + return "Unknown attachments: "+jump.describeAttachments() + else + return null; + } + + /** + * Returns the block where the control will normally flow to, when + * the given sub block is finished (not ignoring the jump + * after this block). (This is overwritten by SequentialBlock and + * SwitchBlock). If this isn't called with a direct sub block, + * the behaviour is undefined, so take care. + * @return null, if the control flows to another FlowBlock. */ + StructuredBlock getNextBlock(StructuredBlock subBlock) { + if (jump != null) + return null; + return getNextBlock(); + } + + FlowBlock getNextFlowBlock(StructuredBlock subBlock) { + if (jump != null) + return jump; + return getNextFlowBlock(); + } + + /** + * 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. + */ + boolean replaceSubBlock(StructuredBlock oldBlock, + StructuredBlock newBlock) { + return false; + } + + /** + * Print the source code for this structured block. This may be + * called only once, because it remembers which local variables + * were declared. + */ + public abstract void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException; +}