Mirror of the BLOAT repository
https://www.cs.purdue.edu/homes/hosking/bloat/
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.
774 lines
21 KiB
774 lines
21 KiB
/**
|
|
* All files in the distribution of BLOAT (Bytecode Level Optimization and
|
|
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
|
|
* Research Foundation of Purdue University. All rights reserved.
|
|
*
|
|
* This library 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.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package EDU.purdue.cs.bloat.codegen;
|
|
|
|
import java.util.*;
|
|
|
|
import EDU.purdue.cs.bloat.cfg.*;
|
|
import EDU.purdue.cs.bloat.tree.*;
|
|
import EDU.purdue.cs.bloat.util.*;
|
|
|
|
/**
|
|
* Liveness represents the interference graph of the local variables contained
|
|
* in a control flow graph.
|
|
*
|
|
* When the liveness of two variables overlap each other, the two variables are
|
|
* said to <i>interfere</i> with each other. The interference graph represents
|
|
* this relationship between variables. There is an (un-directed) edge between
|
|
* variables <tt>a</tt> and <tt>b</tt> in the interference graph if variable
|
|
* <tt>a</tt> interferes with variable <tt>b</tt>.
|
|
*/
|
|
public class Liveness {
|
|
public static boolean DEBUG = false;
|
|
|
|
public static boolean UNIQUE = false;
|
|
|
|
public static final boolean BEFORE = false;
|
|
|
|
public static final boolean AFTER = true;
|
|
|
|
FlowGraph cfg;
|
|
|
|
Graph ig;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param cfg
|
|
* Control flow graph on which to perform liveness analysis.
|
|
*/
|
|
public Liveness(final FlowGraph cfg) {
|
|
this.cfg = cfg;
|
|
computeIntersections();
|
|
}
|
|
|
|
/**
|
|
* Removes a local expression from the interference graph.
|
|
*/
|
|
public void removeVar(final LocalExpr expr) {
|
|
ig.removeNode(expr);
|
|
}
|
|
|
|
/**
|
|
* Should not be called.
|
|
*/
|
|
public boolean liveAtUse(final VarExpr isLive, final VarExpr at,
|
|
final boolean after) {
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
/**
|
|
* Should not be called.
|
|
*/
|
|
public boolean liveAtStartOfBlock(final VarExpr isLive, final Block block) {
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
/**
|
|
* Should not be called.
|
|
*/
|
|
public boolean liveAtEndOfBlock(final VarExpr isLive, final Block block) {
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
/**
|
|
* Returns the <tt>LocalExpr</tt>s (variables) that occur in the CFG.
|
|
* They correspond to nodes in the interference graph.
|
|
*/
|
|
public Collection defs() {
|
|
return ig.keySet();
|
|
}
|
|
|
|
/**
|
|
* Returns an <tt>Iterator</tt> of <tt>LocalExpr</tt>s that interfere
|
|
* with a given <tt>VarExpr</tt>.
|
|
*/
|
|
public Iterator intersections(final VarExpr a) {
|
|
Assert.isTrue(a != null, "Cannot get intersections for null def");
|
|
Assert.isTrue(a.isDef(), "Cannot get intersections for variable uses");
|
|
|
|
final GraphNode node = ig.getNode(a);
|
|
|
|
Assert.isTrue(node != null, "Cannot find IG node for " + a);
|
|
|
|
return new Iterator() {
|
|
Iterator succs = ig.succs(node).iterator();
|
|
|
|
public boolean hasNext() {
|
|
return succs.hasNext();
|
|
}
|
|
|
|
public Object next() {
|
|
final IGNode next = (IGNode) succs.next();
|
|
return next.def;
|
|
}
|
|
|
|
public void remove() {
|
|
throw new RuntimeException();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Determines whether or not two variables interfere with one another.
|
|
*/
|
|
public boolean liveRangesIntersect(final VarExpr a, final VarExpr b) {
|
|
Assert.isTrue((a != null) && (b != null),
|
|
"Cannot get intersections for null def");
|
|
Assert.isTrue(a.isDef() && b.isDef(),
|
|
"Cannot get intersections for variable uses");
|
|
|
|
if (a == b) {
|
|
return false;
|
|
}
|
|
|
|
// If all locals should have unique colors, return true.
|
|
if (Liveness.UNIQUE) {
|
|
return true;
|
|
}
|
|
|
|
final IGNode na = (IGNode) ig.getNode(a);
|
|
final IGNode nb = (IGNode) ig.getNode(b);
|
|
|
|
Assert.isTrue((na != null) && (nb != null));
|
|
|
|
return ig.hasEdge(na, nb);
|
|
}
|
|
|
|
/**
|
|
* Constructs the interference graph.
|
|
*/
|
|
private void computeIntersections() {
|
|
ig = new Graph(); // The interference graph
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("-----------Computing live ranges-----------");
|
|
}
|
|
|
|
// All of the nodes (IGNodes) in the IG
|
|
final List defNodes = new ArrayList();
|
|
|
|
// The IGNodes whose local variable is defined by a PhiCatchStmt
|
|
final List phiCatchNodes = new ArrayList();
|
|
|
|
// An array of NodeInfo for each node in the CFG (indexed by the
|
|
// node's pre-order index). Gives information about the local
|
|
// variables (nodes in the IG) that are defined in each block.
|
|
// The NodeInfos are stored in reverse order. That is, the
|
|
// NodeInfo for the final variable occurrence in the block is the
|
|
// first element in the list.
|
|
final List[] nodes = new ArrayList[cfg.size()];
|
|
|
|
// We need to keep track of the order of the statements in which
|
|
// variables occur. There is an entry in nodeIndices for each
|
|
// block in the CFG. Each entry consists of a mapping between a
|
|
// statement in which a variable occurs and the number of the
|
|
// statement (with respect to the other statements in which
|
|
// variables occur) of interest. This is hard to explain in
|
|
// words. This numbering comes into play in the liveOut method.
|
|
final Map[] nodeIndices = new HashMap[cfg.size()];
|
|
|
|
Iterator iter = cfg.nodes().iterator();
|
|
|
|
// Initialize nodes and nodeIndices
|
|
while (iter.hasNext()) {
|
|
final Block block = (Block) iter.next();
|
|
final int blockIndex = cfg.preOrderIndex(block);
|
|
nodes[blockIndex] = new ArrayList();
|
|
nodeIndices[blockIndex] = new HashMap();
|
|
}
|
|
|
|
// Go in trace order. Code generation for phis in the presence of
|
|
// critical edges depends on it!
|
|
|
|
iter = cfg.trace().iterator();
|
|
|
|
// When performing liveness analysis, we traverse the tree from
|
|
// the bottom up. That is, we do a REVERSE traversal.
|
|
while (iter.hasNext()) {
|
|
final Block block = (Block) iter.next();
|
|
|
|
block.visit(new TreeVisitor(TreeVisitor.REVERSE) {
|
|
public void visitPhiJoinStmt(final PhiJoinStmt stmt) {
|
|
if (!(stmt.target() instanceof LocalExpr)) {
|
|
return;
|
|
}
|
|
|
|
final LocalExpr target = (LocalExpr) stmt.target();
|
|
|
|
// Examine each predacessor and maintain some information
|
|
// about the definitions. Remember that we're dealing with
|
|
// a PhiJoinStmt. The predacessors of PhiJoinStmts are
|
|
// statements that define or use the local (SSA) variable.
|
|
final Iterator preds = cfg.preds(block).iterator();
|
|
|
|
while (preds.hasNext()) {
|
|
final Block pred = (Block) preds.next();
|
|
final int predIndex = cfg.preOrderIndex(pred);
|
|
|
|
final List n = nodes[predIndex];
|
|
final Map indices = nodeIndices[predIndex];
|
|
|
|
indices.put(stmt, new Integer(n.size()));
|
|
final NodeInfo info = new NodeInfo(stmt);
|
|
n.add(info);
|
|
|
|
// Make a new node in the interference graph for target,
|
|
// if one does not already exists
|
|
IGNode node = (IGNode) ig.getNode(target);
|
|
|
|
if (node == null) {
|
|
node = new IGNode(target);
|
|
ig.addNode(target, node);
|
|
defNodes.add(node);
|
|
}
|
|
|
|
info.defNodes.add(node);
|
|
}
|
|
}
|
|
|
|
public void visitPhiCatchStmt(final PhiCatchStmt stmt) {
|
|
}
|
|
|
|
public void visitStmt(final Stmt stmt) {
|
|
}
|
|
});
|
|
}
|
|
|
|
iter = cfg.trace().iterator();
|
|
|
|
while (iter.hasNext()) {
|
|
final Block block = (Block) iter.next();
|
|
final int blockIndex = cfg.preOrderIndex(block);
|
|
|
|
block.visit(new TreeVisitor(TreeVisitor.REVERSE) {
|
|
Node parent = null;
|
|
|
|
public void visitNode(final Node node) {
|
|
final Node p = parent;
|
|
parent = node;
|
|
node.visitChildren(this);
|
|
parent = p;
|
|
}
|
|
|
|
public void visitLocalExpr(final LocalExpr expr) {
|
|
Assert.isTrue(parent != null);
|
|
|
|
// Recall that a LocalExpr represents a use or a definition
|
|
// of a local variable. If the LocalExpr is defined by a
|
|
// PhiJoinStmt, the block in which it resides should already
|
|
// have some information about it.
|
|
|
|
NodeInfo info;
|
|
|
|
final List n = nodes[blockIndex];
|
|
final Map indices = nodeIndices[blockIndex];
|
|
|
|
final Integer i = (Integer) indices.get(parent);
|
|
|
|
if (i == null) {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("adding " + parent + " at "
|
|
+ n.size());
|
|
}
|
|
|
|
indices.put(parent, new Integer(n.size()));
|
|
info = new NodeInfo(parent);
|
|
n.add(info);
|
|
|
|
} else {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("found " + parent + " at " + i);
|
|
}
|
|
|
|
info = (NodeInfo) n.get(i.intValue());
|
|
Assert.isTrue(info != null);
|
|
}
|
|
|
|
if (expr.isDef()) {
|
|
IGNode node = (IGNode) ig.getNode(expr);
|
|
|
|
if (node == null) {
|
|
node = new IGNode(expr);
|
|
ig.addNode(expr, node);
|
|
defNodes.add(node);
|
|
}
|
|
|
|
info.defNodes.add(node);
|
|
}
|
|
}
|
|
|
|
public void visitPhiCatchStmt(final PhiCatchStmt stmt) {
|
|
NodeInfo info;
|
|
|
|
final List n = nodes[blockIndex];
|
|
final Map indices = nodeIndices[blockIndex];
|
|
|
|
final Integer i = (Integer) indices.get(stmt);
|
|
|
|
if (i == null) {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("adding " + stmt + " at "
|
|
+ n.size());
|
|
}
|
|
|
|
indices.put(stmt, new Integer(n.size()));
|
|
info = new NodeInfo(stmt);
|
|
n.add(info);
|
|
|
|
} else {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("found " + parent + " at " + i);
|
|
}
|
|
|
|
info = (NodeInfo) n.get(i.intValue());
|
|
Assert.isTrue(info != null);
|
|
}
|
|
|
|
final LocalExpr target = (LocalExpr) stmt.target();
|
|
|
|
IGNode node = (IGNode) ig.getNode(target);
|
|
|
|
if (node == null) {
|
|
node = new IGNode(target);
|
|
ig.addNode(target, node);
|
|
defNodes.add(node);
|
|
phiCatchNodes.add(node);
|
|
}
|
|
|
|
info.defNodes.add(node);
|
|
}
|
|
|
|
public void visitPhiJoinStmt(final PhiJoinStmt stmt) {
|
|
}
|
|
});
|
|
}
|
|
|
|
// Iterate over all of the nodes in the IG
|
|
final int numDefs = defNodes.size();
|
|
|
|
for (int i = 0; i < numDefs; i++) {
|
|
final IGNode node = (IGNode) defNodes.get(i);
|
|
final LocalExpr def = node.def;
|
|
|
|
// Set of blocks where this variable is live out (i.e. live on
|
|
// any of the block's outgoing edges).
|
|
final BitSet m = new BitSet(cfg.size());
|
|
|
|
final Iterator uses = def.uses().iterator();
|
|
|
|
// Look at each use of the local variable
|
|
while (uses.hasNext()) {
|
|
final LocalExpr use = (LocalExpr) uses.next();
|
|
Node parent = use.parent();
|
|
|
|
if ((parent instanceof MemRefExpr)
|
|
&& ((MemRefExpr) parent).isDef()) {
|
|
parent = parent.parent();
|
|
}
|
|
|
|
// Skip catch-phis. We handle this later.
|
|
if (parent instanceof PhiCatchStmt) {
|
|
// If we want to be less conservative:
|
|
// Need to search back from the operand from all
|
|
// points in the protected region where it is live
|
|
// back to the def of the operand. For each block
|
|
// in protected region, if the operand def is closest
|
|
// dominator of the block
|
|
continue;
|
|
}
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("searching for " + def + " from "
|
|
+ parent);
|
|
}
|
|
|
|
final Block block = parent.block();
|
|
|
|
if (parent instanceof PhiJoinStmt) {
|
|
final PhiJoinStmt phi = (PhiJoinStmt) parent;
|
|
|
|
// The local variable (LocalExpr) occurs within a
|
|
// PhiJoinStmt. Look at the predacessors of the
|
|
// PhiJoinStmt. Recall that each predacessor defines one of
|
|
// the operands to the PhiJoinStmt. Locate the block that
|
|
// defines the LocalExpr in question. Call liveOut to
|
|
// determine for which nodes the LocalExpr is live out.
|
|
|
|
// Examine the predacessors of the block containing the
|
|
// LocalExpr
|
|
final Iterator preds = cfg.preds(block).iterator();
|
|
|
|
while (preds.hasNext()) {
|
|
final Block pred = (Block) preds.next();
|
|
|
|
if (phi.operandAt(pred) == use) {
|
|
final Map indices = nodeIndices[cfg
|
|
.preOrderIndex(pred)];
|
|
final Integer index = (Integer) indices.get(parent);
|
|
Assert.isTrue(index != null, "No index for "
|
|
+ parent);
|
|
|
|
liveOut(m, nodes, pred, index.intValue(), node,
|
|
phiCatchNodes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// The LocalExpr is define in a non-Phi statement. Figure
|
|
// out which number definition define the LocalExpr in quest
|
|
// and call liveOut to compute the set of block in which the
|
|
// LocalExpr is live out.
|
|
|
|
final Map indices = nodeIndices[cfg.preOrderIndex(block)];
|
|
final Integer index = (Integer) indices.get(parent);
|
|
Assert.isTrue(index != null, "No index for " + parent);
|
|
|
|
liveOut(m, nodes, block, index.intValue(), node,
|
|
phiCatchNodes);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Go through all of the variables that are defined by
|
|
// PhiCatchStmts and make them (the variables) conflict with
|
|
// everything that the operands of the PhiCatchStmt conflict
|
|
// with. See liveOut for a discussion.
|
|
|
|
final int numPhiCatches = phiCatchNodes.size();
|
|
|
|
for (int i = 0; i < numPhiCatches; i++) {
|
|
final IGNode node = (IGNode) phiCatchNodes.get(i);
|
|
|
|
final PhiCatchStmt phi = (PhiCatchStmt) node.def.parent();
|
|
|
|
final Iterator operands = phi.operands().iterator();
|
|
|
|
while (operands.hasNext()) {
|
|
final LocalExpr operand = (LocalExpr) operands.next();
|
|
final LocalExpr def = (LocalExpr) operand.def();
|
|
|
|
if (def != null) {
|
|
final IGNode opNode = (IGNode) ig.getNode(def);
|
|
|
|
// Conflict with everything the operand conflicts with.
|
|
final Iterator edges = new ImmutableIterator(ig
|
|
.succs(opNode));
|
|
|
|
while (edges.hasNext()) {
|
|
final IGNode otherNode = (IGNode) edges.next();
|
|
|
|
if (otherNode != node) {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println(otherNode.def
|
|
+ " conflicts with " + opNode.def
|
|
+ " and thus with " + node.def);
|
|
}
|
|
|
|
ig.addEdge(otherNode, node);
|
|
ig.addEdge(node, otherNode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("Interference graph =");
|
|
System.out.println(ig);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Computes (a portion of) the "live out" set for a given local variable. If
|
|
* a variable is live on a block's outgoing edge in the CFG, then it is
|
|
* "live out" at that block.
|
|
*
|
|
* @param m
|
|
* Bit vector that indicates the block for which block the
|
|
* defNode is live out
|
|
* @param nodes
|
|
* The NodeInfo for the local variables used or defined in each
|
|
* block
|
|
* @param block
|
|
* The block in which the LocalExpr of interest is defined
|
|
* @param nodeIndex
|
|
* Which number definition in the defining block
|
|
* @param defNode
|
|
* The node in the IG whose live out set we are interested in
|
|
* @param phiCatchNodes
|
|
* The nodes in the interference graph that represent local
|
|
* variables defined by PhiCatchStmts
|
|
*/
|
|
// Nate sez:
|
|
//
|
|
// In a PhiJoin pred, add
|
|
// ...
|
|
// phi-target := phi-operand
|
|
// jump with throw succs
|
|
//
|
|
// Don't kill Phi targets in protected blocks
|
|
// The phi target and operand don't conflict
|
|
void liveOut(final BitSet m, final List[] nodes, Block block,
|
|
int nodeIndex, final IGNode defNode, final Collection phiCatchNodes) {
|
|
boolean firstNode = true;
|
|
|
|
int blockIndex = cfg.preOrderIndex(block);
|
|
|
|
final ArrayList stack = new ArrayList();
|
|
|
|
Pos pos = new Pos();
|
|
pos.block = block;
|
|
pos.blockIndex = blockIndex;
|
|
pos.nodeIndex = nodeIndex;
|
|
|
|
stack.add(pos);
|
|
|
|
while (!stack.isEmpty()) {
|
|
pos = (Pos) stack.remove(stack.size() - 1);
|
|
|
|
block = pos.block;
|
|
blockIndex = pos.blockIndex;
|
|
nodeIndex = pos.nodeIndex;
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out.println(defNode.def + " is live at position "
|
|
+ nodeIndex + " of " + block);
|
|
}
|
|
|
|
boolean stop = false;
|
|
|
|
// The nodes are sorted in reverse. So, the below gets all of
|
|
// the nodes defined at this block after nodeIndex. I believe
|
|
// this is an optimization so we don't calculate things twice.
|
|
// Or maybe its how we get things to terminate.
|
|
final ListIterator iter = nodes[blockIndex].listIterator(nodeIndex);
|
|
|
|
while (!stop && iter.hasNext()) {
|
|
final NodeInfo info = (NodeInfo) iter.next();
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out
|
|
.println(defNode.def + " is live at " + info.node);
|
|
}
|
|
|
|
if (firstNode) {
|
|
// We don't care about the definition in the block that
|
|
// defines the LocalExpr of interest.
|
|
firstNode = false;
|
|
continue;
|
|
}
|
|
|
|
// Look at all (?) of the definitions of the LocalExpr
|
|
final Iterator e = info.defNodes.iterator();
|
|
|
|
while (e.hasNext()) {
|
|
final IGNode node = (IGNode) e.next();
|
|
|
|
final Iterator catchPhis = phiCatchNodes.iterator();
|
|
|
|
// Calculating the live region of the target of a phi-catch
|
|
// node is a little tricky. The target (variable) must be
|
|
// live throughout the protected region as well as after the
|
|
// PhiCatchStmt (its definition). However, we do not want
|
|
// the phi-catch target to conflict (interfere) with any of
|
|
// its operands. So, we make the target conflict with all
|
|
// of the variables that its operand conflict with. See
|
|
// page 37 of Nate's Thesis.
|
|
|
|
PHIS: while (catchPhis.hasNext()) {
|
|
final IGNode catchNode = (IGNode) catchPhis.next();
|
|
|
|
final PhiCatchStmt phi = (PhiCatchStmt) catchNode.def
|
|
.parent();
|
|
|
|
final Handler handler = (Handler) cfg.handlersMap()
|
|
.get(phi.block());
|
|
|
|
Assert.isTrue(handler != null, "Null handler for "
|
|
+ phi.block());
|
|
|
|
if (handler.protectedBlocks().contains(block)) {
|
|
final Iterator operands = phi.operands().iterator();
|
|
|
|
// If the block containing the LocalExpr in question
|
|
// resides inside a protected region. Make sure that
|
|
// the LocalExpr is not one of the operands to the
|
|
// PhiCatchStmt associated with the protected
|
|
// region.
|
|
|
|
while (operands.hasNext()) {
|
|
final LocalExpr expr = (LocalExpr) operands
|
|
.next();
|
|
|
|
if (expr.def() == node.def) {
|
|
continue PHIS;
|
|
}
|
|
}
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out.println(defNode.def
|
|
+ " conflicts with " + node.def);
|
|
}
|
|
|
|
// Hey, wow. The variable defined in the phi-catch
|
|
// interferes with the variable from the worklist.
|
|
ig.addEdge(node, catchNode);
|
|
ig.addEdge(catchNode, node);
|
|
}
|
|
}
|
|
|
|
if (node != defNode) {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println(defNode.def + " conflicts with "
|
|
+ node.def);
|
|
}
|
|
|
|
// If the node in the worklist is not the node we
|
|
// started
|
|
// with, then they conflict.
|
|
ig.addEdge(node, defNode);
|
|
ig.addEdge(defNode, node);
|
|
|
|
} else {
|
|
if (Liveness.DEBUG) {
|
|
System.out.println("def found stopping search");
|
|
}
|
|
|
|
// We've come across a definition of the LocalExpr in
|
|
// question, so we don't need to do any more.
|
|
stop = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!stop) {
|
|
// Propagate the liveness to each of the predacessors of the
|
|
// block in which the variable of interest is defined. This
|
|
// is accomplished by setting the appropriate bit in m. We
|
|
// also add another Pos to the worklist to work on the
|
|
// predacessor block.
|
|
final Iterator preds = cfg.preds(block).iterator();
|
|
|
|
while (preds.hasNext()) {
|
|
final Block pred = (Block) preds.next();
|
|
final int predIndex = cfg.preOrderIndex(pred);
|
|
|
|
if (Liveness.DEBUG) {
|
|
System.out.println(defNode.def + " is live at end of "
|
|
+ pred);
|
|
}
|
|
|
|
if (!m.get(predIndex)) {
|
|
pos = new Pos();
|
|
pos.block = pred;
|
|
pos.blockIndex = predIndex;
|
|
|
|
// Look at all of the statements in which a variable
|
|
// occur
|
|
pos.nodeIndex = 0;
|
|
|
|
m.set(predIndex);
|
|
stack.add(pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Represents a node in the interference graph. Connected nodes in the
|
|
* interference graph interfere with each other. That is, their live regions
|
|
*/
|
|
class IGNode extends GraphNode {
|
|
LocalExpr def;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param def
|
|
* The local variable represented by this node.
|
|
*/
|
|
public IGNode(final LocalExpr def) {
|
|
this.def = def;
|
|
}
|
|
|
|
public String toString() {
|
|
return def.toString();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stores information about each Node in an expression tree (!) that defines
|
|
* a local variable (i.e. PhiJoinStmt, PhiCatchStmt, and the parent of a
|
|
* LocalExpr).
|
|
*/
|
|
class NodeInfo {
|
|
Node node; // Node in an expression tree in which a variable occurs
|
|
|
|
List defNodes; // node(s) in IG that define above Node
|
|
|
|
public NodeInfo(final Node node) {
|
|
this.node = node;
|
|
defNodes = new ArrayList();
|
|
}
|
|
}
|
|
|
|
class Key {
|
|
int blockIndex;
|
|
|
|
Node node;
|
|
|
|
public Key(final Node node, final int blockIndex) {
|
|
this.blockIndex = blockIndex;
|
|
this.node = node;
|
|
}
|
|
|
|
public int hashCode() {
|
|
return node.hashCode() ^ blockIndex;
|
|
}
|
|
|
|
public boolean equals(final Object obj) {
|
|
if (obj instanceof Key) {
|
|
final Key key = (Key) obj;
|
|
return (key.node == node) && (key.blockIndex == blockIndex);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A Pos is an element in the worklist used to determine the live out set of
|
|
* a given LocalExpr. It consists of the block in which a local variable
|
|
* definition occurs, the block's index (i.e. pre-order traversal number) in
|
|
* the CFG, and the number of the definition in the block that defines the
|
|
* LocalExpr of interest.
|
|
*/
|
|
class Pos {
|
|
Block block;
|
|
|
|
int blockIndex;
|
|
|
|
int nodeIndex;
|
|
}
|
|
}
|
|
|