Initial revision

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@13 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent 5c4d86e1cb
commit 83e1e75c5d
  1. 50
      jode/jode/flow/EmptyBlock.java
  2. 32
      jode/jode/flow/FinallyBlock.java
  3. 252
      jode/jode/flow/FlowBlock.java
  4. 46
      jode/jode/flow/InstructionBlock.java
  5. 59
      jode/jode/flow/RawTryCatchBlock.java
  6. 174
      jode/jode/flow/StructuredBlock.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()+";");
}
}
}

@ -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 {
}

@ -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.<p>
*
* There are following types of structured blocks: <ul>
* <li>if-then-(else)-block (IfThenElseBlock)</li>
* <li>(do)-while/for-block (LoopBlock)
* <li>switch-block (SwitchBlock)
* <li>try-catch-finally-block (TryBlock)
* <li>A block consisting of sub blocks (SequentialBlock)
* </ul>
*/
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;
}

@ -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 */");
}
}

@ -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. <p>
*
* 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. <p>
*
* 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;
}

@ -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:
* <ul>
* <li>if-then-(else)-block (IfThenElseBlock)
* <li>(do)-while/for-block (LoopBlock)
* <li>switch-block (SwitchBlock)
* <li>try-catch-block (CatchBlock)
* <li>try-finally-block (FinallyBlock)
* <li>synchronized-block (SynchronizedBlock)
* <li>one-instruction (InstructionBlock)
* <li>empty-block (EmptyBlock)
* <li>multi-blocks-block (SequentialBlock)
* </ul>
*/
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 (<em>not</em> 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;
}
Loading…
Cancel
Save