Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/src/net/sf/jode/flow/FlowBlock.java

1880 lines
64 KiB

/* FlowBlock Copyright (C) 1998-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.flow;
import net.sf.jode.GlobalOptions;
import net.sf.jode.decompiler.TabbedPrintWriter;
import net.sf.jode.decompiler.MethodAnalyzer;
import net.sf.jode.decompiler.LocalInfo;
import net.sf.jode.expr.Expression;
import net.sf.jode.expr.CombineableOperator;
import net.sf.jode.util.SimpleMap;
///#def COLLECTIONS java.util
import java.util.Map;
import java.util.Iterator;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
///#enddef
/**
* 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.
*
* We don't use the notion of basic flow graphs. A flow block may be
* anything from a single bytecode opcode, to the whole method.
*/
public class FlowBlock {
public static FlowBlock END_OF_METHOD;
// public static FlowBlock NEXT_BY_ADDR;
static {
END_OF_METHOD = new FlowBlock(null, Integer.MAX_VALUE, null);
END_OF_METHOD.label = "END_OF_METHOD";
// NEXT_BY_ADDR = new FlowBlock(null, -1);
// NEXT_BY_ADDR.appendBlock(new DescriptionBlock("FALL THROUGH"), 0);
// NEXT_BY_ADDR.label = "NEXT_BY_ADDR";
}
/**
* The method analyzer. This is used to pretty printing the
* Types and to get information about all locals in this code.
*/
MethodAnalyzer 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
*/
private SlotSet in = new SlotSet();
/**
* The gen locals. This are the locals, to which are written
* somewhere in this flow block. This is only used for try
* catch blocks.
*/
VariableSet used = new VariableSet();
/**
* The gen locals. This are the locals, to which are written
* somewhere in this flow block. This is only used for try
* catch blocks.
*/
VariableSet gen = new VariableSet();
/**
* The gen locals. This are the locals, to which are written
* somewhere in this flow block. This is only used for try
* catch blocks.
*/
SlotSet kill = new SlotSet();
/**
* The starting blockNr of this flow block. This is mainly used
* to produce the source code in code order.
*/
private int blockNr;
/**
* The number of flow blocks that were combined into this block so far.
*/
private int length;
/**
* The outermost structructed block in this flow block.
*/
StructuredBlock block;
/**
* The last modified structured block. This is probably the
* last instruction in the outermost block, that is in the
* outermost chain of SequentialBlock.
*/
StructuredBlock lastModified;
/**
* This contains a map of all successing flow blocks and there
* jumps. The key of this map are the flow blocks, while
* the elements is the first jump to that flow block. The other
* jumps are accessible via the jump.next field.
*/
private Map successors = new SimpleMap();
/**
* 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.
*/
List predecessors = new ArrayList();
/**
* This is a pointer to the next flow block in byte code order.
* It is null for the last flow block.
*/
FlowBlock nextByCodeOrder;
/**
* This is a pointer to the previous flow block in byte code order.
* It is null for the first flow block.
*/
FlowBlock prevByCodeOrder;
/**
* The stack map. This tells how many objects are on stack at
* begin of the flow block, and to what locals they are maped.
* @see #mapStackToLocal
*/
VariableStack stackMap;
static class SuccessorInfo {
/**
* The kill locals. This are the slots, which must be
* overwritten in this block on every path to the successor.
* That means, that all paths from the start of the current
* flow block to the successor contain (unconditional)
* assignments to this slot.
*/
SlotSet kill;
/**
* The gen locals. This are the locals, which can be
* overwritten in this block on a path to the successor. That
* means, that there exists a path form the start of the
* current flow block to the successor that contains a
* assignments to this local, and that is not overwritten
* afterwards.
*/
VariableSet gen;
/**
* The linked list of jumps.
*/
Jump jumps;
}
/**
* The default constructor. Creates a new empty flowblock.
*/
public FlowBlock(MethodAnalyzer method, int blockNr, FlowBlock lastFlow) {
this.method = method;
this.blockNr = blockNr;
length = 1;
prevByCodeOrder = lastFlow;
if (lastFlow != null)
lastFlow.nextByCodeOrder = this;
block = new EmptyBlock();
block.setFlowBlock(this);
lastModified = block;
}
public int getNextBlockNr() {
return blockNr + length;
}
public boolean hasNoJumps() {
return successors.size() == 0 && predecessors.size() == 0;
}
/**
* This method resolves some of the jumps to successor.
* @param jumps The list of jumps with that successor.
* @param succ The successing flow block.
* @return The remaining jumps, that couldn't be resolved.
*/
public Jump resolveSomeJumps(Jump jumps, FlowBlock succ) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Resolve: "+this);
/* We will put all jumps that we can not resolve into this
* linked list.
*/
Jump remainingJumps = null;
if (lastModified.jump == null) {
/* This can happen if lastModified is a breakable block, and
* there is no break to it yet. We give lastModified this jump
* as successor since many other routines rely on this.
*/
Jump lastJump = new Jump(succ);
lastModified.setJump(lastJump);
remainingJumps = lastJump;
}
for (Jump jump = jumps; jump != null; jump = jump.next) {
/* First swap all conditional blocks, that have two jumps,
* so that the jump to succ will be on the outside.
*/
if (jump.prev.outer instanceof ConditionalBlock
&& jump.prev.outer.jump != null) {
StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer;
Expression instr = cb.getInstruction();
cb.setInstruction(instr.negate());
cb.swapJump(prev);
}
}
while (jumps != null) {
Jump jump = jumps;
jumps = jumps.next;
/* if the jump is the jump of lastModified, skip it.
*/
if (jump.prev == lastModified) {
jump.next = remainingJumps;
remainingJumps = jump;
continue;
}
/* jump.prev.outer is not null, otherwise jump.prev would
* be lastModified.
*/
if (jump.prev.outer instanceof ConditionalBlock) {
StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer;
Expression instr = cb.getInstruction();
/* This is a jump inside an ConditionalBlock.
*
* cb is the conditional block,
* prev the empty block containing the jump
* instr is the condition */
if (cb.jump != null) {
/* This can only happen if cb also jumps to succ.
* This is a weired "if (cond) empty"-block. We
* transform it by hand.
*/
prev.removeJump();
IfThenElseBlock ifBlock =
new IfThenElseBlock(cb.getInstruction().negate());
ifBlock.moveDefinitions(cb, prev);
ifBlock.replace(cb);
ifBlock.moveJump(cb.jump);
ifBlock.setThenBlock(prev);
if (cb == lastModified)
lastModified = ifBlock;
continue;
}
/* Now cb.jump is null, so cb.outer is not null,
* since otherwise it would have no successor. */
if (cb.outer instanceof LoopBlock
|| (cb.outer instanceof SequentialBlock
&& cb.outer.getSubBlocks()[0] == cb
&& cb.outer.outer instanceof LoopBlock)) {
/* If this is the first instruction of a
* while/for(true) block, make this the loop condition
* (negated of course).
*/
LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ?
(LoopBlock) cb.outer : (LoopBlock) cb.outer.outer;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() != LoopBlock.DOWHILE &&
(loopBlock.jumpMayBeChanged()
|| loopBlock.getNextFlowBlock() == succ)) {
if (loopBlock.jump == null) {
/* consider this jump again */
loopBlock.moveJump(jump);
jumps = jump;
} else
jump.prev.removeJump();
loopBlock.setCondition(instr.negate());
loopBlock.moveDefinitions(cb, null);
cb.removeBlock();
continue;
}
} else if (cb.outer instanceof SequentialBlock
&& cb.outer.getSubBlocks()[1] == cb) {
/* And now for do/while loops, where the jump is
* at the end of the loop.
*/
/* First find the beginning of the loop */
StructuredBlock sb = cb.outer.outer;
while (sb instanceof SequentialBlock) {
sb = sb.outer;
}
/* sb is now the first and cb is the last
* instruction in the current block.
*/
if (sb instanceof LoopBlock) {
LoopBlock loopBlock = (LoopBlock) sb;
if (loopBlock.getCondition() == LoopBlock.TRUE &&
loopBlock.getType() == LoopBlock.WHILE &&
(loopBlock.jumpMayBeChanged()
|| loopBlock.getNextFlowBlock() == succ)) {
if (loopBlock.jump == null) {
/* consider this jump again */
loopBlock.moveJump(jump);
jumps = jump;
} else
jump.prev.removeJump();
loopBlock.setType(LoopBlock.DOWHILE);
loopBlock.setCondition(instr.negate());
loopBlock.moveDefinitions(cb, null);
cb.removeBlock();
continue;
}
}
}
/* This is still a jump inside an ConditionalBlock.
*
* cb is the conditional block,
* prev the empty block containing the jump
* instr is the condition */
/* 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 cond GOTO succ if (!cond)
* \block ===> block
* -> normal Succesor succ -> normal Successor succ
*/
if (cb.outer instanceof SequentialBlock &&
cb.outer.getSubBlocks()[0] == cb &&
(cb.outer.getNextFlowBlock() == succ ||
cb.outer.jumpMayBeChanged())) {
SequentialBlock sequBlock = (SequentialBlock) cb.outer;
IfThenElseBlock newIfBlock
= new IfThenElseBlock(instr.negate());
StructuredBlock thenBlock = sequBlock.getSubBlocks()[1];
newIfBlock.moveDefinitions(sequBlock, thenBlock);
newIfBlock.replace(sequBlock);
newIfBlock.setThenBlock(thenBlock);
if (thenBlock.contains(lastModified)) {
if (lastModified.jump.destination == succ) {
newIfBlock.moveJump(lastModified.jump);
lastModified = newIfBlock;
jump.prev.removeJump();
continue;
}
lastModified = newIfBlock;
}
newIfBlock.moveJump(jump);
// /* consider this jump again */
// jumps = jump;
/* Consider all jumps again, since the ones that moved
* into the thenBlock may be obsolete now.
* XXX only jumps in then should be considered.
*/
if (remainingJumps == null)
jumps = jump;
else {
jumps = remainingJumps;
while (remainingJumps.next != null)
remainingJumps = remainingJumps.next;
remainingJumps.next = jump;
remainingJumps = null;
}
continue;
}
} else {
/* remove this jump if it jumps to the
* getNextFlowBlock(). */
if (jump.destination
== jump.prev.outer.getNextFlowBlock(jump.prev)) {
jump.prev.removeJump();
continue;
}
/* Now find the real outer block, i.e. traverse the
* chain of SequentialBlocks.
*
* Note that only the last instr in a SequentialBlock chain
* can have a jump.
*
* We rely on the fact, that instanceof returns false
* for a null pointer.
*/
StructuredBlock sb = jump.prev.outer;
while (sb instanceof SequentialBlock)
sb = sb.outer;
/* If the block is a catch, go up to the try block.
*/
if (sb instanceof CatchBlock
&& sb.jumpMayBeChanged())
sb = sb.outer;
/* If the block is a synchronized or try block
* and the jump may be changed, move the jump up.
*/
if ((sb instanceof CatchBlock
|| sb instanceof SynchronizedBlock
|| sb instanceof TryBlock)
&& sb.jumpMayBeChanged()) {
sb.moveJump(jump);
/* consider this jump again */
jumps = jump;
continue;
}
/* if this is an unconditional jump at the end of a
* then block belonging to a if-then block without
* else part, and the if block has a jump then replace
* the if-then block with a if-then-else block with an
* else block that contains only the jump and move the
* unconditional jump to the if. (The jump in the else
* block will later probably be replaced with a break,
* continue or return statement.)
*/
if (sb instanceof IfThenElseBlock) {
IfThenElseBlock ifBlock = (IfThenElseBlock) sb;
if (ifBlock.elseBlock == null && ifBlock.jump != null) {
ifBlock.setElseBlock(new EmptyBlock());
ifBlock.elseBlock.moveJump(ifBlock.jump);
ifBlock.moveJump(jump);
/* consider this jump again */
jumps = jump;
continue;
}
}
/* if this is a jump at the end of a then block belonging
* to a if-then block without else part, and the if-then
* block is followed by a single block, then replace the
* if-then block with a if-then-else block and move the
* unconditional jump to the if.
*/
if (sb instanceof IfThenElseBlock
&& sb.outer instanceof SequentialBlock
&& sb.outer.getSubBlocks()[0] == sb) {
IfThenElseBlock ifBlock = (IfThenElseBlock) sb;
SequentialBlock sequBlock = (SequentialBlock) sb.outer;
StructuredBlock elseBlock = sequBlock.subBlocks[1];
if (ifBlock.elseBlock == null
&& (elseBlock.getNextFlowBlock() == succ
|| elseBlock.jump != null
|| elseBlock.jumpMayBeChanged())) {
ifBlock.replace(sequBlock);
ifBlock.setElseBlock(elseBlock);
if (elseBlock.contains(lastModified)) {
if (lastModified.jump.destination == succ) {
ifBlock.moveJump(lastModified.jump);
lastModified = ifBlock;
jump.prev.removeJump();
continue;
}
lastModified = ifBlock;
}
ifBlock.moveJump(jump);
/* Consider all jumps again, since the ones that moved
* into the thenBlock may be obsolete now.
* XXX only jumps in then should be considered.
* XXX I'm not sure if this is complete.
*/
if (remainingJumps == null)
jumps = jump;
else {
jumps = remainingJumps;
while (remainingJumps.next != null)
remainingJumps = remainingJumps.next;
remainingJumps.next = jump;
remainingJumps = null;
}
continue;
}
}
}
/* if this is a jump in a breakable block, and that block
* has not yet a next block, then create a new jump to that
* successor.
*
* The break to the block will be generated later.
*/
for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null; surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
if (surrounder.getNextFlowBlock() == succ)
/* We can break to that block; this is done later. */
break;
if (surrounder.jumpMayBeChanged()) {
surrounder.setJump(new Jump(succ));
/* put surrounder in todo list */
surrounder.jump.next = jumps;
jumps = surrounder.jump;
/* The break is inserted later */
break;
}
if (succ == END_OF_METHOD) {
/* If the jump can be replaced by a return
* we won't do labeled breaks, so we must
* stop here
*/
break;
}
}
}
jump.next = remainingJumps;
remainingJumps = jump;
}
return remainingJumps;
}
/**
* Resolve remaining jumps to the successor by generating break
* instructions. As last resort generate a do while(false) block.
* @param jumps The jump list that need to be resolved.
*/
void resolveRemaining(Jump jumps) {
LoopBlock doWhileFalse = null;
StructuredBlock outerMost = lastModified;
boolean removeLast = false;
for (; jumps != null; jumps = jumps.next) {
StructuredBlock prevBlock = jumps.prev;
if (prevBlock == lastModified) {
/* handled below */
removeLast = true;
continue;
}
int breaklevel = 0;
BreakableBlock breakToBlock = null;
for (StructuredBlock surrounder = prevBlock.outer;
surrounder != null; surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
breaklevel++;
if (surrounder.getNextFlowBlock() == jumps.destination) {
breakToBlock = (BreakableBlock) surrounder;
break;
}
}
}
prevBlock.removeJump();
if (breakToBlock == null) {
/* Nothing else helped, so put a do/while(0)
* block around outerMost and break to that
* block.
*/
if (doWhileFalse == null) {
doWhileFalse = new LoopBlock(LoopBlock.DOWHILE,
LoopBlock.FALSE);
}
/* Adapt outermost, so that it contains the break. */
while (!outerMost.contains(prevBlock))
outerMost = outerMost.outer;
prevBlock.appendBlock
(new BreakBlock(doWhileFalse, breaklevel > 0));
} else
prevBlock.appendBlock
(new BreakBlock(breakToBlock, breaklevel > 1));
}
if (removeLast)
lastModified.removeJump();
if (doWhileFalse != null) {
doWhileFalse.replace(outerMost);
doWhileFalse.setBody(outerMost);
lastModified = doWhileFalse;
}
}
/**
* Move the successors of the given flow block to this flow block.
* @param succ the other flow block
*/
void mergeSuccessors(FlowBlock succ) {
/* Merge the successors from the successing flow block
*/
Iterator iter = succ.successors.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
FlowBlock dest = (FlowBlock) entry.getKey();
SuccessorInfo hisInfo = (SuccessorInfo) entry.getValue();
SuccessorInfo myInfo = (SuccessorInfo) successors.get(dest);
if (dest != END_OF_METHOD)
dest.predecessors.remove(succ);
if (myInfo == null) {
if (dest != END_OF_METHOD)
dest.predecessors.add(this);
successors.put(dest, hisInfo);
} else {
myInfo.gen.addAll(hisInfo.gen);
myInfo.kill.retainAll(hisInfo.kill);
Jump myJumps = myInfo.jumps;
while (myJumps.next != null)
myJumps = myJumps.next;
myJumps.next = hisInfo.jumps;
}
}
}
/**
* Fixes the blockNr chained list, after merging this block with succ.
*/
public void mergeBlockNr(FlowBlock succ) {
if (succ.nextByCodeOrder == this || succ.prevByCodeOrder == null) {
/* Merge succ with its nextByCodeOrder.
* Note: succ.nextByCodeOrder != null, since this is on the
* nextByCodeOrder chain. */
succ.nextByCodeOrder.blockNr = succ.blockNr;
succ.nextByCodeOrder.length += succ.length;
succ.nextByCodeOrder.prevByCodeOrder = succ.prevByCodeOrder;
if (succ.prevByCodeOrder != null)
succ.prevByCodeOrder.nextByCodeOrder = succ.nextByCodeOrder;
} else {
/* Merge succ with its prevByCodeOrder */
succ.prevByCodeOrder.length += succ.length;
succ.prevByCodeOrder.nextByCodeOrder = succ.nextByCodeOrder;
if (succ.nextByCodeOrder != null)
succ.nextByCodeOrder.prevByCodeOrder = succ.prevByCodeOrder;
}
}
/**
* Updates the gen/kill Sets of all jumps in this block.
* @param gens The locals in this block that are visible at the
* begin of successor.
* @param kills The slots that are always overwritten on the way to
* successor. This may be null.
* @return The variables that must be defined * in this block.
*/
void updateGenKill(VariableSet gens, SlotSet kills) {
/* Merge the locals used in successing block with those written
* by this blocks.
*/
in.merge(gens);
/* The gen/kill sets must be updated for every jump
* in the other block */
Iterator i = successors.values().iterator();
while (i.hasNext()) {
SuccessorInfo succInfo = (SuccessorInfo) i.next();
succInfo.gen.mergeGenKill(gens, succInfo.kill);
if (kills != null)
succInfo.kill.mergeKill(kills);
}
}
/**
* Updates the in/out-Vectors of the structured block of the
* successing flow block simultanous to a T2 transformation.
* @param successor The flow block which is unified with this flow
* block.
* @param gens The locals in this block that are visible at the
* begin of successor.
* @param kills The slots that are always overwritten on the way to
* successor.
* @return The variables that must be defined in this block.
*/
void updateInOut(FlowBlock successor, VariableSet gens, SlotSet kills) {
successor.updateGenKill(gens, kills);
/* The ins of the successor that are not killed
* (i.e. unconditionally overwritten) by this block are new
* ins for this block.
*/
SlotSet newIn = (SlotSet) successor.in.clone();
newIn.removeAll(kills);
this.in.addAll(newIn);
this.used.addAll(successor.used);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) {
GlobalOptions.err.println("UpdateInOut: gens : "+gens);
GlobalOptions.err.println(" kills: "+kills);
GlobalOptions.err.println(" s.in : "+successor.in);
GlobalOptions.err.println(" in : "+in);
}
}
/**
* Updates the in/out-Vectors of the structured block of the
* successing flow block for a try catch block. The main difference
* to updateInOut in FlowBlock is, that this function works, as if
* every instruction would have a jump. This is because every
* instruction can throw an exception and thus enter the catch block.<br>
*
* For example this code prints <code>0</code>:
* <pre>
* int a=3;
* try {
* a = 5 / (a=0);
* } catch (DivideByZeroException ex) {
* System.out.println(a);
* }
* </pre>
*
* @param successor The flow block which is unified with this flow
* block.
* @return The variables that must be defined in this block.
*/
public void updateInOutCatch (FlowBlock catchFlow) {
VariableSet gens = ((TryBlock)block).gen;
/* Merge the locals used in the catch block with those written
* by the try block
*/
catchFlow.in.merge(gens);
/* The gen/kill sets must be updated for every jump
* in the other block */
Iterator i = catchFlow.successors.values().iterator();
while (i.hasNext()) {
SuccessorInfo succSuccInfo = (SuccessorInfo) i.next();
succSuccInfo.gen.mergeGenKill(gens, succSuccInfo.kill);
}
in.addAll(catchFlow.in);
used.addAll(catchFlow.used);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) {
GlobalOptions.err.println("UpdateInOutCatch: gens : "+gens);
GlobalOptions.err.println(" s.in : "+catchFlow.in);
GlobalOptions.err.println(" in : "+in);
}
}
/**
* Checks if the FlowBlock and its StructuredBlocks are
* consistent. There are to many conditions to list them
* here, the best way is to read this function and all other
* checkConsistent functions.
*/
public void checkConsistent() {
/* This checks are very time consuming, so don't do them
* normally.
*/
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_CHECK) == 0)
return;
try {
if (block.outer != null || block.flowBlock != this) {
throw new InternalError("Inconsistency: outer:" + block.outer
+ " block.flow"+block.flowBlock
+ " this: "+this);
}
block.checkConsistent();
for (Iterator i = predecessors.iterator(); i.hasNext(); ) {
FlowBlock pred = (FlowBlock)i.next();
if (pred == null)
/* The special start marker */
continue;
if (!pred.successors.containsKey(this))
throw new InternalError
("Inconsistency: "+pred.getLabel()+" not in "
+this.getLabel()+".successors");
}
StructuredBlock last = lastModified;
while (last.outer instanceof SequentialBlock
|| last.outer instanceof TryBlock
|| last.outer instanceof FinallyBlock)
last = last.outer;
if (last.outer != null)
throw new InternalError
("Inconsistency: last "+lastModified
+" surrounded by unexpected structure");
Iterator iter = successors.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
FlowBlock dest = (FlowBlock) entry.getKey();
if (dest.predecessors.contains(this) == (dest == END_OF_METHOD))
throw new InternalError
("Inconsistency: dest "+dest.getLabel()
+" doesn't contain this predecessor");
Jump jumps = ((SuccessorInfo) entry.getValue()).jumps;
if (jumps == null)
throw new InternalError("Inconsistency: no jumps for "
+dest.getLabel());
for (; jumps != null; jumps = jumps.next) {
if (jumps.destination != dest)
throw new InternalError("Inconsistency:" +jumps
+ "doesn't point to "
+dest.getLabel());
if (jumps.prev == null
|| jumps.prev.flowBlock != this
|| jumps.prev.jump != jumps)
throw new InternalError("Inconsistency in" +jumps);
prev_loop:
for (StructuredBlock prev = jumps.prev; prev != block;
prev = prev.outer) {
if (prev.outer == null)
throw new InternalError("Inconsistency: " +prev
+" not in flowblock");
StructuredBlock[] blocks = prev.outer.getSubBlocks();
int i;
for (i=0; i<blocks.length; i++)
if (blocks[i] == prev)
continue prev_loop;
throw new InternalError("Inconsistency: " +prev
+" not in its outer block "
+prev.outer);
}
}
}
} catch (InternalError err) {
GlobalOptions.err.println("Inconsistency in: "+this);
throw err;
}
}
public void prependBlock(StructuredBlock insertBlock) {
lastModified = block = insertBlock.appendBlock(block);
SlotSet blockIn = new SlotSet();
SlotSet blockKill = new SlotSet();
VariableSet blockGen = new VariableSet();
insertBlock.fillInGenSet(blockIn, blockKill);
blockGen.addAll(blockKill);
updateGenKill(blockGen, blockKill);
in.removeAll(blockKill);
in.addAll(blockIn);
used.addAll(blockGen);
doTransformations();
checkConsistent();
}
public void appendReadBlock(StructuredBlock newBlock, LocalInfo local) {
used.add(local);
if (!kill.contains(local))
in.add(local);
gen.mergeRead(local);
kill.mergeKill(local);
newBlock.setFlowBlock(this);
lastModified = lastModified.appendBlock(newBlock);
doTransformations();
checkConsistent();
}
public void appendWriteBlock(StructuredBlock newBlock, LocalInfo local) {
used.add(local);
gen.mergeWrite(local);
kill.mergeKill(local);
newBlock.setFlowBlock(this);
lastModified = lastModified.appendBlock(newBlock);
doTransformations();
checkConsistent();
}
public void appendBlock(StructuredBlock newBlock) {
newBlock.setFlowBlock(this);
lastModified = lastModified.appendBlock(newBlock);
doTransformations();
checkConsistent();
}
public void oldAppendBlock(StructuredBlock newBlock) {
SlotSet blockIn = new SlotSet();
SlotSet blockKill = new SlotSet();
VariableSet blockGen = new VariableSet();
newBlock.setFlowBlock(this);
newBlock.fillInGenSet(blockIn, blockKill);
this.used.addAll(blockKill);
blockGen.addAll(blockKill);
/* Merge the locals used in new block with those written
* by this blocks.
*/
blockIn.merge(this.gen);
blockGen.mergeGenKill(this.gen, blockKill);
blockKill.mergeKill(this.kill);
blockIn.removeAll(this.kill);
this.in.addAll(blockIn);
this.gen = blockGen;
this.kill = blockKill;
lastModified = lastModified.appendBlock(newBlock);
checkConsistent();
doTransformations();
checkConsistent();
}
public void setSuccessors(FlowBlock[] succs) {
Jump[] jumps = new Jump[succs.length];
for (int i=0; i< succs.length; i++) {
Jump jump = new Jump(succs[i]);
SuccessorInfo info = (SuccessorInfo) successors.get(succs[i]);
if (info == null) {
info = new SuccessorInfo();
info.gen = (VariableSet) gen.clone();
info.kill = (SlotSet) kill.clone();
info.jumps = jump;
if (jump.destination != END_OF_METHOD)
jump.destination.predecessors.add(this);
successors.put(succs[i], info);
} else {
jump.next = info.jumps;
info.jumps = jump;
}
jumps[i] = jump;
}
if (jumps.length > 0)
lastModified.setSuccessors(jumps);
gen = null;
kill = null;
checkConsistent();
}
/**
* Do a T2 transformation with succ if possible. It is possible,
* iff succ has exactly this block as predecessor.
* @param succ the successor block, must be a valid successor of this
* block, i.e. not null
*/
public boolean doT2(FlowBlock succ) {
/* check if this successor has only this block as predecessor.
* if the predecessor is not unique, return false. */
if (succ.predecessors.size() != 1 ||
succ.predecessors.get(0) != this)
return false;
checkConsistent();
succ.checkConsistent();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("T2(["+blockNr+","+getNextBlockNr()+"],["
+succ.blockNr+","+succ.getNextBlockNr()+"])");
SuccessorInfo succInfo = (SuccessorInfo) successors.remove(succ);
/* Update the in/out-Vectors now */
updateInOut(succ, succInfo.gen, succInfo.kill);
/* Try to eliminate as many jumps as possible.
*/
Jump jumps = resolveSomeJumps(succInfo.jumps, succ);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Remaining: "+this);
resolveRemaining(jumps);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("after Resolve: "+this);
/* Now unify the blocks.
*/
lastModified = lastModified.appendBlock(succ.block);
mergeSuccessors(succ);
/* This will also set last modified to the new correct value. */
doTransformations();
/* Set blockNr and length to correct value and update nextByCodeOrder */
mergeBlockNr(succ);
/* T2 transformation succeeded */
checkConsistent();
return true;
}
/**
* Do a T2 transformation with the end_of_method block.
*/
public void mergeEndBlock() {
checkConsistent();
SuccessorInfo endInfo
= (SuccessorInfo) successors.remove(END_OF_METHOD);
if (endInfo == null)
return;
Jump allJumps = endInfo.jumps;
/* First remove all implicit jumps to the END_OF_METHOD block.
*/
Jump jumps = null;
for (; allJumps != null; ) {
Jump jump = allJumps;
allJumps = allJumps.next;
if (jump.prev instanceof ReturnBlock) {
/* This jump is implicit */
jump.prev.removeJump();
continue;
}
jump.next = jumps;
jumps = jump;
}
/* Try to eliminate as many jumps as possible.
*/
jumps = resolveSomeJumps(jumps, END_OF_METHOD);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before remaining: "+this);
for (; jumps != null; jumps = jumps.next) {
StructuredBlock prevBlock = jumps.prev;
if (lastModified == prevBlock)
/* handled later */
continue;
BreakableBlock breakToBlock = null;
for (StructuredBlock surrounder = prevBlock.outer;
surrounder != null; surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
if (surrounder.getNextFlowBlock() == END_OF_METHOD)
breakToBlock = (BreakableBlock) surrounder;
/* We don't want labeled breaks, because we can
* simply return. */
break;
}
}
prevBlock.removeJump();
if (breakToBlock == null)
/* The successor is the dummy return instruction, so
* replace the jump with a return.
*/
prevBlock.appendBlock(new ReturnBlock());
else
prevBlock.appendBlock
(new BreakBlock(breakToBlock, false));
}
/* Now remove the jump of the lastModified if it points to
* END_OF_METHOD.
*/
if (lastModified.jump.destination == END_OF_METHOD)
lastModified.removeJump();
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Transformation: "+this);
doTransformations();
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("after Transformation: "+this);
/* transformation succeeded */
checkConsistent();
}
public boolean doT1(int start, int end) {
/* If there are no jumps to the beginning of this flow block
* or if this block has other predecessors with a not yet
* considered block number, return false. The second condition
* make sure that not for each continue a while is created.
*/
if (!predecessors.contains(this))
return false;
for (Iterator i = predecessors.iterator(); i.hasNext(); ) {
FlowBlock predFlow = (FlowBlock) i.next();
if (predFlow != null && predFlow != this
&& predFlow.blockNr >= start && predFlow.blockNr < end) {
return false;
}
}
checkConsistent();
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println("T1(["+blockNr+","+getNextBlockNr()+"])");
SuccessorInfo succInfo = (SuccessorInfo) successors.remove(this);
/* Update the in/out-Vectors now */
updateGenKill(succInfo.gen, null);
Jump jumps = succInfo.jumps;
StructuredBlock bodyBlock = block;
/* If there is only one jump to the beginning and it is
* the last jump (lastModified) 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 to for. */
boolean createdForBlock = false;
if (jumps.next == null
&& jumps.prev == lastModified
&& lastModified instanceof InstructionBlock
&& ((InstructionBlock)lastModified).getInstruction().isVoid()) {
if (lastModified.outer instanceof SequentialBlock
&& lastModified.outer.getSubBlocks()[0]
instanceof LoopBlock) {
LoopBlock lb =
(LoopBlock) lastModified.outer.getSubBlocks()[0];
if (lb.cond == LoopBlock.FALSE && lb.type == LoopBlock.DOWHILE) {
/* The jump is directly following a
* do-while(false) block
*
* Remove do/while, create a for(;;last_instr)
* and replace break to that block with
* continue to for.
*/
lastModified.removeJump();
LoopBlock forBlock =
new LoopBlock(LoopBlock.FOR, LoopBlock.TRUE);
forBlock.replace(bodyBlock);
forBlock.setBody(bodyBlock);
forBlock.incrInstr
= ((InstructionBlock) lastModified).getInstruction();
forBlock.replaceBreakContinue(lb);
lb.bodyBlock.replace(lastModified.outer);
createdForBlock = true;
}
}
if (!createdForBlock
&& (((InstructionBlock) lastModified).getInstruction()
instanceof CombineableOperator)) {
/* The only jump is the jump of the last
* instruction lastModified, there is a big
* chance, that this is a for block, but we
* can't be sure until we have seen the condition.
* We will transform it to a for block, and take
* that back, when we get a non matching condition.
*/
lastModified.removeJump();
LoopBlock forBlock =
new LoopBlock(LoopBlock.POSSFOR, LoopBlock.TRUE);
forBlock.replace(bodyBlock);
forBlock.setBody(bodyBlock);
forBlock.incrBlock = (InstructionBlock) lastModified;
createdForBlock = true;
}
}
if (!createdForBlock) {
/* Creating a for block didn't succeed; create a
* while block instead. */
/* Try to eliminate as many jumps as possible.
*/
jumps = resolveSomeJumps(jumps, this);
LoopBlock whileBlock =
new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE);
/* The block may have been changed above. */
bodyBlock = block;
whileBlock.replace(bodyBlock);
whileBlock.setBody(bodyBlock);
/* if there are further jumps to this, replace every jump with a
* continue to while block and return true.
*/
for (; jumps != null; jumps = jumps.next) {
if (jumps.prev == lastModified)
/* handled later */
continue;
StructuredBlock prevBlock = jumps.prev;
int breaklevel = 0, continuelevel = 0;
BreakableBlock breakToBlock = null;
for (StructuredBlock surrounder = prevBlock.outer;
surrounder != whileBlock;
surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) {
if (surrounder instanceof LoopBlock)
continuelevel++;
breaklevel++;
if (surrounder.getNextFlowBlock() == this) {
breakToBlock = (BreakableBlock) surrounder;
break;
}
}
}
prevBlock.removeJump();
if (breakToBlock == null)
prevBlock.appendBlock
(new ContinueBlock(whileBlock, continuelevel > 0));
else
prevBlock.appendBlock
(new BreakBlock(breakToBlock, breaklevel > 1));
}
/* Now remove the jump of lastModified if it points to this.
*/
if (lastModified.jump != null
&& lastModified.jump.destination == this)
lastModified.removeJump();
}
/* remove ourself from the predecessor list.
*/
predecessors.remove(this);
lastModified = block;
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Transformation: "+this);
doTransformations();
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("after Transformation: "+this);
/* T1 analysis succeeded */
checkConsistent();
return true;
}
public void doTransformations() {
while (lastModified instanceof SequentialBlock) {
if (lastModified.getSubBlocks()[0].doTransformations())
continue;
lastModified = lastModified.getSubBlocks()[1];
}
while (lastModified.doTransformations())
{ /* empty */ }
}
/**
* Search for an apropriate successor.
* @param prevSucc The successor, that was previously tried.
* @param start The minimum blockNr
* @param end The maximum blockNr + 1.
* @return the successor with smallest block number greater than prevSucc
* or null if there isn't any further successor at all.
*/
FlowBlock getSuccessor(int start, int end) {
/* search successor with smallest blockNr. */
Iterator keys = successors.keySet().iterator();
FlowBlock succ = null;
while (keys.hasNext()) {
FlowBlock fb = (FlowBlock) keys.next();
if (fb.blockNr < start || fb.blockNr >= end || fb == this)
continue;
if (succ == null || fb.blockNr < succ.blockNr) {
succ = fb;
}
}
return succ;
}
/**
* The main analyzation. This calls doT1 and doT2 on apropriate
* regions until the whole function is transformed to a single
* block.
*/
public void analyze() {
while (analyze(0, Integer.MAX_VALUE))
{ }
mergeEndBlock();
}
/**
* The main analyzation. This calls doT1 and doT2 on apropriate
* regions. Only blocks whose block number lies in the given block number
* range are considered.
* @param start the start of the block number range.
* @param end the end of the block number range.
*/
public boolean analyze(int start, int end) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println("analyze("+start+", "+end+")");
checkConsistent();
boolean changed = false;
while (true) {
if (lastModified instanceof SwitchBlock) {
/* analyze the switch first.
*/
changed |= analyzeSwitch(start, end);
}
/* Do T1 analysis when there is a loop, but only if:
* - the loop has only one exit (plus returns)
* - or the successor block doesn't belong to the loop.
*
* The reason for the extra checks are loops like
*
* while (x)
* ...
* if (y)
* ...
* return
*
* which would otherwise be translated to:
*
* outer: do {
* do {
* if (!x) break outer;
* ...
* } while(!y)
* ...
* return
* } while(false)
*/
if (successors.containsKey(this)
&& (!successors.containsKey(nextByCodeOrder)
|| successors.size() == 2
|| (successors.size() == 3
&& successors.containsKey(END_OF_METHOD)))
&& doT1(start, end)) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("after T1: "+this);
/* T1 transformation succeeded. This may
* make another T2 analysis in the previous
* block possible.
*/
return true;
}
FlowBlock succ = getSuccessor(start, end);
while (true) {
if (succ == null) {
/* the Block has no successor where T2 is applicable.
* Finish this analyzation.
*/
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("No more successors applicable: "
+ start + " - " + end + "; "
+ blockNr + " - " + getNextBlockNr());
return changed;
} else if ((nextByCodeOrder == succ
|| succ.nextByCodeOrder == this)
/* Only do T2 transformation if the blocks are
* adjacent.
*/
&& doT2(succ)) {
/* T2 transformation succeeded. */
changed = true;
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("after T2: "+this);
break;
} else {
/* Check if all predecessors of either succ or this
* block lie in range [start,end). Otherwise
* we have no chance to combine these two blocks.
*/
for (Iterator i = succ.predecessors.iterator();
i.hasNext(); ) {
FlowBlock pred = (FlowBlock)i.next();
if (pred == null /* the start marker */
|| pred.blockNr < start || pred.blockNr >= end) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("breaking analyze("
+ start + ", " + end + "); "
+ blockNr + " - " + getNextBlockNr());
return changed;
}
}
/* analyze succ, the new region is the
* continuous region of
* [start,end) \cap \compl [blockNr, getNextBlockNr())
* where succ.blockNr lies in.
*/
int newStart = (succ.blockNr > blockNr)
? getNextBlockNr() : start;
int newEnd = (succ.blockNr > blockNr)
? end : blockNr;
if (succ.analyze(newStart, newEnd))
break;
}
/* Try the next successor.
*/
succ = getSuccessor(succ.blockNr+1, end);
}
}
}
/**
* The switch analyzation. This calls doSwitchT2 and doT1 on apropriate
* regions. Only blocks whose block number lies in the given block number
* range are considered and it is taken care of, that the switch
* is never left. <p>
* The current flow block must contain the switch block as lastModified.
* @param start the start of the block number range.
* @param end the end of the block number range.
*/
public boolean analyzeSwitch(int start, int end) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println("analyzeSwitch("+start+", "+end+")");
SwitchBlock switchBlock = (SwitchBlock) lastModified;
boolean changed = false;
int last = -1;
FlowBlock lastFlow = null;
for (int i=0; i < switchBlock.caseBlocks.length; i++) {
if (switchBlock.caseBlocks[i].subBlock instanceof EmptyBlock
&& switchBlock.caseBlocks[i].subBlock.jump != null) {
FlowBlock nextFlow = switchBlock.caseBlocks[i].
subBlock.jump.destination;
if (nextFlow.blockNr >= end)
break;
else if (nextFlow.blockNr >= start) {
/* First analyze the nextFlow block. It may
* return early after a T1 trafo so call it
* until nothing more is possible.
*/
while (nextFlow.analyze(getNextBlockNr(), end))
changed = true;
if (nextFlow.blockNr != getNextBlockNr())
break;
/* Check if nextFlow has only the previous case
* and this case as predecessor. Otherwise
* break the analysis.
*/
if (nextFlow.predecessors.size() > 2
|| (nextFlow.predecessors.size() > 1
&& (lastFlow == null
|| !nextFlow.predecessors.contains(lastFlow)))
|| (((SuccessorInfo)successors.get(nextFlow))
.jumps.next != null))
break;
checkConsistent();
/* note that this info only contains
* the single caseBlock jump */
SuccessorInfo info = (SuccessorInfo)
successors.remove(nextFlow);
if (nextFlow.predecessors.size() == 2) {
SuccessorInfo lastInfo = (SuccessorInfo)
lastFlow.successors.remove(nextFlow);
/* Do the in/out analysis with all jumps
* Note that this won't update lastFlow.in, but
* this will not be used anymore.
*/
info.kill.retainAll(lastInfo.kill);
info.gen.addAll(lastInfo.gen);
Jump lastJumps = lastFlow.resolveSomeJumps
(lastInfo.jumps, nextFlow);
lastFlow.resolveRemaining(lastJumps);
switchBlock.caseBlocks[last+1].isFallThrough = true;
}
updateInOut(nextFlow, info.gen, info.kill);
if (lastFlow != null) {
lastFlow.block.replace
(switchBlock.caseBlocks[last].subBlock);
mergeSuccessors(lastFlow);
}
/* We merge the blocks into the caseBlock later, but
* that doesn't affect consistency.
*/
switchBlock.caseBlocks[i].subBlock.removeJump();
mergeBlockNr(nextFlow);
lastFlow = nextFlow;
last = i;
checkConsistent();
changed = true;
}
}
}
if (lastFlow != null) {
lastFlow.block.replace
(switchBlock.caseBlocks[last].subBlock);
mergeSuccessors(lastFlow);
}
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("after analyzeSwitch: "+this);
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeSwitch done: " + start + " - " + end + "; "
+ blockNr + " - " + getNextBlockNr());
checkConsistent();
return changed;
}
/**
* Mark the flow block as first flow block in a method.
*/
public void addStartPred() {
predecessors.add(null);
}
public void removeStartPred() {
predecessors.remove(null);
}
public void removeSuccessor(Jump jump) {
SuccessorInfo destInfo
= (SuccessorInfo) successors.get(jump.destination);
Jump prev = null;
Jump destJumps = destInfo.jumps;
while (destJumps != jump && destJumps != null) {
prev = destJumps;
destJumps = destJumps.next;
}
if (destJumps == null)
throw new IllegalArgumentException
(blockNr+": removing non existent jump: " + jump);
if (prev != null)
prev.next = destJumps.next;
else {
if (destJumps.next == null) {
successors.remove(jump.destination);
jump.destination.predecessors.remove(this);
} else
destInfo.jumps = destJumps.next;
}
}
public Jump getJumps(FlowBlock dest) {
return ((SuccessorInfo) successors.get(dest)).jumps;
}
public Jump removeJumps(FlowBlock dest) {
if (dest != END_OF_METHOD)
dest.predecessors.remove(this);
return ((SuccessorInfo) successors.remove(dest)).jumps;
}
public Set getSuccessors() {
return successors.keySet();
}
// public void addSuccessor(Jump jump) {
// SuccessorInfo info = (SuccessorInfo) successors.get(jump.destination);
// if (info == null) {
// info = new SuccessorInfo();
// info.jumps = jump;
// if (jump.destination != END_OF_METHOD)
// jump.destination.predecessors.add(this);
// successors.put(jump.destination, info);
// } else {
// jump.next = info.jumps;
// info.jumps = jump;
// }
// }
/**
* This is called after the analysis is completely done. It
* will remove all PUSH/stack_i expressions, (if the bytecode
* is correct).
* @return true, if the stack mapping succeeded.
*/
public final boolean mapStackToLocal() {
mapStackToLocal(VariableStack.EMPTY);
return true;
}
/**
* This is called after the analysis is completely done. It
* will remove all PUSH/stack_i expressions, (if the bytecode
* is correct).
* @param initialStack the stackmap at begin of the flow block
* @return false if the bytecode isn't correct and stack mapping
* didn't worked.
*/
public void mapStackToLocal(VariableStack initialStack) {
if (initialStack == null)
throw new InternalError("initial stack is null");
stackMap = initialStack;
block.mapStackToLocal(initialStack);
Iterator iter = successors.values().iterator();
while (iter.hasNext()) {
SuccessorInfo succInfo = (SuccessorInfo) iter.next();
Jump jumps = succInfo.jumps;
VariableStack stack;
FlowBlock succ = jumps.destination;
if (succ == END_OF_METHOD)
continue;
stack = succ.stackMap;
for (/**/; jumps != null; jumps = jumps.next) {
if (jumps.stackMap == null)
GlobalOptions.err.println("Dead jump? "+jumps.prev
+" in "+this);
stack = VariableStack.merge(stack, jumps.stackMap);
}
if (succ.stackMap == null)
succ.mapStackToLocal(stack);
}
}
public void removePush() {
if (stackMap == null)
/* already done or mapping didn't succeed */
return;
stackMap = null;
block.removePush();
Iterator iter = successors.keySet().iterator();
while (iter.hasNext()) {
FlowBlock succ = (FlowBlock)iter.next();
succ.removePush();
}
}
public void removeOnetimeLocals() {
block.removeOnetimeLocals();
if (nextByCodeOrder != null)
nextByCodeOrder.removeOnetimeLocals();
}
private void promoteInSets() {
for (Iterator i = predecessors.iterator(); i.hasNext(); ) {
FlowBlock pred = (FlowBlock) i.next();
/* Skip the start marker */
if (pred == null)
continue;
SuccessorInfo succInfo = (SuccessorInfo) pred.successors.get(this);
/* First get the gen/kill sets of all jumps of predecessor
* to this block and calculate the intersection.
*/
VariableSet gens = succInfo.gen;
SlotSet kills = succInfo.kill;
/* Merge in locals of this block with those condionally
* written by previous blocks */
in.merge(gens);
/* The ins of the successor that are not killed
* (i.e. unconditionally overwritten) by this block are new
* ins for this block.
*/
SlotSet newIn = (SlotSet) in.clone();
newIn.removeAll(kills);
if (pred.in.addAll(newIn))
pred.promoteInSets();
}
if (nextByCodeOrder != null)
nextByCodeOrder.promoteInSets();
}
/**
* Merge the parameter locals with the in set of this flow block.
* This will also make a successive analysis to merge the gen/kill
* set of the jumps with the next flow block. */
public void mergeParams(LocalInfo[] param) {
// Now we promote the final (maybe slow) in set analysis
promoteInSets();
VariableSet paramSet = new VariableSet(param);
in.merge(paramSet);
}
/**
* Make declarations. It will determine, where in each block the
* variables and method scoped classes must be declared.
*/
public void makeDeclaration(Set done) {
block.propagateUsage();
block.makeDeclaration(done);
if (nextByCodeOrder != null)
nextByCodeOrder.makeDeclaration(done);
}
/**
* Simplify this and all following flowblocks.
*/
public void simplify() {
block.simplify();
if (nextByCodeOrder != null)
nextByCodeOrder.simplify();
}
/**
* 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(TabbedPrintWriter writer)
throws java.io.IOException
{
if (predecessors.size() != 0) {
writer.untab();
writer.println(getLabel()+":");
writer.tab();
}
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) {
writer.println("in: "+in);
}
block.dumpSource(writer);
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INOUT) != 0) {
Iterator iter = successors.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
FlowBlock dest = (FlowBlock) entry.getKey();
SuccessorInfo info = (SuccessorInfo) entry.getValue();
writer.println("successor: "+dest.getLabel()
+" gen : "+ info.gen
+" kill: "+ info.kill);
}
}
if (nextByCodeOrder != null)
nextByCodeOrder.dumpSource(writer);
}
/**
* The serial number for labels.
*/
static int serialno = 0;
/**
* The label of this instruction, or null if it needs no label.
*/
String label = null;
/**
* Returns the block number, where the code in this flow block starts.
*/
public int getBlockNr() {
return blockNr;
}
/**
* Returns the label of this block and creates a new label, if
* there wasn't a label previously.
*/
public String getLabel() {
if (label == null)
label = "flow_"+blockNr+"_"+(serialno++)+"_";
return label;
}
/**
* Returns the structured block, that this flow block contains.
*/
public StructuredBlock getBlock() {
return block;
}
public String toString() {
try {
java.io.StringWriter strw = new java.io.StringWriter();
TabbedPrintWriter writer = new TabbedPrintWriter(strw);
writer.println(super.toString() + ": "+blockNr);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) {
writer.println("in: "+in);
}
writer.tab();
block.dumpSource(writer);
writer.untab();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INOUT) != 0) {
Iterator iter = successors.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
FlowBlock dest = (FlowBlock) entry.getKey();
SuccessorInfo info = (SuccessorInfo) entry.getValue();
writer.println("successor: "+dest.getLabel()
+" gen : "+ info.gen
+" kill: "+ info.kill);
}
}
return strw.toString();
} catch (RuntimeException ex) {
return super.toString();
} catch (java.io.IOException ex) {
return super.toString();
}
}
}