commit
7cd141f28e
@ -0,0 +1,65 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
SUBDIRS = cfg \
|
||||||
|
codegen \
|
||||||
|
context \
|
||||||
|
diva \
|
||||||
|
editor \
|
||||||
|
inline \
|
||||||
|
main \
|
||||||
|
optimize \
|
||||||
|
reflect \
|
||||||
|
ssa \
|
||||||
|
tbaa \
|
||||||
|
tests \
|
||||||
|
trans \
|
||||||
|
tree \
|
||||||
|
util \
|
||||||
|
|
||||||
|
all: |
||||||
|
@for i in $(SUBDIRS) ""; do \
|
||||||
|
if [ "x$$i" != "x" ]; then \
|
||||||
|
$(MAKE) -C $$i all; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
clean: |
||||||
|
@for i in $(SUBDIRS) ""; do \
|
||||||
|
if [ "x$$i" != "x" ]; then \
|
||||||
|
$(MAKE) -C $$i clean; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
docs: |
||||||
|
javadoc -d ../../../../../docs -sourcepath ../../../.. \
|
||||||
|
EDU.purdue.cs.bloat.util \
|
||||||
|
EDU.purdue.cs.bloat.reflect \
|
||||||
|
EDU.purdue.cs.bloat.editor \
|
||||||
|
EDU.purdue.cs.bloat.tree \
|
||||||
|
EDU.purdue.cs.bloat.cfg \
|
||||||
|
EDU.purdue.cs.bloat.ssa \
|
||||||
|
EDU.purdue.cs.bloat.tbaa \
|
||||||
|
EDU.purdue.cs.bloat.trans \
|
||||||
|
EDU.purdue.cs.bloat.diva \
|
||||||
|
EDU.purdue.cs.bloat.codegen \
|
||||||
|
EDU.purdue.cs.bloat.context \
|
||||||
|
EDU.purdue.cs.bloat.optimize \
|
@ -0,0 +1,442 @@ |
|||||||
|
/* |
||||||
|
* Class: Block |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.tree.StackOptimizationData; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
import edu.purdue.cs.bloat.util.GraphNode; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>Block</tt> represents a basic block of code used in control flow |
||||||
|
* graphs. A basic block is always entered at its beginning and exits at its |
||||||
|
* end. That is, its first statement is a label and its last statement is a |
||||||
|
* jump. There are no other labels or jumps in between. |
||||||
|
* <p> |
||||||
|
* Each <tt>Block</tt> knows its parent block and its children in the |
||||||
|
* dominator and postdominator trees. It also knows which blocks are in its |
||||||
|
* dominance frontier and its postdominance frontier. |
||||||
|
* |
||||||
|
* @see FlowGraph |
||||||
|
* @see DominatorTree |
||||||
|
* @see DominanceFrontier |
||||||
|
*/ |
||||||
|
public class Block extends GraphNode { |
||||||
|
// There are several "types" of Blocks. A NON_HEADER block is not the
|
||||||
|
// header of a loop. An IRREDUCIBLE block is one of the headers of an
|
||||||
|
// irreducible loop. An irriducible loop has more than one entry
|
||||||
|
// point. They are very rare and are really ugly. The loop
|
||||||
|
// transformer tries to fix up multiple headers. A REDUCIBLE header is
|
||||||
|
// a header for a reducible loop.
|
||||||
|
public static final int NON_HEADER = 0; |
||||||
|
|
||||||
|
public static final int IRREDUCIBLE = 1; |
||||||
|
|
||||||
|
public static final int REDUCIBLE = 2; |
||||||
|
|
||||||
|
FlowGraph graph; // CFG to which this Block belongs
|
||||||
|
|
||||||
|
InstructionHandle label; // This Block's Label
|
||||||
|
|
||||||
|
Tree tree; // Expression tree for this block
|
||||||
|
|
||||||
|
Block domParent; // Block that (immediately) dominates this Block
|
||||||
|
|
||||||
|
Block pdomParent; |
||||||
|
|
||||||
|
Set domChildren; // Blocks that this Block dominates
|
||||||
|
|
||||||
|
Set pdomChildren; // The postdominator children of this block
|
||||||
|
|
||||||
|
Set domFrontier; // This Block's dominance frontier
|
||||||
|
|
||||||
|
Set pdomFrontier; // This Block's postdominace frontier
|
||||||
|
|
||||||
|
int blockType; // NON_HEADER, IRREDUCIBLE, or REDUCIBLE
|
||||||
|
|
||||||
|
Block header; // The block's loop header
|
||||||
|
|
||||||
|
StackOptimizationData stackOptimizer; // Stack Optimizer
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param label |
||||||
|
* The block's label. Labels are implemented with BCEL using |
||||||
|
* InstructionHandle's attributes this means that a label |
||||||
|
* instruction is also the first instruction in the block it |
||||||
|
* labels. |
||||||
|
* @param graph |
||||||
|
* The CFG containing the block. |
||||||
|
*/ |
||||||
|
Block(InstructionHandle label, FlowGraph graph) { |
||||||
|
this.label = label; |
||||||
|
this.graph = graph; |
||||||
|
this.tree = null; |
||||||
|
this.header = null; |
||||||
|
this.blockType = NON_HEADER; |
||||||
|
|
||||||
|
FlowGraph.setLabel(label); // Make sure it's set.
|
||||||
|
// A little unsure here the start of a Block should be the target of a
|
||||||
|
// BranchInstruction and hasTargeters() should be true.
|
||||||
|
domParent = null; |
||||||
|
pdomParent = null; |
||||||
|
|
||||||
|
domChildren = new LinkedHashSet(); |
||||||
|
pdomChildren = new LinkedHashSet(); |
||||||
|
|
||||||
|
domFrontier = new LinkedHashSet(); |
||||||
|
pdomFrontier = new LinkedHashSet(); |
||||||
|
|
||||||
|
stackOptimizer = new StackOptimizationData(this); // make
|
||||||
|
// StackOptimizationData
|
||||||
|
// object
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* I use this method with caution the label should be set as soon as |
||||||
|
* possible after constructing the block using setLabel(). |
||||||
|
* |
||||||
|
* @param graph |
||||||
|
* The CFG containing the block. |
||||||
|
*/ |
||||||
|
|
||||||
|
Block(FlowGraph graph) { |
||||||
|
this.graph = graph; |
||||||
|
this.tree = null; |
||||||
|
this.header = null; |
||||||
|
this.blockType = NON_HEADER; |
||||||
|
|
||||||
|
// A little unsure here the start of a Block should be the target of a
|
||||||
|
// BranchInstruction and hasTargeters() should be true, otherwise we may
|
||||||
|
// be able to set an attribute.
|
||||||
|
domParent = null; |
||||||
|
pdomParent = null; |
||||||
|
|
||||||
|
domChildren = new LinkedHashSet(); |
||||||
|
pdomChildren = new LinkedHashSet(); |
||||||
|
|
||||||
|
domFrontier = new LinkedHashSet(); |
||||||
|
pdomFrontier = new LinkedHashSet(); |
||||||
|
|
||||||
|
stackOptimizer = new StackOptimizationData(this); // make
|
||||||
|
// StackOptimizationData
|
||||||
|
// object
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* added so that I can delay adding labels until I have parsed the first |
||||||
|
* instruction |
||||||
|
* |
||||||
|
* @param label |
||||||
|
* The InstructionHandle of the first instruction in the block. |
||||||
|
*/ |
||||||
|
public void setLabel(InstructionHandle label) { |
||||||
|
FlowGraph.setLabel(label); |
||||||
|
this.label = label; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the stack optimizer for this block. |
||||||
|
* |
||||||
|
* @return The stack optimizer. |
||||||
|
*/ |
||||||
|
public StackOptimizationData stackOptimizer() { |
||||||
|
return stackOptimizer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the expression tree for this block. |
||||||
|
* |
||||||
|
* @return The tree. |
||||||
|
*/ |
||||||
|
public Tree tree() { |
||||||
|
return tree; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the expression tree for this block. |
||||||
|
*/ |
||||||
|
public void setTree(Tree tree) { |
||||||
|
this.tree = tree; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the CFG containing the block. |
||||||
|
* |
||||||
|
* @return The CFG. |
||||||
|
*/ |
||||||
|
public FlowGraph graph() { |
||||||
|
return graph; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the label associated with this block. |
||||||
|
*/ |
||||||
|
public InstructionHandle label() { |
||||||
|
return label; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Visits the expression tree contained in this block. |
||||||
|
*/ |
||||||
|
public void visitChildren(TreeVisitor visitor) { |
||||||
|
if (tree != null) { |
||||||
|
tree.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitBlock(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the type of this Block. A Block may have one of three types: |
||||||
|
* |
||||||
|
* <ul> |
||||||
|
* <li><tt>NON_HEADER</tt>: Not the header of any loop |
||||||
|
* <li><tt>IRREDUCIBLE</tt>: Header of an irreducible loop |
||||||
|
* <li><tt>REDUCIBLE</tt>: Header of a reducible loop |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* A <i>loop</i> is a strongly connected component of a control flow graph. |
||||||
|
* A loop's <i>header</i> is the block that dominates all other blocks in |
||||||
|
* the loop. A loop is <i>reducible</i> if the only way to enter the loop |
||||||
|
* is through the header. |
||||||
|
*/ |
||||||
|
void setBlockType(int blockType) { |
||||||
|
this.blockType = blockType; |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" Set block type " + this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the type of this Block. |
||||||
|
*/ |
||||||
|
int blockType() { |
||||||
|
return blockType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHeader(Block header) { |
||||||
|
this.header = header; |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" Set header " + this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Block header() { |
||||||
|
return header; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a string representation of this block. |
||||||
|
*/ |
||||||
|
public String toString() { |
||||||
|
String s = "<block " + label + " hdr="; |
||||||
|
|
||||||
|
if (header != null) { |
||||||
|
s += header.label(); |
||||||
|
} else { |
||||||
|
s += "null"; |
||||||
|
} |
||||||
|
|
||||||
|
switch (blockType) { |
||||||
|
case NON_HEADER: |
||||||
|
break; |
||||||
|
case IRREDUCIBLE: |
||||||
|
s += " irred"; |
||||||
|
break; |
||||||
|
case REDUCIBLE: |
||||||
|
s += " red"; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (this == graph.source()) { |
||||||
|
return s + " source>"; |
||||||
|
} else if (this == graph.init()) { |
||||||
|
return s + " init>"; |
||||||
|
} else if (this == graph.sink()) { |
||||||
|
return s + " sink>"; |
||||||
|
} else { |
||||||
|
return s + ">"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the basic blocks that this Block immediately dominates. That is, |
||||||
|
* it returns this Block's children in the dominator tree for the CFG. |
||||||
|
*/ |
||||||
|
Collection domChildren() { |
||||||
|
return domChildren; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the immediate dominator of this Block. That is, it returns the |
||||||
|
* Block's parent in the dominator tree, its immediate dominator. |
||||||
|
*/ |
||||||
|
Block domParent() { |
||||||
|
return domParent; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies that Block dominates this Block (parent in the dominator tree, |
||||||
|
* the immediate dominator). |
||||||
|
* |
||||||
|
* @param block |
||||||
|
* Block that dominates this Block. |
||||||
|
*/ |
||||||
|
void setDomParent(Block block) { |
||||||
|
// If this Block already had a dominator specified, remove
|
||||||
|
// it from its dominator's children.
|
||||||
|
if (domParent != null) { |
||||||
|
domParent.domChildren.remove(this); |
||||||
|
} |
||||||
|
|
||||||
|
domParent = block; |
||||||
|
|
||||||
|
// Add this Block to its new dominator's children.
|
||||||
|
if (domParent != null) { |
||||||
|
domParent.domChildren.add(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns whether or this Block dominates another given Block. A node X |
||||||
|
* dominates a node Y when every path from the first node in the CFG (Enter) |
||||||
|
* to Y must pass through X. |
||||||
|
*/ |
||||||
|
public boolean dominates(Block block) { |
||||||
|
Block p = block; |
||||||
|
|
||||||
|
while (p != null) { |
||||||
|
if (p == this) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
p = p.domParent(); |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the children of this Block in the CFG's postdominator tree. |
||||||
|
*/ |
||||||
|
Collection pdomChildren() { |
||||||
|
return pdomChildren; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the parent of this Block in the CFG's postdominator tree. |
||||||
|
*/ |
||||||
|
Block pdomParent() { |
||||||
|
return pdomParent; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets this Block's parent in the postdominator tree. |
||||||
|
*/ |
||||||
|
void setPdomParent(Block block) { |
||||||
|
if (pdomParent != null) { |
||||||
|
pdomParent.pdomChildren.remove(this); |
||||||
|
} |
||||||
|
|
||||||
|
pdomParent = block; |
||||||
|
|
||||||
|
if (pdomParent != null) { |
||||||
|
pdomParent.pdomChildren.add(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines whether or not this block postdominates a given block. A block |
||||||
|
* X is said to postdominate a block Y when every path from Y to the last |
||||||
|
* node in the CFG (Exit) passes through X. This relationship can be thought |
||||||
|
* of as the reverse of dominance. That is, X dominates Y in the reverse |
||||||
|
* CFG. |
||||||
|
* |
||||||
|
* @see DominatorTree |
||||||
|
*/ |
||||||
|
public boolean postdominates(Block block) { |
||||||
|
Block p = block; |
||||||
|
|
||||||
|
while (p != null) { |
||||||
|
if (p == this) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
p = p.pdomParent(); |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the blocks that are in this block's dominance frontier. The |
||||||
|
* dominance frontier of a node X in a CFG is the set of all nodes Y such |
||||||
|
* that X dominates a predacessor of Y, but does not strictly dominate Y. |
||||||
|
* Nodes in the dominance frontier always have more than one parent (a |
||||||
|
* join). |
||||||
|
* |
||||||
|
* @see DominanceFrontier |
||||||
|
*/ |
||||||
|
Collection domFrontier() { |
||||||
|
Assert.isTrue(domFrontier != null); |
||||||
|
return domFrontier; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the postdominance frontier for this node. A postdominace frontier |
||||||
|
* is essentially the same as a dominace frontier, but the postdominance |
||||||
|
* relationship is used instead of the dominance relationship. |
||||||
|
*/ |
||||||
|
Collection pdomFrontier() { |
||||||
|
Assert.isTrue(pdomFrontier != null); |
||||||
|
return pdomFrontier; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,172 @@ |
|||||||
|
/* |
||||||
|
* Class: DominanceFrontier |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>DominanceFrontier</tt> is used to calculate the <i>dominance frontier</i> |
||||||
|
* of each node in a control flow graph. |
||||||
|
* <p> |
||||||
|
* The <i>dominance frontier</i> of a node x is the set of all nodes w such |
||||||
|
* that x dominates a predacessor of w, but does not strictly dominate w. |
||||||
|
* Basically, nodes in the dominance frontier have one parent that <b>is</b> |
||||||
|
* dominated by x and at least one parent that <b>is not</b> dominated by x. |
||||||
|
* <p> |
||||||
|
* <tt>DominanceFrontier</tt> can be used to calculate both the dominance |
||||||
|
* (forward) and the postdominance (reverse) frontiers for a control flow graph. |
||||||
|
* |
||||||
|
* @see FlowGraph |
||||||
|
*/ |
||||||
|
|
||||||
|
public class DominanceFrontier { |
||||||
|
/** |
||||||
|
* Calculates the dominance frontier for a cfg and notifies the blocks in it |
||||||
|
* appropriately. |
||||||
|
* |
||||||
|
* @param graph |
||||||
|
* The cfg to operate on |
||||||
|
* @param reverse |
||||||
|
* Do we calculate the postdominance frontier? |
||||||
|
*/ |
||||||
|
public static void buildFrontier(FlowGraph graph, boolean reverse) { |
||||||
|
if (!reverse) { |
||||||
|
calcFrontier(graph.source(), graph, reverse); |
||||||
|
} else { |
||||||
|
calcFrontier(graph.sink(), graph, reverse); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Recursively traverses the cfg and builds up the dominance frontier. |
||||||
|
* <p> |
||||||
|
* A block n's dominance frontier is the union of two sets of nodes. The |
||||||
|
* first set is the nodes in the dominance frontier of the nodes that n |
||||||
|
* dominates that are not dominated by n's immediate dominator. The second |
||||||
|
* set consists of the successors of n that are not strictly dominated by n. |
||||||
|
* |
||||||
|
* @param block |
||||||
|
* The block to start from (either source or sink) |
||||||
|
* @param graph |
||||||
|
* The cfg from which to get blocks |
||||||
|
* @param reverse |
||||||
|
* Do we calculate the dominance or postdominance frontier? |
||||||
|
* |
||||||
|
* @return The blocks in the (post)dominance frontier of block |
||||||
|
*/ |
||||||
|
private static LinkedList calcFrontier(Block block, FlowGraph graph, |
||||||
|
boolean reverse) { |
||||||
|
// local is an array of Blocks that are in block's dominance
|
||||||
|
// frontier. It is indexed by the block's pre-order index. I
|
||||||
|
// suppose an array is used so that no block is added to the
|
||||||
|
// dominance frontier twice.
|
||||||
|
Block[] local = new Block[graph.size()]; |
||||||
|
|
||||||
|
Iterator children; // The blocks that are dominated by block
|
||||||
|
|
||||||
|
if (!reverse) { |
||||||
|
children = block.domChildren().iterator(); |
||||||
|
} else { |
||||||
|
children = block.pdomChildren().iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
// Recursively calculate the nodes in the dominance frontier of
|
||||||
|
// block that are not dominated by block's immediate dominator
|
||||||
|
while (children.hasNext()) { |
||||||
|
Block child = (Block) children.next(); |
||||||
|
|
||||||
|
LinkedList df = calcFrontier(child, graph, reverse); |
||||||
|
|
||||||
|
Iterator e = df.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block dfChild = (Block) e.next(); |
||||||
|
|
||||||
|
if (!reverse) { |
||||||
|
if (block != dfChild.domParent()) |
||||||
|
local[graph.preOrderIndex(dfChild)] = dfChild; |
||||||
|
|
||||||
|
} else { |
||||||
|
if (block != dfChild.pdomParent()) |
||||||
|
local[graph.preOrderIndex(dfChild)] = dfChild; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Iterator succs = reverse ? graph.preds(block).iterator() : graph.succs( |
||||||
|
block).iterator(); |
||||||
|
|
||||||
|
// Caculate the successors of block that are not strictly
|
||||||
|
// dominated by block.
|
||||||
|
while (succs.hasNext()) { |
||||||
|
Block succ = (Block) succs.next(); |
||||||
|
|
||||||
|
// If block is not the immediate (post)dominator of its
|
||||||
|
// successor, add it to block's dominance frontier.
|
||||||
|
if (!reverse) { |
||||||
|
if (block != succ.domParent()) |
||||||
|
local[graph.preOrderIndex(succ)] = succ; |
||||||
|
|
||||||
|
} else { |
||||||
|
if (block != succ.pdomParent()) |
||||||
|
local[graph.preOrderIndex(succ)] = succ; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
LinkedList v = new LinkedList(); // The dominance frontier
|
||||||
|
|
||||||
|
for (int i = 0; i < local.length; i++) { |
||||||
|
if (local[i] != null) { |
||||||
|
v.add(local[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Set block's (post)dominance frontier
|
||||||
|
if (!reverse) { |
||||||
|
block.domFrontier().clear(); |
||||||
|
block.domFrontier().addAll(v); |
||||||
|
} else { |
||||||
|
block.pdomFrontier().clear(); |
||||||
|
block.pdomFrontier().addAll(v); |
||||||
|
} |
||||||
|
|
||||||
|
return v; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,399 @@ |
|||||||
|
/* |
||||||
|
* Class: DominatorTree |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* DominatorTree finds the dominator tree of a FlowGraph. |
||||||
|
* <p> |
||||||
|
* The algorithm used is Purdum-Moore. It isn't as fast as Lengauer-Tarjan, but |
||||||
|
* it's a lot simpler. |
||||||
|
* |
||||||
|
* @see FlowGraph |
||||||
|
* @see Block |
||||||
|
*/ |
||||||
|
public class DominatorTree { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
/** |
||||||
|
* Calculates what vertices dominate other verices and notify the basic |
||||||
|
* Blocks as to who their dominator is. |
||||||
|
* |
||||||
|
* @param graph |
||||||
|
* The cfg that is used to find the dominator tree. |
||||||
|
* @param reverse |
||||||
|
* Do we go in revsers? That is, are we computing the dominatance |
||||||
|
* (false) or postdominance (true) tree. |
||||||
|
* @see Block |
||||||
|
*/ |
||||||
|
public static void buildTree(FlowGraph graph, boolean reverse) { |
||||||
|
int size = graph.size(); // The number of vertices in the cfg
|
||||||
|
|
||||||
|
Map snkPreds = new LinkedHashMap(); // The predacessor vertices from the
|
||||||
|
// sink
|
||||||
|
|
||||||
|
// Determine the predacessors of the cfg's sink node
|
||||||
|
insertEdgesToSink(graph, snkPreds, reverse); |
||||||
|
|
||||||
|
// Get the index of the root
|
||||||
|
int root = reverse ? graph.preOrderIndex(graph.sink()) : graph |
||||||
|
.preOrderIndex(graph.source()); |
||||||
|
|
||||||
|
Assert.isTrue(0 <= root && root < size); |
||||||
|
|
||||||
|
// Bit matrix indicating the dominators of each vertex.
|
||||||
|
// If bit j of dom[i] is set, then node j dominates node i.
|
||||||
|
BitSet[] dom = new BitSet[size]; |
||||||
|
|
||||||
|
// A bit vector of all 1's
|
||||||
|
BitSet ALL = new BitSet(size); |
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) { |
||||||
|
ALL.set(i); |
||||||
|
} |
||||||
|
|
||||||
|
// Initially, all the bits in the dominance matrix are set, except
|
||||||
|
// for the root node. The root node is initialized to have itself
|
||||||
|
// as an immediate dominator.
|
||||||
|
//
|
||||||
|
for (int i = 0; i < size; i++) { |
||||||
|
BitSet blockDoms = new BitSet(size); |
||||||
|
dom[i] = blockDoms; |
||||||
|
|
||||||
|
if (i != root) { |
||||||
|
blockDoms.or(ALL); |
||||||
|
} else { |
||||||
|
blockDoms.set(root); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Did the dominator bit vector array change?
|
||||||
|
boolean changed = true; |
||||||
|
|
||||||
|
while (changed) { |
||||||
|
changed = false; |
||||||
|
|
||||||
|
// Get the basic blocks contained in the cfg
|
||||||
|
Iterator blocks = reverse ? graph.postOrder().iterator() : graph |
||||||
|
.preOrder().iterator(); |
||||||
|
|
||||||
|
// Compute the dominators of each node in the cfg. We iterate
|
||||||
|
// over every node in the cfg. The dominators of a node, x, are
|
||||||
|
// found by taking the intersection of the dominator bit vectors
|
||||||
|
// of each predacessor of x and unioning that with x. This
|
||||||
|
// process is repeated until no changes are made to any
|
||||||
|
// dominator
|
||||||
|
// bit vector.
|
||||||
|
|
||||||
|
while (blocks.hasNext()) { |
||||||
|
Block block = (Block) blocks.next(); |
||||||
|
|
||||||
|
int i = graph.preOrderIndex(block); |
||||||
|
|
||||||
|
Assert.isTrue(0 <= i && i < size, "Unreachable block " + block); |
||||||
|
|
||||||
|
// We already know the dominators of the root, keep looking
|
||||||
|
if (i == root) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
BitSet oldSet = dom[i]; |
||||||
|
BitSet blockDoms = new BitSet(size); |
||||||
|
blockDoms.or(oldSet); |
||||||
|
|
||||||
|
// blockDoms := intersection of dom(pred) for all pred(block).
|
||||||
|
Collection preds = reverse ? graph.succs(block) : graph |
||||||
|
.preds(block); |
||||||
|
|
||||||
|
Iterator e = preds.iterator(); |
||||||
|
|
||||||
|
// Find the intersection of the dominators of block's
|
||||||
|
// predacessors.
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block pred = (Block) e.next(); |
||||||
|
|
||||||
|
int j = graph.preOrderIndex(pred); |
||||||
|
Assert.isTrue(j >= 0, "Unreachable block " + pred); |
||||||
|
|
||||||
|
blockDoms.and(dom[j]); |
||||||
|
} |
||||||
|
|
||||||
|
// Don't forget to account for the sink node if block is a
|
||||||
|
// leaf node. Appearantly, there are not edges between
|
||||||
|
// leaf nodes and the sink node!
|
||||||
|
preds = (Collection) snkPreds.get(block); |
||||||
|
|
||||||
|
if (preds != null) { |
||||||
|
e = preds.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block pred = (Block) e.next(); |
||||||
|
|
||||||
|
int j = graph.preOrderIndex(pred); |
||||||
|
Assert.isTrue(j >= 0, "Unreachable block " + pred); |
||||||
|
|
||||||
|
blockDoms.and(dom[j]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Include yourself in your dominators?!
|
||||||
|
blockDoms.set(i); |
||||||
|
|
||||||
|
// If the set changed, set the changed bit.
|
||||||
|
if (!blockDoms.equals(oldSet)) { |
||||||
|
changed = true; |
||||||
|
dom[i] = blockDoms; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Once we have the predacessor bit vectors all squared away, we can
|
||||||
|
// determine which vertices dominate which vertices.
|
||||||
|
|
||||||
|
Iterator blocks = graph.nodes().iterator(); |
||||||
|
|
||||||
|
// Initialize each block's (post)dominator parent and children
|
||||||
|
while (blocks.hasNext()) { |
||||||
|
Block block = (Block) blocks.next(); |
||||||
|
if (!reverse) { |
||||||
|
block.setDomParent(null); |
||||||
|
block.domChildren().clear(); |
||||||
|
} else { |
||||||
|
block.setPdomParent(null); |
||||||
|
block.pdomChildren().clear(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
blocks = graph.nodes().iterator(); |
||||||
|
|
||||||
|
// A block's immediate dominator is its closest dominator. So, we
|
||||||
|
// start with the dominators, dom(b), of a block, b. To find the
|
||||||
|
// imediate dominator of b, we remove all blocks from dom(b) that
|
||||||
|
// dominate any block in dom(b).
|
||||||
|
|
||||||
|
while (blocks.hasNext()) { |
||||||
|
Block block = (Block) blocks.next(); |
||||||
|
|
||||||
|
int i = graph.preOrderIndex(block); |
||||||
|
|
||||||
|
Assert.isTrue(0 <= i && i < size, "Unreachable block " + block); |
||||||
|
|
||||||
|
if (i == root) { |
||||||
|
if (!reverse) { |
||||||
|
block.setDomParent(null); |
||||||
|
} else { |
||||||
|
block.setPdomParent(null); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// Find the immediate dominator
|
||||||
|
// idom := dom(block) - dom(dom(block)) - block
|
||||||
|
BitSet blockDoms = dom[i]; |
||||||
|
|
||||||
|
// print(graph, reverse, "dom set", i, blockDoms);
|
||||||
|
|
||||||
|
BitSet idom = new BitSet(size); |
||||||
|
idom.or(blockDoms); |
||||||
|
idom.clear(i); |
||||||
|
|
||||||
|
for (int j = 0; j < size; j++) { |
||||||
|
if (i != j && blockDoms.get(j)) { |
||||||
|
BitSet domDomBlocks = dom[j]; |
||||||
|
|
||||||
|
// idom = idom - (domDomBlocks - {j})
|
||||||
|
BitSet b = new BitSet(size); |
||||||
|
b.or(domDomBlocks); |
||||||
|
b.xor(ALL); |
||||||
|
b.set(j); |
||||||
|
idom.and(b); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Block parent = null; |
||||||
|
|
||||||
|
// A block should only have one immediate dominator.
|
||||||
|
for (int j = 0; j < size; j++) { |
||||||
|
if (idom.get(j)) { |
||||||
|
Block p = (Block) graph.preOrder().get(j); |
||||||
|
|
||||||
|
Assert.isTrue(parent == null, block |
||||||
|
+ " has more than one immediate dominator: " |
||||||
|
+ parent + " and " + p); |
||||||
|
|
||||||
|
parent = p; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Assert.isTrue(parent != null, block + " has 0 immediate " |
||||||
|
+ (reverse ? "postdominators" : "dominators")); |
||||||
|
|
||||||
|
if (!reverse) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(parent + " dominates " + block); |
||||||
|
} |
||||||
|
|
||||||
|
block.setDomParent(parent); |
||||||
|
|
||||||
|
} else { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(parent + " postdominates " + block); |
||||||
|
} |
||||||
|
|
||||||
|
block.setPdomParent(parent); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines which nodes are predacessors of a cfg's sink node. Creates a |
||||||
|
* Map that maps the sink node to its predacessors (or the leaf nodes to the |
||||||
|
* sink node, their predacessor, if we're going backwards). |
||||||
|
* |
||||||
|
* @param graph |
||||||
|
* The cfg to operate on. |
||||||
|
* @param preds |
||||||
|
* A mapping from leaf nodes to their predacessors. The exact |
||||||
|
* semantics depend on whether or not we are going forwards. |
||||||
|
* @param reverse |
||||||
|
* Are we computing the dominators or postdominators? |
||||||
|
*/ |
||||||
|
private static void insertEdgesToSink(FlowGraph graph, Map preds, |
||||||
|
boolean reverse) { |
||||||
|
BitSet visited = new BitSet(); // see insertEdgesToSinkDFS
|
||||||
|
BitSet returned = new BitSet(); |
||||||
|
|
||||||
|
visited.set(graph.preOrderIndex(graph.source())); |
||||||
|
|
||||||
|
insertEdgesToSinkDFS(graph, graph.source(), visited, returned, preds, |
||||||
|
reverse); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method determines which nodes are the predacessor of the sink node |
||||||
|
* of a cfg. A depth-first traversal of the cfg is performed. When a leaf |
||||||
|
* node (that is not the sink node) is encountered, add an entry to the |
||||||
|
* preds Map. |
||||||
|
* |
||||||
|
* @param graph |
||||||
|
* The cfg being operated on. |
||||||
|
* @param block |
||||||
|
* The basic Block to start at. |
||||||
|
* @param visited |
||||||
|
* Vertices that were visited |
||||||
|
* @param returned |
||||||
|
* Vertices that returned |
||||||
|
* @param preds |
||||||
|
* Maps a node to a HashSet representing its predacessors. In the |
||||||
|
* case that we're determining the dominace tree, preds maps the |
||||||
|
* sink node to its predacessors. In the case that we're |
||||||
|
* determining the postdominance tree, preds maps the sink node's |
||||||
|
* predacessors to the sink node. |
||||||
|
* @param reverse |
||||||
|
* Do we go in reverse? |
||||||
|
*/ |
||||||
|
private static void insertEdgesToSinkDFS(FlowGraph graph, Block block, |
||||||
|
BitSet visited, BitSet returned, Map preds, boolean reverse) { |
||||||
|
boolean leaf = true; // Is a vertex a leaf node?
|
||||||
|
|
||||||
|
// Get the successors of block
|
||||||
|
Iterator e = graph.succs(block).iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block succ = (Block) e.next(); |
||||||
|
|
||||||
|
// Determine index of succ vertex in a pre-order traversal
|
||||||
|
int index = graph.preOrderIndex(succ); |
||||||
|
Assert.isTrue(index >= 0, "Unreachable block " + succ); |
||||||
|
|
||||||
|
if (!visited.get(index)) { |
||||||
|
// If the successor block hasn't been visited, visit it
|
||||||
|
visited.set(index); |
||||||
|
insertEdgesToSinkDFS(graph, succ, visited, returned, preds, |
||||||
|
reverse); |
||||||
|
returned.set(index); |
||||||
|
leaf = false; |
||||||
|
|
||||||
|
} else if (returned.get(index)) { |
||||||
|
// Already visited and returned, so a descendent of succ
|
||||||
|
// has an edge to the sink.
|
||||||
|
leaf = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (leaf && block != graph.sink()) { |
||||||
|
// If we're dealing with a leaf node that is not the sink, set
|
||||||
|
// up its predacessor set.
|
||||||
|
|
||||||
|
if (!reverse) { |
||||||
|
// If we're going forwards (computing dominators), get the
|
||||||
|
// predacessor vertices from the sink
|
||||||
|
Set p = (Set) preds.get(graph.sink()); |
||||||
|
|
||||||
|
// If there are no (known) predacessors, make a new
|
||||||
|
// LinkedHashSet to
|
||||||
|
// store them and register it in the pred Map.
|
||||||
|
if (p == null) { |
||||||
|
p = new LinkedHashSet(); |
||||||
|
preds.put(graph.sink(), p); |
||||||
|
} |
||||||
|
|
||||||
|
// The block is in the predacessors of the sink
|
||||||
|
p.add(block); |
||||||
|
|
||||||
|
} else { |
||||||
|
// If we're going backwards, get the block's predacessors
|
||||||
|
Set p = (Set) preds.get(block); |
||||||
|
|
||||||
|
if (p == null) { |
||||||
|
p = new LinkedHashSet(); |
||||||
|
preds.put(block, p); |
||||||
|
} |
||||||
|
|
||||||
|
// Add the sink vertex to the predacessors of the block
|
||||||
|
p.add(graph.sink()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,97 @@ |
|||||||
|
/* |
||||||
|
* Class: Handler |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>Handler</tt> represents a try-catch block. It containes a set of |
||||||
|
* protected <tt>Block</tt>s (the "try" blocks), a catch <tt>Block</tt>, |
||||||
|
* and the <tt>Type</tt> of exception that is caught by the catch block. |
||||||
|
* |
||||||
|
* @see Block |
||||||
|
* @see edu.purdue.cs.bloat.reflect.Catch |
||||||
|
* @see edu.purdue.cs.bloat.editor.TryCatch |
||||||
|
*/ |
||||||
|
public class Handler { |
||||||
|
Set protectedBlocks; |
||||||
|
|
||||||
|
Block catchBlock; |
||||||
|
|
||||||
|
final Type type; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param catchBlock |
||||||
|
* The block of code that handles an exception |
||||||
|
* @param type |
||||||
|
* The type of exception that is thrown |
||||||
|
*/ |
||||||
|
public Handler(Block catchBlock, Type type) { |
||||||
|
this.protectedBlocks = new LinkedHashSet(); |
||||||
|
this.catchBlock = catchBlock; |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>Collection</tt> of the "try" blocks. |
||||||
|
*/ |
||||||
|
public Collection protectedBlocks() { |
||||||
|
return protectedBlocks; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCatchBlock(Block block) { |
||||||
|
catchBlock = block; |
||||||
|
} |
||||||
|
|
||||||
|
public Block catchBlock() { |
||||||
|
return catchBlock; |
||||||
|
} |
||||||
|
|
||||||
|
public Type catchType() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return "try -> catch (" + type + ") " + catchBlock; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
Block.class\
|
||||||
|
DominanceFrontier.class\
|
||||||
|
DominatorTree.class\
|
||||||
|
FlowGraph.class\
|
||||||
|
ReplaceTarget.class\
|
||||||
|
Subroutine.class\
|
||||||
|
VerifyCFG.class
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,194 @@ |
|||||||
|
/* |
||||||
|
* Class: ReplaceTarget |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.tree.GotoStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.IfStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.JsrStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.JumpStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.RetStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Stmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SwitchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>ReplaceTarget</tt> replaces the block that is the target of a |
||||||
|
* <tt>JumpStmt</tt>, <tt>JsrStmt</tt>, <tt>RetStmt</tt>, |
||||||
|
* <tt>GotoStmt</tt>, <tt>SwitchStmt</tt>, or <tt>IfStmt</tt> with |
||||||
|
* another <tt>Block</tt>. |
||||||
|
*/ |
||||||
|
public class ReplaceTarget extends TreeVisitor { |
||||||
|
Block oldDst; |
||||||
|
|
||||||
|
Block newDst; |
||||||
|
|
||||||
|
public ReplaceTarget(Block oldDst, Block newDst) { |
||||||
|
this.oldDst = oldDst; |
||||||
|
this.newDst = newDst; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
Stmt last = (Stmt) tree.lastStmt(); |
||||||
|
|
||||||
|
if (last instanceof JumpStmt) { |
||||||
|
JumpStmt stmt = (JumpStmt) last; |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" Replacing " + oldDst + " with " + newDst |
||||||
|
+ " in " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
if (stmt.catchTargets().remove(oldDst)) { |
||||||
|
stmt.catchTargets().add(newDst); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
if (stmt.sub().entry() == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.print(" replacing " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.block().graph().setSubEntry(stmt.sub(), newDst); |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" with " + stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
Iterator paths = stmt.sub().paths().iterator(); |
||||||
|
|
||||||
|
while (paths.hasNext()) { |
||||||
|
Block[] path = (Block[]) paths.next(); |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" path = " + path[0] + " " + path[1]); |
||||||
|
} |
||||||
|
|
||||||
|
if (path[1] == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" replacing ret to " + oldDst |
||||||
|
+ " with ret to " + newDst); |
||||||
|
} |
||||||
|
|
||||||
|
path[1] = newDst; |
||||||
|
((JsrStmt) path[0].tree().lastStmt()).setFollow(newDst); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
if (stmt.target() == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.print(" replacing " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.setTarget(newDst); |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" with " + stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
if (stmt.defaultTarget() == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.print(" replacing " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.setDefaultTarget(newDst); |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" with " + stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Block[] targets = stmt.targets(); |
||||||
|
|
||||||
|
for (int i = 0; i < targets.length; i++) { |
||||||
|
if (targets[i] == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.print(" replacing " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
targets[i] = newDst; |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" with " + stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfStmt(IfStmt stmt) { |
||||||
|
if (stmt.trueTarget() == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.print(" replacing " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.setTrueTarget(newDst); |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" with " + stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (stmt.falseTarget() == oldDst) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.print(" replacing " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.setFalseTarget(newDst); |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println(" with " + stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,296 @@ |
|||||||
|
/* |
||||||
|
* Class: Subroutine |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.tree.AddressStoreStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Subroutine represents a subroutine (target of a <i>jsr</i> instruction) in |
||||||
|
* java bytecode. Subroutines are used to implement the finally part of a |
||||||
|
* try-catch-finally block. |
||||||
|
* <p> |
||||||
|
* Each Subroutine belongs in a control flow graph, has an entry and exit block, |
||||||
|
* and has a local variable that contains its return address. Additionally, it |
||||||
|
* maintains a list of paths from blocks in which the subroutine is called to |
||||||
|
* block that is executed after the subroutine returns. |
||||||
|
* <p> |
||||||
|
* Note that it is assumed that each subroutine ends with a <i>ret</i>. While |
||||||
|
* this is true for bytecode generated by javac, it is not required. |
||||||
|
* |
||||||
|
* @see AddressStoreStmt |
||||||
|
* @see Block |
||||||
|
*/ |
||||||
|
|
||||||
|
// Important: I assume there is a ret statement for each jsr.
|
||||||
|
// This is true for javac code, but not in general.
|
||||||
|
public class Subroutine { |
||||||
|
FlowGraph graph; // CFG containing this Subroutine
|
||||||
|
|
||||||
|
Block entry; // Basic Block at beginning of code
|
||||||
|
|
||||||
|
Block exit; // Basic Block ending code
|
||||||
|
|
||||||
|
ArrayList paths; |
||||||
|
|
||||||
|
ReturnaddressType returnAddress; // This Subroutine's return address
|
||||||
|
|
||||||
|
LocalVariableGen localVariable = null; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param graph |
||||||
|
* The CFG containing the block. |
||||||
|
*/ |
||||||
|
public Subroutine(FlowGraph graph) { |
||||||
|
this.graph = graph; |
||||||
|
this.entry = null; |
||||||
|
this.exit = null; |
||||||
|
this.paths = new ArrayList(); |
||||||
|
this.returnAddress = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the local variable containing the return address of this |
||||||
|
* subroutine. |
||||||
|
*/ |
||||||
|
public ReturnaddressType returnAddress() { |
||||||
|
return returnAddress; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the address (stored in a LocalVariable) to which this subroutine |
||||||
|
* will return once it is finished. |
||||||
|
* |
||||||
|
* @param returnAddress |
||||||
|
* Local variable that stores the address to which the subroutine |
||||||
|
* returns when it is completed. |
||||||
|
* |
||||||
|
* @see Tree#visit_astore |
||||||
|
*/ |
||||||
|
public void setReturnAddress(ReturnaddressType returnAddress) { |
||||||
|
this.returnAddress = returnAddress; |
||||||
|
} |
||||||
|
|
||||||
|
// Set and get Local variable that is used to store the return address
|
||||||
|
// instead of the stack
|
||||||
|
public LocalVariableGen localVariable() { |
||||||
|
return localVariable; |
||||||
|
} |
||||||
|
|
||||||
|
public void setLocalVariable(LocalVariableGen localVar) { |
||||||
|
this.localVariable = localVar; |
||||||
|
} |
||||||
|
|
||||||
|
public void unsetLocalVariable() { |
||||||
|
this.localVariable = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the number of places that this subroutine is called. |
||||||
|
*/ |
||||||
|
public int numPaths() { |
||||||
|
return paths.size(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the paths (a Collection of two-element arrays of Blocks) that |
||||||
|
* represent the Blocks that end in a call to this subroutine and the block |
||||||
|
* that begin with the return address from this subroutine. |
||||||
|
*/ |
||||||
|
public Collection paths() { |
||||||
|
return paths; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the CFG that contains this subroutine. |
||||||
|
*/ |
||||||
|
public FlowGraph graph() { |
||||||
|
return graph; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes all paths involving block regardless of whether it is a calling |
||||||
|
* (source) block or a returning (target) block. |
||||||
|
*/ |
||||||
|
public void removePathsContaining(Block block) { |
||||||
|
for (int i = paths.size() - 1; i >= 0; i--) { |
||||||
|
Block[] path = (Block[]) paths.get(i); |
||||||
|
if (path[0] == block || path[1] == block) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println("removing path " + path[0] + " -> " |
||||||
|
+ path[1]); |
||||||
|
} |
||||||
|
paths.remove(i); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a path between a caller Block and a return Block. |
||||||
|
*/ |
||||||
|
public void removePath(Block callerBlock, Block returnBlock) { |
||||||
|
for (int i = 0; i < paths.size(); i++) { |
||||||
|
Block[] path = (Block[]) paths.get(i); |
||||||
|
if (path[0] == callerBlock && path[1] == returnBlock) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println("removing path " + path[0] + " -> " |
||||||
|
+ path[1]); |
||||||
|
} |
||||||
|
paths.remove(i); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes all caller-return paths. |
||||||
|
*/ |
||||||
|
public void removeAllPaths() { |
||||||
|
paths = new ArrayList(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a path from the block before a Subroutine is called to a block after |
||||||
|
* the subroutine is called. If the callerBlock is already associated with a |
||||||
|
* returnBlock, the old returnBlock is replaced. |
||||||
|
* |
||||||
|
* @param callerBlock |
||||||
|
* The block in which the subroutine is called. This Block ends |
||||||
|
* with a <i>jsr</i> to this subroutine. |
||||||
|
* @param returnBlock |
||||||
|
* The block to which the subroutine returns. This Block begins |
||||||
|
* at the return address of this subroutine. |
||||||
|
*/ |
||||||
|
public void addPath(Block callerBlock, Block returnBlock) { |
||||||
|
for (int i = 0; i < paths.size(); i++) { |
||||||
|
Block[] path = (Block[]) paths.get(i); |
||||||
|
if (path[0] == callerBlock) { |
||||||
|
path[1] = returnBlock; |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
paths.add(new Block[] { callerBlock, returnBlock }); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the "return block" for a given "caller block". |
||||||
|
*/ |
||||||
|
public Block pathTarget(Block block) { |
||||||
|
for (int i = 0; i < paths.size(); i++) { |
||||||
|
Block[] path = (Block[]) paths.get(i); |
||||||
|
if (path[0] == block) { |
||||||
|
return path[1]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the "caller block" for a given "return block". |
||||||
|
*/ |
||||||
|
public Block pathSource(Block block) { |
||||||
|
for (int i = 0; i < paths.size(); i++) { |
||||||
|
Block[] path = (Block[]) paths.get(i); |
||||||
|
if (path[1] == block) { |
||||||
|
return path[0]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the entry Block for this Subroutine. |
||||||
|
*/ |
||||||
|
public void setEntry(Block entry) { |
||||||
|
this.entry = entry; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the exit Block for this Subroutine. |
||||||
|
*/ |
||||||
|
public void setExit(Block exit) { |
||||||
|
this.exit = exit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the first Block in the subroutine. |
||||||
|
*/ |
||||||
|
public Block entry() { |
||||||
|
return entry; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the last Block in the subroutine. |
||||||
|
*/ |
||||||
|
public Block exit() { |
||||||
|
return exit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prints a textual representation of this Subroutine. |
||||||
|
* |
||||||
|
* @param out |
||||||
|
* The PrintStream to which to print. |
||||||
|
*/ |
||||||
|
public void print(PrintStream out) { |
||||||
|
out.println(" " + entry); |
||||||
|
|
||||||
|
Iterator e = paths().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block[] path = (Block[]) e.next(); |
||||||
|
out.println(" path: " + path[0] + " -> " + path[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return "sub " + entry; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,445 @@ |
|||||||
|
/* |
||||||
|
* Class: VerifyCFG |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.cfg; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.tree.DefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.ExprStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.GotoStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.IfStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.JsrStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.RetStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.SwitchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* VerifyCFG visits the nodes in a control flow graph and verifies that certain |
||||||
|
* properties of the graph are true. For instance, value numbers of expressions |
||||||
|
* are not equal to -1, node connections are consistent, exception handlers are |
||||||
|
* set up correctly, etc. Mostly used for debugging purposes. |
||||||
|
*/ |
||||||
|
public class VerifyCFG extends TreeVisitor implements Optimization { |
||||||
|
Block block; // The Block containing the node being visited
|
||||||
|
|
||||||
|
Node parent; // The (expected) parent of the node being visited
|
||||||
|
|
||||||
|
FlowGraph cfg; // The CFG being visited
|
||||||
|
|
||||||
|
Set uses; // Expressions in which a definition is used
|
||||||
|
|
||||||
|
Set nodes; // (Visited) nodes in the CFG
|
||||||
|
|
||||||
|
boolean checkValueNumbers; // Do we check the value numbers of expressions?
|
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
state.controlFlowGraph().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Don't check value numbers. |
||||||
|
*/ |
||||||
|
public VerifyCFG() { |
||||||
|
this(false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Since value numbers are not strictly part of the control |
||||||
|
* flow graph, they may or may not be checked. For instance, if a CFG is |
||||||
|
* being verfied before value numbers are assigned, we would not want to |
||||||
|
* check them. |
||||||
|
* |
||||||
|
* @param checkValueNumbers |
||||||
|
* Are the value numbers of expressions checked? |
||||||
|
*/ |
||||||
|
public VerifyCFG(boolean checkValueNumbers) { |
||||||
|
this.checkValueNumbers = checkValueNumbers; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Verify the specified call flow graph. Does not check the value numbers. |
||||||
|
* |
||||||
|
* @param cfg |
||||||
|
* The call flow graph to verify. |
||||||
|
*/ |
||||||
|
public static void verify(FlowGraph cfg) { |
||||||
|
cfg.visit(new VerifyCFG()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Visit the blocks and expression trees in a control flow graph. Examine |
||||||
|
* the uses of a variable that is defined in the CFG. Make that all uses are |
||||||
|
* reachable (i.e. are in the CFG). |
||||||
|
*/ |
||||||
|
public void visitFlowGraph(FlowGraph cfg) { |
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println("Verifying CFG for " + cfg.method()); |
||||||
|
} |
||||||
|
|
||||||
|
this.cfg = cfg; |
||||||
|
|
||||||
|
uses = new LinkedHashSet(); |
||||||
|
nodes = new LinkedHashSet(); |
||||||
|
|
||||||
|
cfg.visitChildren(this); |
||||||
|
|
||||||
|
Iterator e = uses.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Expr use = (Expr) e.next(); |
||||||
|
Assert.isTrue(nodes.contains(use), "use = " + use + " (" |
||||||
|
+ System.identityHashCode(use) + ") is not in the CFG"); |
||||||
|
} |
||||||
|
|
||||||
|
if (FlowGraph.DEBUG) { |
||||||
|
System.out.println("Verification successful"); |
||||||
|
} |
||||||
|
|
||||||
|
this.cfg = null; |
||||||
|
uses = null; |
||||||
|
nodes = null; |
||||||
|
block = null; |
||||||
|
parent = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* First make sure that the <tt>Block</tt> indeed is in the CFG. If the |
||||||
|
* block begins an exception handler, then make sure that all edges from |
||||||
|
* protected blocks lead to the handler block. Also make sure that all of |
||||||
|
* the handler block's predacessor lead to protected blocks. Finally, make |
||||||
|
* sure that the successor/predacessor relationship holds. |
||||||
|
*/ |
||||||
|
public void visitBlock(Block block) { |
||||||
|
Assert.isTrue(block.graph() == cfg, block + " is not in the CFG"); |
||||||
|
|
||||||
|
Iterator e; |
||||||
|
|
||||||
|
Handler handler = (Handler) cfg.handlersMap().get(block); |
||||||
|
|
||||||
|
// If this block is the first block in an exception handler, make
|
||||||
|
// sure that the only predacessor edges the block has are
|
||||||
|
// protected blocks that may throw the exception handled by the
|
||||||
|
// block. Additionally, we check that there are edges from all
|
||||||
|
// protected blocks to the handler block.
|
||||||
|
//
|
||||||
|
// The predacessor to the first block in an exception handler may
|
||||||
|
// be the init block. However, it is not really a protected
|
||||||
|
// block, so just overlook it.
|
||||||
|
|
||||||
|
if (handler != null) { |
||||||
|
HashSet handlerPreds = new LinkedHashSet(); |
||||||
|
|
||||||
|
e = handler.protectedBlocks().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block prot = (Block) e.next(); |
||||||
|
handlerPreds.add(prot); |
||||||
|
handlerPreds.addAll(cfg.preds(prot)); |
||||||
|
} |
||||||
|
|
||||||
|
HashSet extra = new LinkedHashSet(cfg.preds(block)); |
||||||
|
extra.removeAll(handlerPreds); |
||||||
|
HashSet missing = new LinkedHashSet(handlerPreds); |
||||||
|
missing.removeAll(cfg.preds(block)); |
||||||
|
|
||||||
|
Assert.isTrue((extra.size() == 0 && missing.size() == 0) |
||||||
|
|| (missing.size() == 1 && missing.contains(cfg.init())), |
||||||
|
"Handler prots = " + handlerPreds |
||||||
|
+ " != handler block preds = " + cfg.preds(block) |
||||||
|
+ " extra = " + extra + " missing = " + missing); |
||||||
|
} |
||||||
|
|
||||||
|
// Make sure that the predacessor has a successor and vice versa.
|
||||||
|
e = cfg.preds(block).iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block pred = (Block) e.next(); |
||||||
|
Assert.isTrue(cfg.succs(pred).contains(block), pred |
||||||
|
+ " has no succ " + block); |
||||||
|
Assert.isTrue(cfg.preds(block).contains(pred), block |
||||||
|
+ " has no pred " + pred); |
||||||
|
} |
||||||
|
|
||||||
|
e = cfg.succs(block).iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Block succ = (Block) e.next(); |
||||||
|
Assert.isTrue(cfg.succs(block).contains(succ), block |
||||||
|
+ " has no succ " + succ); |
||||||
|
Assert.isTrue(cfg.preds(succ).contains(block), succ |
||||||
|
+ " has no pred " + block); |
||||||
|
} |
||||||
|
|
||||||
|
this.block = block; |
||||||
|
|
||||||
|
parent = null; |
||||||
|
block.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that all of targets of the <tt>ret</tt> are valid. The |
||||||
|
* targets are the blocks to which the subroutine can return. |
||||||
|
*/ |
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
Set targets = new LinkedHashSet(); |
||||||
|
|
||||||
|
Iterator iter = stmt.sub().paths().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Block[] path = (Block[]) iter.next(); |
||||||
|
targets.add(path[1]); |
||||||
|
} |
||||||
|
|
||||||
|
targets.addAll(stmt.catchTargets()); |
||||||
|
|
||||||
|
verifyTargets(stmt.block(), targets); |
||||||
|
|
||||||
|
visitNode(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that all of the targets of the <tt>jsr</tt> are valid. The |
||||||
|
* only target is the entry block of the subroutine. |
||||||
|
*/ |
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
Set targets = new LinkedHashSet(); |
||||||
|
targets.add(stmt.sub().entry()); |
||||||
|
targets.addAll(stmt.catchTargets()); |
||||||
|
verifyTargets(stmt.block(), targets); |
||||||
|
|
||||||
|
visitNode(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that that all of the targets of the switch are valid. |
||||||
|
*/ |
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
Set targets = new LinkedHashSet(); |
||||||
|
|
||||||
|
targets.add(stmt.defaultTarget()); |
||||||
|
|
||||||
|
for (int i = 0; i < stmt.targets().length; i++) { |
||||||
|
targets.add(stmt.targets()[i]); |
||||||
|
} |
||||||
|
|
||||||
|
targets.addAll(stmt.catchTargets()); |
||||||
|
|
||||||
|
verifyTargets(stmt.block(), targets); |
||||||
|
|
||||||
|
visitNode(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that the targets of the if statement are valid. Targets consist |
||||||
|
* of the true target, the false target, and the first blocks of any |
||||||
|
* exceptions that may be thrown by the if statement. |
||||||
|
*/ |
||||||
|
public void visitIfStmt(IfStmt stmt) { |
||||||
|
Set targets = new LinkedHashSet(); |
||||||
|
targets.add(stmt.trueTarget()); |
||||||
|
targets.add(stmt.falseTarget()); |
||||||
|
targets.addAll(stmt.catchTargets()); |
||||||
|
verifyTargets(stmt.block(), targets); |
||||||
|
|
||||||
|
visitNode(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that the target of <tt>goto</tt> is valid. |
||||||
|
*/ |
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
Set targets = new LinkedHashSet(); |
||||||
|
targets.add(stmt.target()); |
||||||
|
targets.addAll(stmt.catchTargets()); |
||||||
|
verifyTargets(stmt.block(), targets); |
||||||
|
|
||||||
|
visitNode(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Verifies information about the targets of a jump in a given block. First, |
||||||
|
* make sure that the number of targets is the same as the number of |
||||||
|
* sucessor nodes to the block. Make sure that targets of all of the jumps |
||||||
|
* are indeed in the CFG. Make sure that every target is a successor of the |
||||||
|
* block. |
||||||
|
*/ |
||||||
|
private void verifyTargets(Block block, Set targets) { |
||||||
|
Assert.isTrue(targets.size() == cfg.succs(block).size(), block |
||||||
|
+ " has succs " + cfg.succs(block) + " != " + targets + " in " |
||||||
|
+ block.tree().lastStmt()); |
||||||
|
|
||||||
|
Iterator iter = targets.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Block target = (Block) iter.next(); |
||||||
|
Assert.isTrue(block.graph().hasNode(target), target |
||||||
|
+ " is not in the CFG"); |
||||||
|
Assert.isTrue(cfg.succs(block).contains(target), target |
||||||
|
+ " is not a succ of " + block + " " |
||||||
|
+ block.tree().lastStmt()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If desired, makes sure that the store expression's value number is not |
||||||
|
* -1. Makes sure that the store expression's block and parent <tt>Node</tt> |
||||||
|
* are what we expect them to be. If the type of the <tt>StoreExpr</tt> is |
||||||
|
* void, then make sure that its parent is an <tt>ExprStmt</tt> (i.e. make |
||||||
|
* sure it is not nested within another expression). |
||||||
|
*/ |
||||||
|
public void visitStoreExpr(StoreExpr node) { |
||||||
|
nodes.add(node); |
||||||
|
|
||||||
|
if (checkValueNumbers) { |
||||||
|
Assert.isTrue(node.valueNumber() != -1, node |
||||||
|
+ ".valueNumber() = -1"); |
||||||
|
} |
||||||
|
|
||||||
|
Assert.isTrue(node.block() == block, node + ".block() = " |
||||||
|
+ node.block() + " != block = " + block); |
||||||
|
Assert.isTrue(node.parent() == parent, node + ".parent() = " |
||||||
|
+ node.parent() + " != parent = " + parent); |
||||||
|
|
||||||
|
// Visit the MemExpr into which node stores.
|
||||||
|
parent = node; |
||||||
|
node.target().visit(this); |
||||||
|
|
||||||
|
// Visit the expression whose value is being stored by node
|
||||||
|
parent = node; |
||||||
|
node.expr().visit(this); |
||||||
|
|
||||||
|
parent = node.parent(); |
||||||
|
|
||||||
|
if (node.type().equals(Type.VOID)) { |
||||||
|
Assert.isTrue(parent instanceof ExprStmt, "parent of " + node |
||||||
|
+ " = " + parent + " is not an ExprStmt"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that the <tt>Node</tt> resides in the block that we expect it |
||||||
|
* to and that it has the expected parent expression tree <tt>Node</tt>. |
||||||
|
* Make sure that the children of this <tt>Node</tt> are also correct. |
||||||
|
*/ |
||||||
|
public void visitNode(Node node) { |
||||||
|
nodes.add(node); |
||||||
|
|
||||||
|
Assert.isTrue(node.block() == block, node + ".block() = " |
||||||
|
+ node.block() + " != block = " + block); |
||||||
|
Assert.isTrue(node.parent() == parent, node + ".parent() = " |
||||||
|
+ node.parent() + " != parent = " + parent); |
||||||
|
|
||||||
|
final ArrayList children = new ArrayList(); |
||||||
|
|
||||||
|
node.visitChildren(new TreeVisitor() { |
||||||
|
public void visitNode(Node n) { |
||||||
|
children.add(n); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
Iterator e = children.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Node child = (Node) e.next(); |
||||||
|
parent = node; |
||||||
|
child.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
parent = node.parent(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If desired, make sure that the value number of the <tt>Expr</tt> is not |
||||||
|
* -1. |
||||||
|
*/ |
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
if (checkValueNumbers) { |
||||||
|
Assert.isTrue(expr.valueNumber() != -1, expr |
||||||
|
+ ".valueNumber() = -1"); |
||||||
|
} |
||||||
|
|
||||||
|
visitNode(expr); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Keep track of all the uses of the expression defined by the |
||||||
|
* <tt>DefExpr</tt>. This information is used when verifying the |
||||||
|
* <tt>FlowGraph</tt>. |
||||||
|
*/ |
||||||
|
public void visitDefExpr(DefExpr expr) { |
||||||
|
uses.addAll(expr.uses()); |
||||||
|
visitExpr(expr); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make sure that the <tt>VarExpr</tt> either defines a local variable, is |
||||||
|
* defined by another expression, or is the child of a <tt>PhiStmt</tt> |
||||||
|
* (therefore making the <tt>VarExpr</tt> a phi-variable). |
||||||
|
*/ |
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
Assert.isTrue(expr.isDef() || expr.def() != null |
||||||
|
|| expr.parent() instanceof PhiStmt, "Null def for variable " |
||||||
|
+ expr); |
||||||
|
|
||||||
|
visitDefExpr(expr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Classes to represent a Java method as a control flow graph of basic |
||||||
|
blocks. A <em>basic block</em> is a sequence of code that is entered |
||||||
|
only in once place (e.g. the target of a branch statement) and is |
||||||
|
exited at only one place (e.g. a branch statement). Each basic block |
||||||
|
consists of an expression tree. There are also classes to represent |
||||||
|
try-catch blocks, Java subroutines (<tt>finally</tt> blocks), certain |
||||||
|
properties of the control flow graph such as its dominator tree, and |
||||||
|
to visualize a control flow graph.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,47 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
.SUFFIXES: .java .class |
||||||
|
JAVA_HOME = /usr/local
|
||||||
|
CP := $(CLASSPATH)
|
||||||
|
#JAVA_HOME = /gcm/where/jdk/1.3/sparc.Solaris
|
||||||
|
JAVAC = $(JAVA_HOME)/bin/javac
|
||||||
|
JFLAGS = -g
|
||||||
|
CLASSPATH = $(JAVA_HOME)/lib/classes.zip:$(CP)
|
||||||
|
|
||||||
|
all: class |
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f *.class
|
||||||
|
|
||||||
|
class: |
||||||
|
@files=`$(MAKE) -n _class | grep $(JAVAC) | cut -d' ' -f4`; \
|
||||||
|
cpath=$(CLASSPATH):`(cd ../../../../..; pwd)`; \
|
||||||
|
if [ "x$$files" != "x" ]; then \
|
||||||
|
echo $(JAVAC) $(JFLAGS) -classpath $$cpath $$files; \
|
||||||
|
$(JAVAC) $(JFLAGS) -classpath $$cpath $$files; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
_class: $(CLASS) |
||||||
|
|
||||||
|
.java.class: |
||||||
|
cpath=$(CLASSPATH):`(cd ../../../../..; pwd)`; \
|
||||||
|
$(JAVAC) -classpath $$cpath $<
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,823 @@ |
|||||||
|
/* |
||||||
|
* Class: Liveness |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.codegen; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.cfg.Handler; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MemRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiJoinStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Stmt; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
import edu.purdue.cs.bloat.util.Graph; |
||||||
|
import edu.purdue.cs.bloat.util.GraphNode; |
||||||
|
import edu.purdue.cs.bloat.util.ImmutableIterator; |
||||||
|
|
||||||
|
/** |
||||||
|
* 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(FlowGraph cfg) { |
||||||
|
this.cfg = cfg; |
||||||
|
computeIntersections(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a local expression from the interference graph. |
||||||
|
*/ |
||||||
|
public void removeVar(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(VarExpr isLive, Block block) { |
||||||
|
throw new RuntimeException(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Should not be called. |
||||||
|
*/ |
||||||
|
public boolean liveAtEndOfBlock(VarExpr isLive, 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(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() { |
||||||
|
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(VarExpr a, 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 (UNIQUE) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
IGNode na = (IGNode) ig.getNode(a); |
||||||
|
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 LinkedHashMap[cfg.size()]; |
||||||
|
|
||||||
|
Iterator iter = cfg.nodes().iterator(); |
||||||
|
|
||||||
|
// Initialize nodes and nodeIndices
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Block block = (Block) iter.next(); |
||||||
|
int blockIndex = cfg.preOrderIndex(block); |
||||||
|
nodes[blockIndex] = new ArrayList(); |
||||||
|
nodeIndices[blockIndex] = new LinkedHashMap(); |
||||||
|
} |
||||||
|
|
||||||
|
// 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(PhiJoinStmt stmt) { |
||||||
|
if (!(stmt.target() instanceof LocalExpr)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
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.
|
||||||
|
Iterator preds = cfg.preds(block).iterator(); |
||||||
|
|
||||||
|
while (preds.hasNext()) { |
||||||
|
Block pred = (Block) preds.next(); |
||||||
|
int predIndex = cfg.preOrderIndex(pred); |
||||||
|
|
||||||
|
List n = nodes[predIndex]; |
||||||
|
Map indices = nodeIndices[predIndex]; |
||||||
|
|
||||||
|
indices.put(stmt, new Integer(n.size())); |
||||||
|
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(PhiCatchStmt stmt) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStmt(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(Node node) { |
||||||
|
Node p = parent; |
||||||
|
parent = node; |
||||||
|
node.visitChildren(this); |
||||||
|
parent = p; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLocalExpr(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; |
||||||
|
|
||||||
|
List n = nodes[blockIndex]; |
||||||
|
Map indices = nodeIndices[blockIndex]; |
||||||
|
|
||||||
|
Integer i = (Integer) indices.get(parent); |
||||||
|
|
||||||
|
if (i == null) { |
||||||
|
if (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 (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(PhiCatchStmt stmt) { |
||||||
|
NodeInfo info; |
||||||
|
|
||||||
|
List n = nodes[blockIndex]; |
||||||
|
Map indices = nodeIndices[blockIndex]; |
||||||
|
|
||||||
|
Integer i = (Integer) indices.get(stmt); |
||||||
|
|
||||||
|
if (i == null) { |
||||||
|
if (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 (DEBUG) { |
||||||
|
System.out.println("found " + parent + " at " + i); |
||||||
|
} |
||||||
|
|
||||||
|
info = (NodeInfo) n.get(i.intValue()); |
||||||
|
Assert.isTrue(info != null); |
||||||
|
} |
||||||
|
|
||||||
|
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(PhiJoinStmt stmt) { |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// Iterate over all of the nodes in the IG
|
||||||
|
int numDefs = defNodes.size(); |
||||||
|
|
||||||
|
for (int i = 0; i < numDefs; i++) { |
||||||
|
IGNode node = (IGNode) defNodes.get(i); |
||||||
|
LocalExpr def = node.def; |
||||||
|
|
||||||
|
// Set of blocks where this variable is live out (i.e. live on
|
||||||
|
// any of the block's outgoing edges).
|
||||||
|
BitSet m = new BitSet(cfg.size()); |
||||||
|
|
||||||
|
Iterator uses = def.uses().iterator(); |
||||||
|
|
||||||
|
// Look at each use of the local variable
|
||||||
|
while (uses.hasNext()) { |
||||||
|
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 (DEBUG) { |
||||||
|
System.out.println("searching for " + def + " from " |
||||||
|
+ parent); |
||||||
|
} |
||||||
|
|
||||||
|
Block block = parent.block(); |
||||||
|
|
||||||
|
if (parent instanceof PhiJoinStmt) { |
||||||
|
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
|
||||||
|
Iterator preds = cfg.preds(block).iterator(); |
||||||
|
|
||||||
|
while (preds.hasNext()) { |
||||||
|
Block pred = (Block) preds.next(); |
||||||
|
|
||||||
|
if (phi.operandAt(pred) == use) { |
||||||
|
Map indices = nodeIndices[cfg.preOrderIndex(pred)]; |
||||||
|
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.
|
||||||
|
|
||||||
|
Map indices = nodeIndices[cfg.preOrderIndex(block)]; |
||||||
|
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.
|
||||||
|
|
||||||
|
int numPhiCatches = phiCatchNodes.size(); |
||||||
|
|
||||||
|
for (int i = 0; i < numPhiCatches; i++) { |
||||||
|
IGNode node = (IGNode) phiCatchNodes.get(i); |
||||||
|
|
||||||
|
PhiCatchStmt phi = (PhiCatchStmt) node.def.parent(); |
||||||
|
|
||||||
|
Iterator operands = phi.operands().iterator(); |
||||||
|
|
||||||
|
while (operands.hasNext()) { |
||||||
|
LocalExpr operand = (LocalExpr) operands.next(); |
||||||
|
LocalExpr def = (LocalExpr) operand.def(); |
||||||
|
|
||||||
|
if (def != null) { |
||||||
|
IGNode opNode = (IGNode) ig.getNode(def); |
||||||
|
|
||||||
|
// Conflict with everything the operand conflicts with.
|
||||||
|
Iterator edges = new ImmutableIterator(ig.succs(opNode)); |
||||||
|
|
||||||
|
while (edges.hasNext()) { |
||||||
|
IGNode otherNode = (IGNode) edges.next(); |
||||||
|
|
||||||
|
if (otherNode != node) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(otherNode.def |
||||||
|
+ " conflicts with " + opNode.def |
||||||
|
+ " and thus with " + node.def); |
||||||
|
} |
||||||
|
|
||||||
|
ig.addEdge(otherNode, node); |
||||||
|
ig.addEdge(node, otherNode); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (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 phiCatchNode |
||||||
|
* 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(BitSet m, List[] nodes, Block block, int nodeIndex, |
||||||
|
IGNode defNode, Collection phiCatchNodes) { |
||||||
|
boolean firstNode = true; |
||||||
|
|
||||||
|
int blockIndex = cfg.preOrderIndex(block); |
||||||
|
|
||||||
|
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 (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.
|
||||||
|
ListIterator iter = nodes[blockIndex].listIterator(nodeIndex); |
||||||
|
|
||||||
|
while (!stop && iter.hasNext()) { |
||||||
|
NodeInfo info = (NodeInfo) iter.next(); |
||||||
|
|
||||||
|
if (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
|
||||||
|
Iterator e = info.defNodes.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
IGNode node = (IGNode) e.next(); |
||||||
|
|
||||||
|
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()) { |
||||||
|
IGNode catchNode = (IGNode) catchPhis.next(); |
||||||
|
|
||||||
|
PhiCatchStmt phi = (PhiCatchStmt) catchNode.def |
||||||
|
.parent(); |
||||||
|
|
||||||
|
Handler handler = (Handler) cfg.handlersMap().get( |
||||||
|
phi.block()); |
||||||
|
|
||||||
|
Assert.isTrue(handler != null, "Null handler for " |
||||||
|
+ phi.block()); |
||||||
|
|
||||||
|
if (handler.protectedBlocks().contains(block)) { |
||||||
|
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()) { |
||||||
|
LocalExpr expr = (LocalExpr) operands.next(); |
||||||
|
|
||||||
|
if (expr.def() == node.def) { |
||||||
|
continue PHIS; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (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 (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 (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.
|
||||||
|
Iterator preds = cfg.preds(block).iterator(); |
||||||
|
|
||||||
|
while (preds.hasNext()) { |
||||||
|
Block pred = (Block) preds.next(); |
||||||
|
int predIndex = cfg.preOrderIndex(pred); |
||||||
|
|
||||||
|
if (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(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(Node node) { |
||||||
|
this.node = node; |
||||||
|
defNodes = new ArrayList(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Key { |
||||||
|
int blockIndex; |
||||||
|
|
||||||
|
Node node; |
||||||
|
|
||||||
|
public Key(Node node, int blockIndex) { |
||||||
|
this.blockIndex = blockIndex; |
||||||
|
this.node = node; |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return node.hashCode() ^ blockIndex; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj instanceof Key) { |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
CodeGenerator.class\
|
||||||
|
Liveness.class\
|
||||||
|
RegisterAllocator.class
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,752 @@ |
|||||||
|
/* |
||||||
|
* Class: RegisterAllocator |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.codegen; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.tree.ArithExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.InitStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiJoinStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
import edu.purdue.cs.bloat.util.Graph; |
||||||
|
import edu.purdue.cs.bloat.util.GraphNode; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* RegisterAllocator performs analysis on a control flow graph and determines |
||||||
|
* the minimum amount of local variables needed in a method. |
||||||
|
* |
||||||
|
* @see LocalVariable |
||||||
|
*/ |
||||||
|
// Note that RegisterAllocator uses a different IGNode from Liveness!
|
||||||
|
public class RegisterAllocator implements Optimization { |
||||||
|
FlowGraph cfg; |
||||||
|
|
||||||
|
Liveness liveness; |
||||||
|
|
||||||
|
Map colors; |
||||||
|
|
||||||
|
int colorsUsed; |
||||||
|
|
||||||
|
final static float MAX_WEIGHT = Float.MAX_VALUE; |
||||||
|
|
||||||
|
final static float LOOP_FACTOR = 10.0F; |
||||||
|
|
||||||
|
final static int MAX_DEPTH = (int) (Math.log(MAX_WEIGHT) / Math |
||||||
|
.log(LOOP_FACTOR)); |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
transform(state.cfg(), new Liveness(state.cfg())); |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Print a debugging message. Called before #transform(). |
||||||
|
* |
||||||
|
* @see edu.purdue.cs.bloat.optimize.Optimization#preDebugMessage() |
||||||
|
*/ |
||||||
|
public String preDebugMessage() { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Print a debugging message. Called after #transform(). |
||||||
|
* |
||||||
|
* @see edu.purdue.cs.bloat.optimize.Optimization#postDebugMessage() |
||||||
|
*/ |
||||||
|
public String postDebugMessage() { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Builds an interference graph based on the expression nodes |
||||||
|
* found in liveness. Traverses the graph and determines which nodes needs |
||||||
|
* to be precolored and which nodes can be coalesced (move statements). |
||||||
|
* Nodes are coalesced and local variables are assigned to expressions. |
||||||
|
* |
||||||
|
* @see FlowGraph |
||||||
|
* @see LocalVariable |
||||||
|
*/ |
||||||
|
public void transform(FlowGraph cfg, Liveness liveness) { |
||||||
|
this.cfg = cfg; |
||||||
|
this.liveness = liveness; |
||||||
|
colorsUsed = 0; |
||||||
|
colors = new LinkedHashMap(); |
||||||
|
|
||||||
|
// Construct the interference graph.
|
||||||
|
final Graph ig = new Graph(); |
||||||
|
|
||||||
|
Iterator iter = liveness.defs().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
VarExpr def = (VarExpr) iter.next(); |
||||||
|
|
||||||
|
if (!(def instanceof LocalExpr)) { |
||||||
|
// Ignore node in the Liveness IG that are not LocalExprs
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Create a new node in the IG, if one does not already exist
|
||||||
|
IGNode defNode = (IGNode) ig.getNode(def); |
||||||
|
|
||||||
|
if (defNode == null) { |
||||||
|
defNode = new IGNode((LocalExpr) def); |
||||||
|
ig.addNode(def, defNode); |
||||||
|
} |
||||||
|
|
||||||
|
// Examine each variable that interferes with def
|
||||||
|
Iterator intersections = liveness.intersections(def); |
||||||
|
|
||||||
|
while (intersections.hasNext()) { |
||||||
|
VarExpr expr = (VarExpr) intersections.next(); |
||||||
|
|
||||||
|
if (expr == def) { |
||||||
|
// If for some reason, def interferes with itself,
|
||||||
|
// ignore it
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Add an edge in RegisterAllocator's IG between the variables
|
||||||
|
// that interfere
|
||||||
|
if (expr instanceof LocalExpr) { |
||||||
|
IGNode node = (IGNode) ig.getNode(expr); |
||||||
|
|
||||||
|
if (node == null) { |
||||||
|
node = new IGNode((LocalExpr) expr); |
||||||
|
ig.addNode(expr, node); |
||||||
|
} |
||||||
|
|
||||||
|
ig.addEdge(defNode, node); |
||||||
|
ig.addEdge(node, defNode); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Arrays of expressions that invovle a copy of one local variable
|
||||||
|
// to another. Expressions invovled in copies (i.e. "moves") can
|
||||||
|
// be coalesced into one expression.
|
||||||
|
// MODIFIED
|
||||||
|
|
||||||
|
final ArrayList copies = new ArrayList(); |
||||||
|
|
||||||
|
// Nodes that are the targets of InitStmt are considered to be
|
||||||
|
// precolored.
|
||||||
|
final ArrayList precolor = new ArrayList(); |
||||||
|
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
/* |
||||||
|
*/ |
||||||
|
public void visitBlock(Block block) { |
||||||
|
// Don't visit the sink block. There's nothing interesting
|
||||||
|
// there.
|
||||||
|
if (block != RegisterAllocator.this.cfg.sink()) { |
||||||
|
block.visitChildren(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiStmt(PhiStmt stmt) { |
||||||
|
stmt.visitChildren(this); |
||||||
|
|
||||||
|
if (!(stmt.target() instanceof LocalExpr)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// A PhiStmt invovles an assignment (copy). So note the copy
|
||||||
|
// between the target and all of the PhiStmt's operands in the
|
||||||
|
// copies list.
|
||||||
|
|
||||||
|
IGNode lnode = (IGNode) ig.getNode(stmt.target()); |
||||||
|
|
||||||
|
HashSet set = new LinkedHashSet(); |
||||||
|
|
||||||
|
Iterator e = stmt.operands().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Expr op = (Expr) e.next(); |
||||||
|
|
||||||
|
if (op instanceof LocalExpr && op.def() != null) { |
||||||
|
if (!set.contains(op.def())) { |
||||||
|
set.add(op.def()); |
||||||
|
|
||||||
|
if (op.def() != stmt.target()) { |
||||||
|
IGNode rnode = (IGNode) ig.getNode(op.def()); |
||||||
|
copies.add(new IGNode[] { lnode, rnode }); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
|
||||||
|
if (!(expr.target() instanceof LocalExpr)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
IGNode lnode = (IGNode) ig.getNode(expr.target()); |
||||||
|
|
||||||
|
if (expr.expr() instanceof LocalExpr |
||||||
|
&& expr.expr().def() != null) { |
||||||
|
|
||||||
|
// A store of a variable into another variable is a copy
|
||||||
|
IGNode rnode = (IGNode) ig.getNode(expr.expr().def()); |
||||||
|
copies.add(new IGNode[] { lnode, rnode }); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Treat L := L + k as a copy so that they get converted
|
||||||
|
// back to iincs.
|
||||||
|
if (expr.target().type().equals(Type.INT)) { |
||||||
|
if (!(expr.expr() instanceof ArithExpr)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// We're dealing with integer arithmetic. Remember that
|
||||||
|
// an
|
||||||
|
// ArithExpr has a left and a right operand. If one of
|
||||||
|
// the
|
||||||
|
// operands is a variable and if the other is a constant
|
||||||
|
// and
|
||||||
|
// the operation is addition or substraction, we have an
|
||||||
|
// increment.
|
||||||
|
|
||||||
|
ArithExpr rhs = (ArithExpr) expr.expr(); |
||||||
|
LocalExpr var = null; |
||||||
|
|
||||||
|
Integer value = null; |
||||||
|
|
||||||
|
if (rhs.left() instanceof LocalExpr |
||||||
|
&& rhs.right() instanceof ConstantExpr) { |
||||||
|
|
||||||
|
var = (LocalExpr) rhs.left(); |
||||||
|
|
||||||
|
ConstantExpr c = (ConstantExpr) rhs.right(); |
||||||
|
|
||||||
|
if (c.value() instanceof Integer) { |
||||||
|
value = (Integer) c.value(); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (rhs.right() instanceof LocalExpr |
||||||
|
&& rhs.left() instanceof ConstantExpr) { |
||||||
|
|
||||||
|
var = (LocalExpr) rhs.right(); |
||||||
|
|
||||||
|
ConstantExpr c = (ConstantExpr) rhs.left(); |
||||||
|
|
||||||
|
if (c.value() instanceof Integer) { |
||||||
|
value = (Integer) c.value(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (rhs.operation() == ArithExpr.SUB) { |
||||||
|
if (value != null) { |
||||||
|
value = new Integer(-value.intValue()); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (rhs.operation() != ArithExpr.ADD) { |
||||||
|
value = null; |
||||||
|
} |
||||||
|
|
||||||
|
if (value != null && var.def() != null) { |
||||||
|
int incr = value.intValue(); |
||||||
|
|
||||||
|
if ((short) incr == incr) { |
||||||
|
// Only generate an iinc if the increment
|
||||||
|
// fits in a short
|
||||||
|
IGNode rnode = (IGNode) ig.getNode(var.def()); |
||||||
|
copies.add(new IGNode[] { lnode, rnode }); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
*/ |
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
stmt.visitChildren(this); |
||||||
|
|
||||||
|
// The initialized variables are precolored.
|
||||||
|
LocalExpr[] t = stmt.targets(); |
||||||
|
|
||||||
|
for (int i = 0; i < t.length; i++) { |
||||||
|
precolor.add(t[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// Coalesce move related nodes, maximum weight first.
|
||||||
|
/* |
||||||
|
*/ |
||||||
|
|
||||||
|
while (copies.size() > 0) { |
||||||
|
// We want the copy (v <- w) with the maximum:
|
||||||
|
// weight(v) + weight(w)
|
||||||
|
// ---------------------
|
||||||
|
// size(union)
|
||||||
|
// where union is the intersection of the nodes that conflict
|
||||||
|
// with v and the nodes that conflict with w. This equation
|
||||||
|
// appears to be in conflict with the one given on page 38 of
|
||||||
|
// Nate's thesis.
|
||||||
|
|
||||||
|
HashSet union; // The union of neighboring nodes
|
||||||
|
|
||||||
|
int max = 0; |
||||||
|
|
||||||
|
IGNode[] copy = (IGNode[]) copies.get(max); |
||||||
|
|
||||||
|
float maxWeight = copy[0].weight + copy[1].weight; |
||||||
|
union = new LinkedHashSet(); |
||||||
|
union.addAll(ig.succs(copy[0])); |
||||||
|
union.addAll(ig.succs(copy[1])); |
||||||
|
maxWeight /= union.size(); |
||||||
|
|
||||||
|
for (int i = 1; i < copies.size(); i++) { |
||||||
|
copy = (IGNode[]) copies.get(i); |
||||||
|
|
||||||
|
float weight = copy[0].weight + copy[1].weight; |
||||||
|
union.clear(); |
||||||
|
union.addAll(ig.succs(copy[0])); |
||||||
|
union.addAll(ig.succs(copy[1])); |
||||||
|
weight /= union.size(); |
||||||
|
|
||||||
|
if (weight > maxWeight) { |
||||||
|
// The ith copy has the maximum weight
|
||||||
|
maxWeight = weight; |
||||||
|
max = i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Remove the copy with the max weight from the copies list. He
|
||||||
|
// does it in a rather round-about way.
|
||||||
|
copy = (IGNode[]) copies.get(max); |
||||||
|
copies.set(max, copies.get(copies.size() - 1)); |
||||||
|
copies.remove(copies.size() - 1); |
||||||
|
|
||||||
|
if (!ig.hasEdge(copy[0], copy[1])) { |
||||||
|
// If the variables involved in the copy do not interfere with
|
||||||
|
// each other, they are coalesced.
|
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println("coalescing " + copy[0] + " " + copy[1]); |
||||||
|
System.out.println(" 0 conflicts " + ig.succs(copy[0])); |
||||||
|
System.out.println(" 1 conflicts " + ig.succs(copy[1])); |
||||||
|
} |
||||||
|
|
||||||
|
ig.succs(copy[0]).addAll(ig.succs(copy[1])); |
||||||
|
ig.preds(copy[0]).addAll(ig.preds(copy[1])); |
||||||
|
|
||||||
|
copy[0].coalesce(copy[1]); |
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println(" coalesced " + copy[0]); |
||||||
|
System.out.println(" conflicts " + ig.succs(copy[0])); |
||||||
|
} |
||||||
|
|
||||||
|
// Remove coalesced node from the IG
|
||||||
|
ig.removeNode(copy[1].key); |
||||||
|
|
||||||
|
iter = copies.iterator(); |
||||||
|
|
||||||
|
// Examine all copies. If the copy involves the node that was
|
||||||
|
// coalesced, the copy is no longer interesting. Remove it.
|
||||||
|
while (iter.hasNext()) { |
||||||
|
IGNode[] c = (IGNode[]) iter.next(); |
||||||
|
|
||||||
|
if (c[0] == copy[1] || c[1] == copy[1]) { |
||||||
|
iter.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
/* |
||||||
|
*/ |
||||||
|
// Create a list of uncolored nodes.
|
||||||
|
ArrayList uncoloredNodes = new ArrayList(); |
||||||
|
|
||||||
|
Iterator nodes = ig.nodes().iterator(); |
||||||
|
|
||||||
|
while (nodes.hasNext()) { |
||||||
|
IGNode node = (IGNode) nodes.next(); |
||||||
|
|
||||||
|
ArrayList p = new ArrayList(precolor); |
||||||
|
p.retainAll(node.defs); |
||||||
|
|
||||||
|
// See if any node got coalesced with a precolored node.
|
||||||
|
if (p.size() == 1) { |
||||||
|
// Precolored
|
||||||
|
node.color = ((LocalExpr) p.get(0)).index(); |
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println("precolored " + node + " " + node.color); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (p.size() == 0) { |
||||||
|
// Uncolored (i.e. not coalesced with any of the pre-colored
|
||||||
|
// nodes.
|
||||||
|
node.color = -1; |
||||||
|
uncoloredNodes.add(node); |
||||||
|
|
||||||
|
} else { |
||||||
|
// If two or more pre-colored nodes were coalesced, we have a
|
||||||
|
// problem.
|
||||||
|
throw new RuntimeException("coalesced pre-colored defs " + p); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// MOD
|
||||||
|
/* |
||||||
|
* Iterator inits = precolor.iterator(); while (inits.hasNext()) { |
||||||
|
* VarExpr def = (VarExpr) inits.next(); IGNode defNode = (IGNode) |
||||||
|
* ig.getNode(def); |
||||||
|
* |
||||||
|
* Iterator succs = ig.succs(defNode).iterator(); |
||||||
|
* |
||||||
|
* |
||||||
|
* if (defNode.wide) { // Wide variables need two colors defNode.color =
|
||||||
|
* colorsUsed; |
||||||
|
* |
||||||
|
* if (CodeGenerator.DEBUG) { System.out.println(" assigning color " + |
||||||
|
* colorsUsed + " to " + defNode); } colorsUsed=colorsUsed+2; ; } else { |
||||||
|
* defNode.color = colorsUsed; |
||||||
|
* |
||||||
|
* if (CodeGenerator.DEBUG) { System.out.println(" assigning color " + |
||||||
|
* colorsUsed + " to " + defNode); } colorsUsed++; } } |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
// END MOD
|
||||||
|
// Sort the uncolored nodes, by decreasing weight. Wide nodes
|
||||||
|
// have half their original weight since they take up two indices
|
||||||
|
// and we want to put color nodes with the lower indices.
|
||||||
|
Collections.sort(uncoloredNodes, new Comparator() { |
||||||
|
public int compare(Object a, Object b) { |
||||||
|
IGNode na = (IGNode) a; |
||||||
|
IGNode nb = (IGNode) b; |
||||||
|
|
||||||
|
float wa = na.weight / ig.succs(na).size(); |
||||||
|
float wb = nb.weight / ig.succs(nb).size(); |
||||||
|
|
||||||
|
if (na.wide) { |
||||||
|
wa /= 2; |
||||||
|
} |
||||||
|
|
||||||
|
if (nb.wide) { |
||||||
|
wb /= 2; |
||||||
|
} |
||||||
|
|
||||||
|
if (wb > wa) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
if (wb < wa) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
nodes = uncoloredNodes.iterator(); |
||||||
|
|
||||||
|
while (nodes.hasNext()) { |
||||||
|
IGNode node = (IGNode) nodes.next(); |
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println("coloring " + node); |
||||||
|
System.out.println(" conflicts " + ig.succs(node)); |
||||||
|
} |
||||||
|
|
||||||
|
// Make sure node has not been colored
|
||||||
|
Assert.isTrue(node.color == -1); |
||||||
|
|
||||||
|
// Determine which colors have been assigned to the nodes
|
||||||
|
// conflicting with the node of interest
|
||||||
|
BitSet used = new BitSet(); |
||||||
|
|
||||||
|
Iterator succs = ig.succs(node).iterator(); |
||||||
|
|
||||||
|
while (succs.hasNext()) { |
||||||
|
IGNode succ = (IGNode) succs.next(); |
||||||
|
|
||||||
|
if (succ.color != -1) { |
||||||
|
used.set(succ.color); |
||||||
|
|
||||||
|
if (succ.wide) { |
||||||
|
used.set(succ.color + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Find the next available color
|
||||||
|
for (int i = 0; node.color == -1; i++) { |
||||||
|
if (!used.get(i)) { |
||||||
|
if (node.wide) { |
||||||
|
// Wide variables need two colors
|
||||||
|
if (!used.get(i + 1)) { |
||||||
|
node.color = i; |
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println(" assigning color " + i |
||||||
|
+ " to " + node); |
||||||
|
} |
||||||
|
|
||||||
|
if (i + 1 >= colorsUsed) { |
||||||
|
colorsUsed = i + 2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
node.color = i; |
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println(" assigning color " + i |
||||||
|
+ " to " + node); |
||||||
|
} |
||||||
|
|
||||||
|
if (i >= colorsUsed) { |
||||||
|
colorsUsed = i + 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
nodes = ig.nodes().iterator(); |
||||||
|
|
||||||
|
while (nodes.hasNext()) { |
||||||
|
IGNode node = (IGNode) nodes.next(); |
||||||
|
|
||||||
|
// Make sure each node has been colored
|
||||||
|
Assert.isTrue(node.color != -1, "No color for " + node); |
||||||
|
|
||||||
|
iter = node.defs.iterator(); |
||||||
|
|
||||||
|
// Set the index of the variable and all of its uses to be the
|
||||||
|
// chosen color.
|
||||||
|
while (iter.hasNext()) { |
||||||
|
LocalExpr def = (LocalExpr) iter.next(); |
||||||
|
def.setIndex(node.color); |
||||||
|
|
||||||
|
Iterator uses = def.uses().iterator(); |
||||||
|
|
||||||
|
while (uses.hasNext()) { |
||||||
|
LocalExpr use = (LocalExpr) uses.next(); |
||||||
|
use.setIndex(node.color); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (CodeGenerator.DEBUG) { |
||||||
|
System.out.println("After allocating locals--------------------"); |
||||||
|
cfg.print(System.out); |
||||||
|
System.out.println("End print----------------------------------"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the maximum number of local variables used by the cfg after its |
||||||
|
* "registers" (local variables) have been allocated. |
||||||
|
*/ |
||||||
|
public int maxLocals() { |
||||||
|
return colorsUsed; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new local variable in this method (as modeled by the cfg). |
||||||
|
* Updates the number of local variables appropriately. |
||||||
|
*/ |
||||||
|
public LocalVariableGen newLocal(Type type) { |
||||||
|
// Why don't we add Type information to the LocalVariable? Are we
|
||||||
|
// assuming that type checking has already been done and so its a
|
||||||
|
// moot point?
|
||||||
|
|
||||||
|
LocalVariableGen var = new LocalVariableGen(colorsUsed, "retAdr" |
||||||
|
+ colorsUsed, type, null, null); |
||||||
|
colorsUsed += type.getSize(); |
||||||
|
return var; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* IGNode is a node in the interference graph. Note that this node is |
||||||
|
* different from the one in Liveness. For instance, this one stores |
||||||
|
* information about a node's color, its weight, etc. Because nodes may be |
||||||
|
* coalesced, an IGNode may represent more than one LocalExpr. That's why |
||||||
|
* there is a list of definitions. |
||||||
|
*/ |
||||||
|
class IGNode extends GraphNode { |
||||||
|
Set defs; |
||||||
|
|
||||||
|
LocalExpr key; |
||||||
|
|
||||||
|
int color; |
||||||
|
|
||||||
|
boolean wide; // Is the variable wide?
|
||||||
|
|
||||||
|
float weight; |
||||||
|
|
||||||
|
public IGNode(LocalExpr def) { |
||||||
|
color = -1; |
||||||
|
key = def; |
||||||
|
defs = new LinkedHashSet(); |
||||||
|
defs.add(def); |
||||||
|
wide = (def.type().getSize() == 2); |
||||||
|
computeWeight(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Coalesce two nodes in the interference graph. The weight of the other |
||||||
|
* node is added to that of this node. This node also inherits all of |
||||||
|
* the definitions of the other node. |
||||||
|
*/ |
||||||
|
void coalesce(IGNode node) { |
||||||
|
Assert.isTrue(wide == node.wide); |
||||||
|
|
||||||
|
weight += node.weight; |
||||||
|
|
||||||
|
Iterator iter = node.defs.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
LocalExpr def = (LocalExpr) iter.next(); |
||||||
|
defs.add(def); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return "(color=" + color + " weight=" + weight + " " |
||||||
|
+ defs.toString() + ")"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Calculates the weight of a Block based on its loop depth. If the |
||||||
|
* block does not exceed the MAX_DEPTH, then the weight is LOOP_FACTOR |
||||||
|
* raised to the depth. |
||||||
|
*/ |
||||||
|
private float blockWeight(Block block) { |
||||||
|
int depth = cfg.loopDepth(block); |
||||||
|
|
||||||
|
if (depth > MAX_DEPTH) { |
||||||
|
return MAX_WEIGHT; |
||||||
|
} |
||||||
|
|
||||||
|
float w = 1.0F; |
||||||
|
|
||||||
|
while (depth-- > 0) { |
||||||
|
w *= LOOP_FACTOR; |
||||||
|
} |
||||||
|
|
||||||
|
return w; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Computes the weight of a node in the interference graph. The weight |
||||||
|
* is based on where the variable represented by this node is used. The |
||||||
|
* method blockWeight is used to determine the weight of a variable used |
||||||
|
* in a block based on the loop depth of the block. Special care must be |
||||||
|
* taken if the variable is used in a PhiStmt. |
||||||
|
*/ |
||||||
|
private void computeWeight() { |
||||||
|
weight = 0.0F; |
||||||
|
|
||||||
|
Iterator iter = defs.iterator(); |
||||||
|
|
||||||
|
// Look at all(?) of the definitions of the IGNode
|
||||||
|
while (iter.hasNext()) { |
||||||
|
LocalExpr def = (LocalExpr) iter.next(); |
||||||
|
|
||||||
|
weight += blockWeight(def.block()); |
||||||
|
|
||||||
|
Iterator uses = def.uses().iterator(); |
||||||
|
|
||||||
|
// If the variable is used as an operand to a PhiJoinStmt,
|
||||||
|
// find the predacessor block to the PhiJoinStmt in which the
|
||||||
|
// variable occurs and add the weight of that block to the
|
||||||
|
// running total weight.
|
||||||
|
while (uses.hasNext()) { |
||||||
|
LocalExpr use = (LocalExpr) uses.next(); |
||||||
|
|
||||||
|
if (use.parent() instanceof PhiJoinStmt) { |
||||||
|
PhiJoinStmt phi = (PhiJoinStmt) use.parent(); |
||||||
|
|
||||||
|
Iterator preds = cfg.preds(phi.block()).iterator(); |
||||||
|
|
||||||
|
while (preds.hasNext()) { |
||||||
|
Block pred = (Block) preds.next(); |
||||||
|
Expr op = phi.operandAt(pred); |
||||||
|
|
||||||
|
if (use == op) { |
||||||
|
weight += blockWeight(pred); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else if (use.parent() instanceof PhiCatchStmt) { |
||||||
|
// If the variable is used in a PhiCatchStmt, add the
|
||||||
|
// weight of the block in which the variable is defined
|
||||||
|
// to
|
||||||
|
// the running total.
|
||||||
|
weight += blockWeight(use.def().block()); |
||||||
|
|
||||||
|
} else { |
||||||
|
// Just add in the weight of the block in which the
|
||||||
|
// variable is used.
|
||||||
|
weight += blockWeight(use.block()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Generates Java bytecodes from the contents of a control flow graph. |
||||||
|
It also performs "register" allocation of the local variables inside |
||||||
|
the virtual machine.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,295 @@ |
|||||||
|
/* |
||||||
|
* Class: BloatContext |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.context; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
import org.apache.bcel.util.Repository; |
||||||
|
import org.apache.bcel.verifier.structurals.UninitializedObjectType; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
import edu.purdue.cs.bloat.inline.CallGraph; |
||||||
|
import edu.purdue.cs.bloat.inline.InlineContext; |
||||||
|
import edu.purdue.cs.bloat.inline.InlineStats; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* This abstract class is a central repository for all things that are necessary |
||||||
|
* for a BLOATing sessions. Its subclasses implement certain schemes for |
||||||
|
* managing BLOAT data structures such as editors and control flow graphs. |
||||||
|
*/ |
||||||
|
public abstract class BloatContext implements InlineContext { |
||||||
|
public static boolean DEBUG = Boolean.getBoolean("BloatContext.DEBUG"); |
||||||
|
|
||||||
|
protected InlineStats inlineStats; |
||||||
|
|
||||||
|
// Ignore stuff for inlining
|
||||||
|
protected Set ignorePackages = new LinkedHashSet(); |
||||||
|
|
||||||
|
protected Set ignoreClasses = new LinkedHashSet(); |
||||||
|
|
||||||
|
protected Set ignoreMethods = new LinkedHashSet(); |
||||||
|
|
||||||
|
protected Set ignoreFields = new LinkedHashSet(); |
||||||
|
|
||||||
|
protected boolean ignoreSystem = false; |
||||||
|
|
||||||
|
protected CallGraph callGraph; |
||||||
|
|
||||||
|
protected Set roots; // Root methods of call graph
|
||||||
|
|
||||||
|
protected static void db(String s) { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println(s); |
||||||
|
} |
||||||
|
|
||||||
|
protected Repository loader; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Each <tt>BloatContext</tt> needs to know about a |
||||||
|
* <tt>ClassInfoLoader</tt>. |
||||||
|
*/ |
||||||
|
public BloatContext(Repository loader) { |
||||||
|
this.loader = loader; |
||||||
|
} |
||||||
|
|
||||||
|
private static ClassLoader systemCL; |
||||||
|
static { |
||||||
|
String s = ""; |
||||||
|
systemCL = s.getClass().getClassLoader(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns <tt>true</tt> if the give type is a system class (that is, has |
||||||
|
* the same class loader as java.lang.String). |
||||||
|
*/ |
||||||
|
public static boolean isSystem(ObjectType type) { |
||||||
|
Class c = null; |
||||||
|
try { |
||||||
|
c = Class.forName(type.getClassName().replace('/', '.')); |
||||||
|
|
||||||
|
} catch (ClassNotFoundException ex) { |
||||||
|
System.err |
||||||
|
.println("** Could not find class " + type.getClassName()); |
||||||
|
ex.printStackTrace(System.err); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
// Have to use == because class loader might be null
|
||||||
|
return (c.getClassLoader() == systemCL); |
||||||
|
} |
||||||
|
|
||||||
|
public void setRootMethods(Set roots) { |
||||||
|
if (this.callGraph != null) { |
||||||
|
// Can't set the call graph roots after its been created
|
||||||
|
throw new IllegalStateException("Cannot set roots after " |
||||||
|
+ "call graph has been created"); |
||||||
|
} |
||||||
|
|
||||||
|
this.roots = roots; |
||||||
|
} |
||||||
|
|
||||||
|
public CallGraph getCallGraph() { |
||||||
|
if (this.callGraph == null) { |
||||||
|
// Create a new CallGraph
|
||||||
|
this.callGraph = new CallGraph(this, this.roots); |
||||||
|
} |
||||||
|
return (this.callGraph); |
||||||
|
} |
||||||
|
|
||||||
|
public InlineStats getInlineStats() { |
||||||
|
if (inlineStats == null) { |
||||||
|
inlineStats = new InlineStats(); |
||||||
|
} |
||||||
|
return (inlineStats); |
||||||
|
} |
||||||
|
|
||||||
|
public void addIgnorePackage(String name) { |
||||||
|
name = name.replace('.', '/'); |
||||||
|
ignorePackages.add(name); |
||||||
|
} |
||||||
|
|
||||||
|
public void addIgnoreClass(Type type) { |
||||||
|
ignoreClasses.add(type); |
||||||
|
} |
||||||
|
|
||||||
|
public void addIgnoreMethod(MethodRef method) { |
||||||
|
ignoreMethods.add(method); |
||||||
|
} |
||||||
|
|
||||||
|
public void addIgnoreField(MemberRef field) { |
||||||
|
ignoreFields.add(field); |
||||||
|
} |
||||||
|
|
||||||
|
public void setIgnoreSystem(boolean ignore) { |
||||||
|
this.ignoreSystem = ignore; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean ignoreClass(Type type) { |
||||||
|
// First, check to see if we explicitly ignore it. If not, check
|
||||||
|
// to see if we ignore its package. The ladies always seem to
|
||||||
|
// ignore my package.
|
||||||
|
if (type instanceof ReferenceType) |
||||||
|
if (type instanceof ArrayType) |
||||||
|
type = ((ArrayType) type).getBasicType(); |
||||||
|
else if (type instanceof UninitializedObjectType) |
||||||
|
type = ((UninitializedObjectType) type).getInitialized(); |
||||||
|
// CONVERT ARRAYTYPES ETC TO OBJECTTYPES OR BASICTYPES
|
||||||
|
|
||||||
|
if (ignoreClasses.contains(type)) { |
||||||
|
return (true); |
||||||
|
|
||||||
|
} else if (type instanceof BasicType) { |
||||||
|
addIgnoreClass(type); |
||||||
|
return (true); |
||||||
|
|
||||||
|
} else { |
||||||
|
ObjectType objType = (ObjectType) type; |
||||||
|
if (this.ignoreSystem) { |
||||||
|
if (isSystem(objType)) { |
||||||
|
addIgnoreClass(objType); |
||||||
|
return (true); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
String packageName = objType.getClassName(); |
||||||
|
int lastSlash = packageName.lastIndexOf('/'); |
||||||
|
|
||||||
|
if (lastSlash == -1) { |
||||||
|
return (false); |
||||||
|
} |
||||||
|
|
||||||
|
packageName = packageName.substring(0, lastSlash); |
||||||
|
|
||||||
|
// If any ignore package is a prefix of the class's package,
|
||||||
|
// then ignore it. This makes our lives easier.
|
||||||
|
Iterator packages = ignorePackages.iterator(); |
||||||
|
while (packages.hasNext()) { |
||||||
|
String s = (String) packages.next(); |
||||||
|
if (objType.getClassName().startsWith(s)) { |
||||||
|
addIgnoreClass(type); |
||||||
|
return (true); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return (false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean ignoreMethod(MethodRef method) { |
||||||
|
if (ignoreMethods.contains(method)) { |
||||||
|
return (true); |
||||||
|
|
||||||
|
} else if (ignoreClass(method.declaringClass())) { |
||||||
|
addIgnoreMethod(method); |
||||||
|
return (true); |
||||||
|
} |
||||||
|
return (false); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean ignoreField(MemberRef field) { |
||||||
|
if (ignoreMethods.contains(field)) { |
||||||
|
return (true); |
||||||
|
|
||||||
|
} else if (ignoreClass(field.declaringClass())) { |
||||||
|
addIgnoreField(field); |
||||||
|
return (true); |
||||||
|
} |
||||||
|
return (false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits all classes, methods, and fields, that have been modified. |
||||||
|
*/ |
||||||
|
public abstract void commitDirty(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Test the ignore stuff. |
||||||
|
*/ |
||||||
|
public static void main(String[] args) { |
||||||
|
PrintWriter out = new PrintWriter(System.out, true); |
||||||
|
PrintWriter err = new PrintWriter(System.err, true); |
||||||
|
|
||||||
|
BloatContext context = new PersistentBloatContext( |
||||||
|
org.apache.bcel.Repository.getRepository()); |
||||||
|
// new CachingBloatContext(new ClassFileLoader(), new ArrayList(),
|
||||||
|
// false);
|
||||||
|
|
||||||
|
List types = new ArrayList(); |
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) { |
||||||
|
if (args[i].equals("-ip")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
err.println("** Missing package name"); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
out.println("Ignoring package " + args[i]); |
||||||
|
context.addIgnorePackage(args[i]); |
||||||
|
|
||||||
|
} else if (args[i].equals("-ic")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
err.println("** Missing class name"); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
out.println("Ignoring class " + args[i]); |
||||||
|
String type = args[i].replace('.', '/'); |
||||||
|
context.addIgnoreClass(Type.getType("L" + type + ";")); |
||||||
|
|
||||||
|
} else { |
||||||
|
// A type
|
||||||
|
String type = args[i].replace('.', '/'); |
||||||
|
types.add(Type.getType("L" + type + ";")); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
out.println(""); |
||||||
|
|
||||||
|
Iterator iter = types.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
Type type = (Type) iter.next(); |
||||||
|
out.println("Ignore " + type + "? " + context.ignoreClass(type)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
BloatContext.class\
|
||||||
|
PersistentBloatContext.class
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,483 @@ |
|||||||
|
/* |
||||||
|
* Class: PersistentBloatContext |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.context; |
||||||
|
|
||||||
|
import org.apache.bcel.verifier.structurals.UninitializedObjectType; |
||||||
|
import org.apache.bcel.util.Repository; |
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
import org.apache.bcel.classfile.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.ClassHierarchy; |
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
import edu.purdue.cs.bloat.editor.NameAndType; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Maintains all BLOAT data structures as if they were meant to reside in a |
||||||
|
* persistent store. As a result, it keeps every piece of BLOAT data around |
||||||
|
* because it might be needed in the future. No fancing cache maintainence is |
||||||
|
* performed. Because we are going for maximum information we take the closure |
||||||
|
* of classes when working with the class hierarchy. |
||||||
|
*/ |
||||||
|
public class PersistentBloatContext extends BloatContext { |
||||||
|
|
||||||
|
protected final ClassHierarchy hierarchy; |
||||||
|
|
||||||
|
protected Map classEditors; // Maps ClassInfos to ClassEditors
|
||||||
|
|
||||||
|
protected Map classInfos; // Maps ClassInfos to ClassEditors
|
||||||
|
|
||||||
|
public static boolean DB_COMMIT = true; |
||||||
|
|
||||||
|
protected static void comm(String s) { |
||||||
|
if (DB_COMMIT || DEBUG) { |
||||||
|
System.out.println(s); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Each <tt>BloatContext</tt> stems from a |
||||||
|
* <tt>ClassInfoLoader</tt>. Using the loader it can create an |
||||||
|
* <tt>Editor</tt> and such. Initially, no classes are loaded. |
||||||
|
*/ |
||||||
|
public PersistentBloatContext(Repository loader) { |
||||||
|
this(loader, true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. It is the responsibility of the subclasses to add classes to |
||||||
|
* the hierarchy by calling <tt>addClasses</tt>. |
||||||
|
* |
||||||
|
* @param loader |
||||||
|
* Used to load classes |
||||||
|
* @param closure |
||||||
|
* Do we look for the maximum number of classes? |
||||||
|
*/ |
||||||
|
public PersistentBloatContext(Repository loader, boolean closure) { |
||||||
|
super(loader); |
||||||
|
db("Creating a new BloatContext"); |
||||||
|
|
||||||
|
// Create a bunch of the mappings we maintain. Make sure to do
|
||||||
|
// this before anything else!
|
||||||
|
|
||||||
|
classEditors = new LinkedHashMap(); |
||||||
|
classInfos = new LinkedHashMap(); |
||||||
|
|
||||||
|
// Have to create an empty class hierarchy then add the classes.
|
||||||
|
// There is a strange circular dependence between the hierarchy
|
||||||
|
// and the context.
|
||||||
|
this.hierarchy = new ClassHierarchy(this, new ArrayList(), closure); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a bunch of (names of) classes to the hierarchy. |
||||||
|
*/ |
||||||
|
protected void addClasses(Collection classes) { |
||||||
|
Iterator iter = classes.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
String className = (String) iter.next(); |
||||||
|
this.hierarchy.addClassNamed(className); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public JavaClass loadClass(String className) throws ClassNotFoundException { |
||||||
|
// Lots of interesting stuff to do here. For the moment, just
|
||||||
|
// load the class from the ClassInfoLoader and add it to the
|
||||||
|
// hierarchy.
|
||||||
|
|
||||||
|
className = className.replace('.', '/'); |
||||||
|
|
||||||
|
// Check the cache of ClassInfos
|
||||||
|
JavaClass info = (JavaClass) classInfos.get(className); |
||||||
|
|
||||||
|
if (info == null) { |
||||||
|
db("BloatContext: Loading class " + className); |
||||||
|
info = loader.loadClass(className); |
||||||
|
hierarchy.addClassNamed(className); |
||||||
|
db("loadClass: " + className + " -> " + info); |
||||||
|
classInfos.put(className, info); |
||||||
|
} |
||||||
|
|
||||||
|
return (info); |
||||||
|
} |
||||||
|
|
||||||
|
public JavaClass newClassInfo(int class_name_index, |
||||||
|
int superclass_name_index, String file_name, int major, int minor, |
||||||
|
int access_flags, ConstantPool constant_pool, int[] interfaces, |
||||||
|
Field[] fields, Method[] methods, Attribute[] attributes) { |
||||||
|
JavaClass jc = new JavaClass(class_name_index, superclass_name_index, |
||||||
|
file_name, major, minor, access_flags, constant_pool, |
||||||
|
interfaces, fields, methods, attributes); |
||||||
|
String className = jc.getClassName(); |
||||||
|
|
||||||
|
db("newClassEditor(...........): " + className + " -> " + jc); |
||||||
|
|
||||||
|
classInfos.put(className, jc); |
||||||
|
return jc; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassGen newClass(int accessflags, String className, |
||||||
|
String file_name, Type superType, Type[] interfaces) { |
||||||
|
String[] interNames = new String[interfaces.length]; |
||||||
|
for (int i = 0; i < interfaces.length; i++) { |
||||||
|
interNames[i] = ((ObjectType) interfaces[i]).getClassName(); |
||||||
|
} |
||||||
|
|
||||||
|
ClassGen cg = new ClassGen(className, ((ObjectType) superType) |
||||||
|
.getClassName(), file_name, accessflags, interNames); |
||||||
|
JavaClass jc = cg.getJavaClass(); |
||||||
|
String classname = cg.getClassName(); |
||||||
|
db("newClassInfo(.....): " + classname + " -> " + cg); |
||||||
|
classEditors.put(classname, cg); |
||||||
|
classInfos.put(classname, jc); |
||||||
|
return cg; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* public ClassInfo newClassInfo(int modifiers, int classIndex, int |
||||||
|
* superClassIndex, int[] interfaceIndexes, List constants) { |
||||||
|
* |
||||||
|
* return this.loader.storeClass(modifiers, classIndex, superClassIndex, |
||||||
|
* interfaceIndexes, constants); } |
||||||
|
*/ |
||||||
|
|
||||||
|
public ClassHierarchy getHierarchy() { |
||||||
|
return (this.hierarchy); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassGen newClass(int class_name_index, int superclass_name_index, |
||||||
|
String file_name, int major, int minor, int access_flags, |
||||||
|
ConstantPool constant_pool, int[] interfaces, Field[] fields, |
||||||
|
Method[] methods, Attribute[] attributes) { |
||||||
|
JavaClass jc = new JavaClass(class_name_index, superclass_name_index, |
||||||
|
file_name, major, minor, access_flags, constant_pool, |
||||||
|
interfaces, fields, methods, attributes); |
||||||
|
|
||||||
|
ClassGen ce = new ClassGen(jc); |
||||||
|
|
||||||
|
String className = ce.getClassName(); |
||||||
|
|
||||||
|
db("editClass(ClassInfo): " + className + " -> " + ce); |
||||||
|
|
||||||
|
classEditors.put(className, ce); |
||||||
|
classInfos.put(className, jc); |
||||||
|
return ce; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassGen editClass(String className) throws ClassNotFoundException, |
||||||
|
ClassFormatException { |
||||||
|
// Only make the name -> classInfo mapping if we edit the class,
|
||||||
|
// this way the mapping will be deleted when the ClassEditor is
|
||||||
|
// released.
|
||||||
|
|
||||||
|
// className = className.intern();
|
||||||
|
|
||||||
|
ClassGen info = (ClassGen) classEditors.get(className); |
||||||
|
|
||||||
|
if (info == null) { |
||||||
|
JavaClass jc = loadClass(className); |
||||||
|
db("editClass(String): " + className + " -> " + info); |
||||||
|
return editClass(jc); |
||||||
|
} |
||||||
|
|
||||||
|
return (info); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassGen editClass(Type classType) throws ClassNotFoundException, |
||||||
|
ClassFormatException { |
||||||
|
if (classType instanceof ReferenceType) { |
||||||
|
if (classType instanceof ObjectType) |
||||||
|
return editClass((ObjectType) classType); |
||||||
|
else if (classType instanceof ArrayType) |
||||||
|
return editClass(((ArrayType) classType).getBasicType()); |
||||||
|
else if (classType instanceof UninitializedObjectType) |
||||||
|
return editClass(((UninitializedObjectType) classType) |
||||||
|
.getInitialized()); |
||||||
|
} else |
||||||
|
throw new ClassNotFoundException(classType |
||||||
|
+ "is not an ObjectType and cannot be loaded"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassGen editClass(ObjectType classType) |
||||||
|
throws ClassNotFoundException, ClassFormatException { |
||||||
|
return (editClass(classType.getClassName())); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassGen editClass(JavaClass info) { |
||||||
|
// Check the cache
|
||||||
|
ClassGen ce = (ClassGen) classEditors.get(info.getClassName()); |
||||||
|
|
||||||
|
if (ce == null) { |
||||||
|
ce = new ClassGen(info); |
||||||
|
classInfos.put(info.getClassName(), info); |
||||||
|
classEditors.put(info.getClassName(), ce); |
||||||
|
|
||||||
|
// if(!classInfos.containsValue(info)) {
|
||||||
|
// String className = ce.getClassName().intern();
|
||||||
|
// db("editClass(ClassInfo): " + className + " -> " + info);
|
||||||
|
// classInfos.put(className, info);
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
return (ce); |
||||||
|
} |
||||||
|
|
||||||
|
public MethodGen editMethod(MethodRef method) throws NoSuchMethodException { |
||||||
|
|
||||||
|
// Groan, we have to do this the HARD way.
|
||||||
|
db("Creating a new MethodEditor for " + method); |
||||||
|
String name = method.name(); |
||||||
|
String signature = method.getSignature(); |
||||||
|
|
||||||
|
try { |
||||||
|
ClassGen ce = editClass(method.declaringClass()); |
||||||
|
Method[] methods = ce.getMethods(); |
||||||
|
|
||||||
|
for (int i = 0; i < methods.length; i++) { |
||||||
|
MethodGen me = new MethodGen(methods[i], method |
||||||
|
.declaringClass().getSignature(), ce.getConstantPool());// TODO
|
||||||
|
|
||||||
|
if (me.getName().equals(name) |
||||||
|
&& me.getSignature().equals(signature)) { |
||||||
|
// The call to editMethod should have already handled
|
||||||
|
// the methodEditors mapping, but we still need to do
|
||||||
|
// methodInfos.
|
||||||
|
return (me); |
||||||
|
} |
||||||
|
|
||||||
|
// release(methods[i], ce.getClassName());
|
||||||
|
} |
||||||
|
|
||||||
|
} catch (ClassNotFoundException ex1) { |
||||||
|
} catch (ClassFormatException ex2) { |
||||||
|
} |
||||||
|
|
||||||
|
throw new NoSuchMethodException(method.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
public MethodGen editMethod(Method info, String declaringClass) { |
||||||
|
// Groan, we have to do this the HARD way.
|
||||||
|
db("Creating a new MethodEditor for " + info.getName()); |
||||||
|
String name = info.getName(); |
||||||
|
String signature = info.getSignature(); |
||||||
|
|
||||||
|
try { |
||||||
|
ClassGen ce = editClass(declaringClass); |
||||||
|
Method[] methods = ce.getMethods(); |
||||||
|
|
||||||
|
for (int i = 0; i < methods.length; i++) { |
||||||
|
|
||||||
|
if (methods[i].getName().equals(name) |
||||||
|
&& methods[i].getSignature().equals(signature)) { |
||||||
|
MethodGen me = new MethodGen(methods[i], declaringClass, ce |
||||||
|
.getConstantPool()); |
||||||
|
// The call to editMethod should have already handled
|
||||||
|
// the methodEditors mapping, but we still need to do
|
||||||
|
// methodInfos.
|
||||||
|
return (me); |
||||||
|
} |
||||||
|
|
||||||
|
// release(methods[i], ce.getClassName());
|
||||||
|
} |
||||||
|
|
||||||
|
} catch (ClassNotFoundException ex1) { |
||||||
|
} catch (ClassFormatException ex2) { |
||||||
|
} |
||||||
|
return null; |
||||||
|
// throw new NoSuchMethodException(info.toString());
|
||||||
|
} |
||||||
|
|
||||||
|
public FieldGen editField(MemberRef field) throws NoSuchFieldException { |
||||||
|
|
||||||
|
// Just like we had to do with methods
|
||||||
|
|
||||||
|
NameAndType nat = field.nameAndType(); |
||||||
|
String name = nat.name(); |
||||||
|
Type type = nat.type(); |
||||||
|
|
||||||
|
try { |
||||||
|
ClassGen ce = editClass(field.declaringClass()); |
||||||
|
Field[] fields = ce.getFields(); |
||||||
|
|
||||||
|
for (int i = 0; i < fields.length; i++) { |
||||||
|
FieldGen fe = editField(fields[i], field.declaringClass() |
||||||
|
.getSignature());// TODO
|
||||||
|
|
||||||
|
if (fe.getName().equals(name) && fe.getType().equals(type)) { |
||||||
|
return (fe); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} catch (ClassNotFoundException ex1) { |
||||||
|
} catch (ClassFormatException ex2) { |
||||||
|
} |
||||||
|
return null; |
||||||
|
// throw new NoSuchFieldException(field.toString());
|
||||||
|
} |
||||||
|
|
||||||
|
public FieldGen editField(Field info, String className) { |
||||||
|
// Check the cache
|
||||||
|
String name = info.getName(); |
||||||
|
Type type = info.getType(); |
||||||
|
|
||||||
|
try { |
||||||
|
ClassGen ce = editClass(className); |
||||||
|
Field[] fields = ce.getFields(); |
||||||
|
|
||||||
|
for (int i = 0; i < fields.length; i++) { |
||||||
|
FieldGen fe = editField(fields[i], className); |
||||||
|
|
||||||
|
if (fe.getName().equals(name) && fe.getType().equals(type)) { |
||||||
|
return (fe); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} catch (ClassNotFoundException ex1) { |
||||||
|
} catch (ClassFormatException ex2) { |
||||||
|
} |
||||||
|
return null; |
||||||
|
// throw new NoSuchFieldException(info.toString());
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void release(JavaClass info) { |
||||||
|
// Since we keep around all data, do nothing
|
||||||
|
} |
||||||
|
|
||||||
|
public void release(ClassGen ce) { |
||||||
|
// Since we keep around all data, do nothing
|
||||||
|
} |
||||||
|
|
||||||
|
public void release(Method info, String className) { |
||||||
|
// Since we keep around all data, do nothing
|
||||||
|
} |
||||||
|
|
||||||
|
public void release(Field info, String className) { |
||||||
|
// Since we keep around all data, do nothing
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Classes that are ignored are not committed. |
||||||
|
* |
||||||
|
* @see ignoreClass |
||||||
|
*/ |
||||||
|
public void commit(JavaClass info) { |
||||||
|
ClassGen cg = (ClassGen) classEditors.get(info.getClassName()); |
||||||
|
JavaClass jc = (JavaClass) cg.getJavaClass(); |
||||||
|
classInfos.put(info.getClassName(), jc); |
||||||
|
} |
||||||
|
|
||||||
|
public void commit(ClassGen info) { |
||||||
|
classEditors.put(info.getClassName(), info); |
||||||
|
} |
||||||
|
|
||||||
|
public void commit(MethodGen methodGen) { |
||||||
|
this.commit(methodGen.getMethod(), methodGen.getClassName()); |
||||||
|
} |
||||||
|
|
||||||
|
public void commit(Method m, String classname) { |
||||||
|
try { |
||||||
|
ClassGen cg = editClass(classname); |
||||||
|
Method oldMethod = cg.containsMethod(m.getName(), m.getSignature()); |
||||||
|
cg.replaceMethod(oldMethod, m); |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
// IF THERE IS NO CLASS THERE IS NOTHING TO COMMIT, SHOULDN'T
|
||||||
|
// HAPPEN
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* private Method commit(Method m){ try{ ClassGen cg = editClass(classname); |
||||||
|
* Method oldMethod = cg.containsMethod(m.getName(),m.getSignature()); |
||||||
|
* cg.replaceMethod(oldMethod, m); }catch(ClassNotFoundException cnfe){ //IF
|
||||||
|
* THERE IS NO CLASS THERE IS NOTHING TO COMMIT, SHOULDN'T HAPPEN } } |
||||||
|
*/ |
||||||
|
public void commit(Field f, String classname) { |
||||||
|
try { |
||||||
|
ClassGen cg = editClass(classname); // Ask to commit the ClassGen
|
||||||
|
Field oldField = cg.containsField(f.getName()); |
||||||
|
cg.replaceField(oldField, f); |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
// IF THERE IS NO CLASS THERE IS NOTHING TO COMMIT, SHOULDN'T
|
||||||
|
// HAPPEN
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* private Field commit(Field f){ FieldGen fg = |
||||||
|
* (FieldGen)fieldEditors.get(f); if(fg != null){ fg.update(); Field |
||||||
|
* newField = fg.getField(); //return final version of fg
|
||||||
|
* fieldEditors.remove(f); fieldEditors.put(newField, fg); return newField; |
||||||
|
* }else{ return f; //return the old field } }
|
||||||
|
*/ |
||||||
|
|
||||||
|
// THE COMMIT OF A METHOD/FIELD SHOULD RESULT IN THE COMMIT OF THE
|
||||||
|
// PARENT
|
||||||
|
// CLASS SO commit(JavaClass) SHOULD SUFFICE.
|
||||||
|
// Reason I got rid of commit(method) is bcel's Method has no mapping to
|
||||||
|
// the class that the method belongs to. Each editField or editMethod
|
||||||
|
// ensures that the class is loaded. (release does nothing)
|
||||||
|
public void commit() { |
||||||
|
} |
||||||
|
|
||||||
|
public void commitDirty() { |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* // Commit all dirty fields Object[] array =
|
||||||
|
* this.fieldEditors.values().toArray(); for(int i = 0; i < array.length; |
||||||
|
* i++) { FieldEditor fe = (FieldEditor) array[i]; if(fe.isDirty() && |
||||||
|
* !ignoreField(fe.memberRef())) { comm(" Committing field: " + |
||||||
|
* fe.declaringClass().name() + "." + fe.name()); commit(fe.fieldInfo()); } } //
|
||||||
|
* Commit all dirty methods array = this.methodEditors.values().toArray(); |
||||||
|
* for(int i = 0; i < array.length; i++) { MethodEditor me = (MethodEditor) |
||||||
|
* array[i]; if(me.isDirty() && !ignoreMethod(me.memberRef())) { comm(" |
||||||
|
* Committing method: " + me.declaringClass().name() + "." + me.name() + |
||||||
|
* me.type()); commit(me.methodInfo()); } } // Commit all dirty classes
|
||||||
|
* array = this.classEditors.values().toArray(); for(int i = 0; i < |
||||||
|
* array.length; i++) { ClassEditor ce = (ClassEditor) array[i]; |
||||||
|
* if(ce.isDirty() && !ignoreClass(ce.type())) { comm(" Committing class: " + |
||||||
|
* ce.name()); commit(ce.classInfo()); } } } |
||||||
|
*/ |
||||||
|
|
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Repositories for important BLOAT objects such as the |
||||||
|
<tt>Editor</tt>, <tt>ClassHierarchy</tt>, and <tt>FlowGraph</tt>s. In |
||||||
|
order to avoid build dependencies with other packages we took the |
||||||
|
novel approach of having a "context" interface in several packages that |
||||||
|
the classes in this package then implement.</p> |
||||||
|
|
||||||
|
<p>The reason we implement all of the methods in one class is so that |
||||||
|
if the user wants to have different contexts with different attributes |
||||||
|
(for instance, caching policies), all one has to do is subclass |
||||||
|
<tt>BloatContext</tt> instead of subclassing other contextes which may |
||||||
|
become ackward.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,537 @@ |
|||||||
|
/* |
||||||
|
* Class: InductionVarAnalyzer |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Demand-driven Induction Variable Analysis (diva)*/ |
||||||
|
package edu.purdue.cs.bloat.diva; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.ssa.ComponentVisitor; |
||||||
|
import edu.purdue.cs.bloat.ssa.SSAGraph; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.IfCmpStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MemExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiJoinStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SCStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SRStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StaticFieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Stmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Swizzler; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* InductionVarAnalyzer traverses a control flow graph and looks for array |
||||||
|
* element swizzle operations inside loops. If possible, these swizzle |
||||||
|
* operations are hoisted out of the loop and are replaced with range swizzle |
||||||
|
* operations. The technique used is Demand-driven Induction Variable Analysis |
||||||
|
* (DIVA). |
||||||
|
* <p> |
||||||
|
* To accomplish its tasks, InductionVarAnalyzer keeps track of a number of |
||||||
|
* induction variables (represented by Swizzler objects) and local variables. |
||||||
|
* |
||||||
|
* @see Swizzler |
||||||
|
* @see LocalExpr |
||||||
|
*/ |
||||||
|
public class InductionVarAnalyzer implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
SSAGraph ssaGraph; |
||||||
|
|
||||||
|
FlowGraph CFG; // Control flow graph being operated on
|
||||||
|
|
||||||
|
LinkedHashMap IndStore; // Stores induction variables and
|
||||||
|
|
||||||
|
// associated swizzlers
|
||||||
|
LinkedHashMap LocalStore; // Stores local variables
|
||||||
|
|
||||||
|
Expr ind_var = null; // An induction variable
|
||||||
|
|
||||||
|
Expr ind_init = null; // Initial value of an induction variable
|
||||||
|
|
||||||
|
Expr ind_term = null; // Not used???
|
||||||
|
|
||||||
|
Expr ind_inc = null; // Expression used to increment induction
|
||||||
|
|
||||||
|
// variable (all uses commented out)
|
||||||
|
Expr tgt = null; // Target of the phi statement that defines
|
||||||
|
|
||||||
|
// an induction var
|
||||||
|
|
||||||
|
boolean changed = false; // Was the cfg changed?
|
||||||
|
|
||||||
|
/** |
||||||
|
* Searches the list of induction variables for an induction variable with a |
||||||
|
* given value number. |
||||||
|
* |
||||||
|
* @param vn |
||||||
|
* Value number to search for. |
||||||
|
* |
||||||
|
* @return Swizzler object whose target has the desired value number or |
||||||
|
* null, if value number is not found. |
||||||
|
*/ |
||||||
|
public Swizzler getSwizzler(int vn) { |
||||||
|
Iterator iter = IndStore.values().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Swizzler swz = (Swizzler) iter.next(); |
||||||
|
if ((swz.target().valueNumber() == vn) |
||||||
|
|| (swz.ind_var().valueNumber() == vn)) |
||||||
|
return swz; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Searchs the stored list of local variables for a local variable with a |
||||||
|
* given value number. |
||||||
|
* |
||||||
|
* @param vn |
||||||
|
* The value number to search for. |
||||||
|
* |
||||||
|
* @return The local variable with the given value number, or null, if not |
||||||
|
* found. |
||||||
|
*/ |
||||||
|
public MemExpr getLocal(int vn) { |
||||||
|
Iterator iter = LocalStore.keySet().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
MemExpr le = (MemExpr) iter.next(); |
||||||
|
if (le.valueNumber() == vn) |
||||||
|
return le; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Displays (to System.out) all of the Swizzlers stored in the induction |
||||||
|
* variable store. |
||||||
|
* |
||||||
|
* @see Swizzler |
||||||
|
*/ |
||||||
|
public void Display_store() { |
||||||
|
Iterator iter = IndStore.values().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Swizzler indswz = (Swizzler) iter.next(); |
||||||
|
|
||||||
|
System.out.println("\nIV: " + indswz.ind_var() + " tgt: " |
||||||
|
+ indswz.target() + "\narray: " + indswz.array() |
||||||
|
+ " init: " + indswz.init_val() + " end: " |
||||||
|
+ indswz.end_val()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Displays the contents of a Swizzler object to System.out. |
||||||
|
* |
||||||
|
* @param indswz |
||||||
|
* The Swizzler to display. |
||||||
|
*/ |
||||||
|
public void displaySwizzler(Swizzler indswz) { |
||||||
|
System.out.println("\nIV: " + indswz.ind_var() + "vn:" |
||||||
|
+ indswz.ind_var().valueNumber() + " tgt: " + indswz.target() |
||||||
|
+ "vn:" + indswz.target().valueNumber() + "\narray: " |
||||||
|
+ indswz.array() + " init: " + indswz.init_val() + " end: " |
||||||
|
+ indswz.end_val()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a swizzle range statement (SRStmt) to the end of each predecessor |
||||||
|
* block of the block containing the phi statement that defines an induction |
||||||
|
* variable provided that the phi block does not dominate its predacessor. |
||||||
|
* Phew. |
||||||
|
* |
||||||
|
* @param indswz |
||||||
|
* Swizzler representing the induction variable on which the |
||||||
|
* range swizzle statement is added. |
||||||
|
*/ |
||||||
|
public void insert_aswrange(Swizzler indswz) { |
||||||
|
Iterator iter = CFG.preds(indswz.phi_block()).iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
Block blk = (Block) iter.next(); |
||||||
|
if (!indswz.phi_block().dominates(blk)) { |
||||||
|
SRStmt aswrange = new SRStmt((Expr) indswz.array().clone(), |
||||||
|
(Expr) indswz.init_val().clone(), (Expr) indswz |
||||||
|
.end_val().clone()); |
||||||
|
blk.tree().addStmtBeforeJump(aswrange); |
||||||
|
changed = true; |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Inserted ASWR: " + aswrange |
||||||
|
+ "\nin block: " + blk); |
||||||
|
|
||||||
|
System.out.println("$$$ can insert aswrange now\n" |
||||||
|
+ "array: " + indswz.array() + "\nIV: " |
||||||
|
+ indswz.ind_var() + "\ninit: " + indswz.init_val() |
||||||
|
+ "\nend: " + indswz.end_val()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* To determine if a phi statement is a mu */ |
||||||
|
/* Returns null if not a MU and sets ind_var & ind_init */ |
||||||
|
/* to refer to the IV & its initial value otherwise */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines whether or not a phi statement is a mu function. A mu function |
||||||
|
* is a phi function that merges values at loop headers, as opposed to those |
||||||
|
* that occur as a result of forward branching. Mu functions always have two |
||||||
|
* arguments. |
||||||
|
* |
||||||
|
* @param phi |
||||||
|
* phi statement that may be a mu function |
||||||
|
* @param cfg |
||||||
|
* CFG to look through <font color="ff0000">Get rid of this |
||||||
|
* parameter</font> |
||||||
|
* |
||||||
|
* @return The block containing the mu functions external (that is, outside |
||||||
|
* the loop) argument, also known as the external ssalink. If the |
||||||
|
* phi statement is not a mu function, null is returned. |
||||||
|
*/ |
||||||
|
public Block isMu(PhiJoinStmt phi, FlowGraph cfg) { |
||||||
|
// Does it contain two operands?
|
||||||
|
if (phi.numOperands() != 2) |
||||||
|
return null; |
||||||
|
|
||||||
|
// Is it REDUCIBLE?
|
||||||
|
if (cfg.blockType(phi.block()) == Block.IRREDUCIBLE |
||||||
|
|| cfg.blockType(phi.block()) == Block.NON_HEADER) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Does one of them dominate the phi and the other dominated by the phi? |
||||||
|
*/ |
||||||
|
|
||||||
|
Iterator iter = cfg.preds(phi.block()).iterator(); |
||||||
|
Block pred1 = (Block) iter.next(); |
||||||
|
Block pred2 = (Block) iter.next(); |
||||||
|
|
||||||
|
if (pred1.dominates(phi.block()) && phi.block().dominates(pred2) |
||||||
|
&& (pred1 != phi.block())) { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Extlink = 1 pred1:" + pred1 + " pred2:" |
||||||
|
+ pred2); |
||||||
|
ind_var = phi.operandAt(pred2); |
||||||
|
ind_init = phi.operandAt(pred1); |
||||||
|
return pred1; |
||||||
|
} |
||||||
|
if (pred2.dominates(phi.block()) && phi.block().dominates(pred1) |
||||||
|
&& (pred2 != phi.block())) { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Extlink = 2 pred1:" + pred1 + " pred2:" |
||||||
|
+ pred2); |
||||||
|
ind_var = phi.operandAt(pred1); |
||||||
|
ind_init = phi.operandAt(pred2); |
||||||
|
return pred2; |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs DIVA on a CFG public static void transform(FlowGraph cfg) { //
|
||||||
|
* Create a new instance to allow multiple threads. InductionVarAnalyzer me = |
||||||
|
* new InductionVarAnalyzer(); me.transform(cfg); } |
||||||
|
*/ |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
transform(state.controlFlowGraph()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs DIVA on a CFG. |
||||||
|
*/ |
||||||
|
private void transform(FlowGraph cfg) { |
||||||
|
ssaGraph = new SSAGraph(cfg); |
||||||
|
CFG = cfg; |
||||||
|
IndStore = new LinkedHashMap(); |
||||||
|
LocalStore = new LinkedHashMap(); |
||||||
|
changed = false; |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out |
||||||
|
.println("----------Before visitComponents--------------"); |
||||||
|
cfg.print(System.out); |
||||||
|
} |
||||||
|
|
||||||
|
// Visit each strongly connected component (SCC) in the CFG. SCCs
|
||||||
|
// correspond to sequences in the program. Visit each node in the
|
||||||
|
// SCC and build the local variable store. Create Swizzlers at
|
||||||
|
// PhiStmts, if approproate, and store them in the induction
|
||||||
|
// variable store. If it can be determined that an array element
|
||||||
|
// swizzle can be hoisted out of a loop, it is hoisted.
|
||||||
|
ssaGraph.visitComponents(new ComponentVisitor() { |
||||||
|
public void visitComponent(List scc) { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("SCC ="); |
||||||
|
|
||||||
|
Iterator e = scc.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Node v = (Node) e.next(); |
||||||
|
if (DEBUG) |
||||||
|
System.out.println(" " + v + "{" + v.key() + "} " |
||||||
|
+ v.getClass()); |
||||||
|
|
||||||
|
v.visit(new TreeVisitor() { |
||||||
|
public void visitPhiJoinStmt(PhiJoinStmt phi) { |
||||||
|
if (isMu(phi, CFG) != null) { |
||||||
|
// Iterator iter = phi.operands().iterator();
|
||||||
|
tgt = phi.target(); |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("IV:" + ind_var + " VN:" |
||||||
|
+ ind_var.valueNumber() + "\ninit:" |
||||||
|
+ ind_init + " target: " + tgt |
||||||
|
+ " VN: " + tgt.valueNumber()); |
||||||
|
Swizzler swz = new Swizzler(ind_var, tgt, |
||||||
|
ind_init, phi.block()); |
||||||
|
if (DEBUG) { |
||||||
|
System.out |
||||||
|
.println("store swizzler for " |
||||||
|
+ ind_var.def() + " & " |
||||||
|
+ tgt.def()); |
||||||
|
displaySwizzler(swz); |
||||||
|
} |
||||||
|
|
||||||
|
if (ind_var.def() != null) |
||||||
|
IndStore.put(ind_var.def(), swz); |
||||||
|
|
||||||
|
if (tgt.def() != null) |
||||||
|
IndStore.put(tgt.def(), swz); |
||||||
|
|
||||||
|
if (DEBUG) |
||||||
|
System.out.println(" Mu: " + phi + "{" |
||||||
|
+ phi.key() + "}"); |
||||||
|
} else { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Phi: " + phi + "{" |
||||||
|
+ phi.key() + "}"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLocalExpr(LocalExpr me) { |
||||||
|
if (me.def() != null) { |
||||||
|
if (LocalStore.get(me.def()) == null) { |
||||||
|
LocalStore.put(me.def(), me); |
||||||
|
} |
||||||
|
} |
||||||
|
if (LocalStore.get(me) == null) { |
||||||
|
LocalStore.put(me, me); |
||||||
|
} |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("stored ME: " + me |
||||||
|
+ " vn: " + me.valueNumber()); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr me) { |
||||||
|
if (me.def() != null) { |
||||||
|
if (LocalStore.get(me.def()) == null) { |
||||||
|
LocalStore.put(me.def(), me); |
||||||
|
} |
||||||
|
} |
||||||
|
if (LocalStore.get(me) == null) { |
||||||
|
LocalStore.put(me, me); |
||||||
|
} |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("stored ME: " + me |
||||||
|
+ " vn: " + me.valueNumber()); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfCmpStmt(IfCmpStmt cmp) { |
||||||
|
Swizzler indswz = null; |
||||||
|
boolean set_term = false; |
||||||
|
|
||||||
|
if (cmp.left().def() != null) |
||||||
|
indswz = (Swizzler) IndStore.get(cmp.left() |
||||||
|
.def()); |
||||||
|
if (indswz != null) { |
||||||
|
if (DEBUG) |
||||||
|
displaySwizzler(indswz); |
||||||
|
if (indswz.end_val() == null) { |
||||||
|
indswz.set_end_val(cmp.right()); |
||||||
|
set_term = true; |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Set end_val of " |
||||||
|
+ indswz.ind_var() + " to " |
||||||
|
+ cmp.right()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (cmp.right().def() != null) |
||||||
|
indswz = (Swizzler) IndStore.get(cmp |
||||||
|
.right().def()); |
||||||
|
if (indswz != null) { |
||||||
|
if (DEBUG) |
||||||
|
displaySwizzler(indswz); |
||||||
|
if (indswz.end_val() == null) { |
||||||
|
indswz.set_end_val(cmp.left()); |
||||||
|
set_term = true; |
||||||
|
if (DEBUG) |
||||||
|
System.out |
||||||
|
.println("Set end_val of " |
||||||
|
+ indswz.ind_var() |
||||||
|
+ " to " |
||||||
|
+ cmp.left()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (set_term && indswz != null |
||||||
|
&& indswz.array() != null) { |
||||||
|
indswz.aswizzle().set_redundant(true); |
||||||
|
insert_aswrange(indswz); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt sc) { |
||||||
|
Swizzler indswz; |
||||||
|
MemExpr le = null; |
||||||
|
|
||||||
|
if (DEBUG) |
||||||
|
System.out.println("SC: array= " + sc.array() |
||||||
|
+ " VN:" + sc.array().valueNumber() |
||||||
|
+ "\nindex=" + sc.index() + " VN:" |
||||||
|
+ sc.index().valueNumber()); |
||||||
|
|
||||||
|
indswz = getSwizzler(sc.index().valueNumber()); |
||||||
|
if (indswz != null) { |
||||||
|
if (DEBUG) |
||||||
|
displaySwizzler(indswz); |
||||||
|
if (indswz.array() == null) { |
||||||
|
le = getLocal(sc.array().valueNumber()); |
||||||
|
if (le == null && sc.array().def() != null) |
||||||
|
le = getLocal(sc.array().def() |
||||||
|
.valueNumber()); |
||||||
|
if (le != null) { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Le: " + le); |
||||||
|
indswz.set_array(le); |
||||||
|
indswz.set_aswizzle(sc); |
||||||
|
} else |
||||||
|
return; |
||||||
|
} |
||||||
|
if (indswz.end_val() != null) { |
||||||
|
sc.set_redundant(true); |
||||||
|
insert_aswrange(indswz); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* public void visitStoreExpr(StoreExpr ind_store) { |
||||||
|
* if(ind_var != null) { |
||||||
|
* if(ind_var.equalsExpr(ind_store.target())) { if (tgt != |
||||||
|
* null && ind_store.expr() instanceof ArithExpr){ |
||||||
|
* ArithExpr ind_exp = (ArithExpr)ind_store.expr(); |
||||||
|
* if(tgt.equalsExpr(ind_exp.left())) ind_inc = |
||||||
|
* ind_exp.right(); else if(tgt.equals(ind_exp.right())) |
||||||
|
* ind_inc = ind_exp.left(); else { ind_inc = null; |
||||||
|
* return; } System.out.println("Ind_inc: "+ind_inc); } } } } |
||||||
|
*/ |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("------------After visitComponents---------"); |
||||||
|
cfg.print(System.out); |
||||||
|
} |
||||||
|
|
||||||
|
// If the CFG changed (i.e. if an array range swizzle was added),
|
||||||
|
// traverse
|
||||||
|
// the graph and remove redundent swizzle statements.
|
||||||
|
if (changed) { |
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
ListIterator iter; |
||||||
|
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
iter = tree.stmts().listIterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Stmt stmt = (Stmt) iter.next(); |
||||||
|
stmt.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt sc) { |
||||||
|
Object dup2stmt; |
||||||
|
if (sc.redundant()) { |
||||||
|
|
||||||
|
iter.remove(); |
||||||
|
dup2stmt = iter.previous(); |
||||||
|
iter.remove(); |
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Removed Redundant ASW: " + sc |
||||||
|
+ "\nand " + dup2stmt); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("----------------After cfg.visit--------------"); |
||||||
|
cfg.print(System.out); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " DIVA: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return "-----Before DIVA------"; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return "-----After DIVA-----"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
InductionVarAnalyzer.class\
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,8 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Performs demand-driven induction variable analysis on a Java |
||||||
|
classfile.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,179 @@ |
|||||||
|
/* |
||||||
|
* Class: EditorContext |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.editor; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
import org.apache.bcel.classfile.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* An <tt>EditorContext</tt> supplies a means of loading and editing classes. |
||||||
|
* Note that a number of these methods are identical to methods in |
||||||
|
* <tt>Editor</tt>. It is expected that an <tt>EditorContext</tt> will have |
||||||
|
* a different caching (of <tt>ClassEditor</tt>s, etc.) policy than |
||||||
|
* <tt>Editor</tt> does. Hence, the methods in <tt>EditorContext</tt> should |
||||||
|
* be used to edit classes, etc. |
||||||
|
*/ |
||||||
|
public interface EditorContext { |
||||||
|
|
||||||
|
/** |
||||||
|
* Loads a class into BLOAT |
||||||
|
*/ |
||||||
|
public JavaClass loadClass(String className) throws ClassNotFoundException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new <code>ClassInfo</code> |
||||||
|
* |
||||||
|
* @param modifiers |
||||||
|
* The modifiers describing the newly-created class
|
||||||
|
* @param classIndex |
||||||
|
* The index of the name of the newly-created class in its |
||||||
|
* constant pool |
||||||
|
* @param superClassIndex |
||||||
|
* The index of the name of the newly-created class's superclass |
||||||
|
* in its constant pool |
||||||
|
* @param interfaceIndexes |
||||||
|
* The indexes of the names of the interfaces that the |
||||||
|
* newly-created class implements |
||||||
|
* @param constants |
||||||
|
* The constant pool for the newly created class (a list of |
||||||
|
* {@link Constant}s). |
||||||
|
*/ |
||||||
|
/** |
||||||
|
* Returns the <tt>ClassHierarchy</tt> of all classes and interfaces known |
||||||
|
* to BLOAT. |
||||||
|
*/ |
||||||
|
public ClassHierarchy getHierarchy(); |
||||||
|
|
||||||
|
public JavaClass newClassInfo(int class_name_index, |
||||||
|
int superclass_name_index, String file_name, int major, int minor, |
||||||
|
int access_flags, ConstantPool constant_pool, int[] interfaces, |
||||||
|
Field[] fields, Method[] methods, Attribute[] attributes); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <code>ClassEditor</code> for editing a new class with the |
||||||
|
* given name. It will override any class with the given name that is |
||||||
|
* already being edited. |
||||||
|
*/ |
||||||
|
|
||||||
|
public ClassGen newClass(int accessflags, String className, |
||||||
|
String file_name, Type superType, Type[] interfaces); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>ClassEditor</tt> used to edit a class of a given name. |
||||||
|
*/ |
||||||
|
public ClassGen editClass(String className) throws ClassNotFoundException, |
||||||
|
ClassFormatException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>ClassEditor</tt> used to edit a class described by a |
||||||
|
* given <tt>Type</tt>. |
||||||
|
*/ |
||||||
|
public ClassGen editClass(Type classType) throws ClassNotFoundException, |
||||||
|
ClassFormatException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>ClassEditor</tt> used to edit a class described by a |
||||||
|
* given <tt>ClassInfo</tt>. |
||||||
|
*/ |
||||||
|
public ClassGen editClass(JavaClass info); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>FieldEditor</tt> for editing a <tt>FieldInfo</tt>. |
||||||
|
*/ |
||||||
|
public FieldGen editField(Field info, String classname); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>FieldEditor</tt> for editing a field. |
||||||
|
*/ |
||||||
|
public FieldGen editField(MemberRef field) throws NoSuchFieldException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>MethodEditor</tt> for editing a method. |
||||||
|
*/ |
||||||
|
public MethodGen editMethod(Method info, String classname); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a <tt>MethodEditor</tt> for editing a method. |
||||||
|
*/ |
||||||
|
public MethodGen editMethod(MethodRef method) throws NoSuchMethodException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Signals that we are done editing a method. The object used to model it |
||||||
|
* may be reclaimed. |
||||||
|
*/ |
||||||
|
public void release(Method info, String className); |
||||||
|
|
||||||
|
/** |
||||||
|
* Signals that we are done editing a field. The object used to model it may |
||||||
|
* be reclaimed. |
||||||
|
*/ |
||||||
|
public void release(Field info, String className); |
||||||
|
|
||||||
|
/** |
||||||
|
* Signals that we are done editing a class. The object used to model it may |
||||||
|
* be reclaimed. |
||||||
|
*/ |
||||||
|
public void release(JavaClass info); |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits the changes made to a class. |
||||||
|
*/ |
||||||
|
public void commit(JavaClass info); |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits the changes made to a method. |
||||||
|
*/ |
||||||
|
public void commit(Method info, String className); |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits the changes made to a method. |
||||||
|
*/ |
||||||
|
public void commit(MethodGen info); |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits the changes made to a field. |
||||||
|
*/ |
||||||
|
public void commit(Field info, String className); |
||||||
|
|
||||||
|
/** |
||||||
|
* Commits all changes made to classes, methods, and fields. |
||||||
|
*/ |
||||||
|
public void commit(); |
||||||
|
} |
@ -0,0 +1,480 @@ |
|||||||
|
/* |
||||||
|
* Class: InstructionAdaptor |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.editor; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* This adapter provides a default implementation for every method in |
||||||
|
* InstructionVisitor. |
||||||
|
*/ |
||||||
|
public class InstructionAdapter { |
||||||
|
public void visit_nop(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ldc(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_aload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iaload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_laload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_faload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_daload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_aaload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_baload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_caload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_saload(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_istore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lstore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fstore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dstore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_astore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_aastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_bastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_castore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_sastore(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_pop(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_pop2(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dup(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dup_x1(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dup_x2(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dup2(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dup2_x1(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dup2_x2(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_swap(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iadd(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ladd(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fadd(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dadd(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_isub(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lsub(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fsub(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dsub(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_imul(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lmul(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fmul(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dmul(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_idiv(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ldiv(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fdiv(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ddiv(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_irem(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lrem(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_frem(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_drem(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ineg(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lneg(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fneg(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dneg(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ishl(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lshl(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ishr(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lshr(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iushr(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lushr(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iand(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_land(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ior(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lor(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ixor(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lxor(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iinc(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_i2l(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_i2f(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_i2d(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_l2i(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_l2f(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_l2d(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_f2i(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_f2l(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_f2d(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_d2i(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_d2l(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_d2f(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_i2b(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_i2c(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_i2s(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lcmp(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fcmpl(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_fcmpg(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dcmpl(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dcmpg(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifeq(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifne(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_iflt(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifge(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifgt(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifle(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_icmpeq(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_icmpne(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_icmplt(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_icmpge(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_icmpgt(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_icmple(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_acmpeq(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_if_acmpne(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_goto(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_jsr(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ret(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_switch(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ireturn(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_lreturn(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_freturn(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_dreturn(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_areturn(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_return(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_getstatic(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_putstatic(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_putstatic_nowb(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_getfield(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_putfield(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_putfield_nowb(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokevirtual(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokespecial(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokestatic(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokeinterface(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_new(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_newarray(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_arraylength(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_athrow(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_checkcast(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_instanceof(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_monitorenter(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_monitorexit(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_multianewarray(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifnull(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_ifnonnull(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_rc(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_aupdate(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_supdate(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_aswizzle(Instruction inst) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_aswrange(Instruction inst) { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
/* |
||||||
|
* Class: InstructionVisitor |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.editor; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Instruction; |
||||||
|
|
||||||
|
/** |
||||||
|
* The visitor pattern allows functionality to be added to a number of classes |
||||||
|
* (or in this case one class, <tt>Instruction</tt>, that can vary in |
||||||
|
* behavior) without modifying the classes themselves. Additionally, the visitor |
||||||
|
* pattern simulates double dispatching. For instance <tt>visit</tt> method of |
||||||
|
* <tt>Instruction</tt> calls a particular method of |
||||||
|
* <tt>InstructionVisitor</tt> based on the <tt>Instruction</tt>'s opcode. |
||||||
|
* <p> |
||||||
|
* <tt>InstructionVisitor</tt> provides an interface for performing actions |
||||||
|
* based on the instruction type. Classes implementing this interface should not |
||||||
|
* be able to miss any of the instruction types. This interface was created as |
||||||
|
* an alternative to having 138 different subtypes of Instruction. |
||||||
|
* |
||||||
|
* @see Instruction#visit |
||||||
|
* @see edu.purdue.cs.bloat.tree.Tree |
||||||
|
* |
||||||
|
* @author Nate Nystrom (<a |
||||||
|
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>) |
||||||
|
*/ |
||||||
|
public interface InstructionVisitor { |
||||||
|
public void visitInst(Instruction inst); |
||||||
|
// public void visit_rc(Instruction inst);
|
||||||
|
// public void visit_aupdate(Instruction inst);
|
||||||
|
// public void visit_supdate(Instruction inst);
|
||||||
|
// public void visit_aswizzle(Instruction inst);
|
||||||
|
// public void visit_aswrange(Instruction inst);
|
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
ClassHierarchy.class\
|
||||||
|
EditorContext.class\
|
||||||
|
InstructionAdapter.class\
|
||||||
|
InstructionVisitor.class\
|
||||||
|
MemberRef.class\
|
||||||
|
MethodRef.class\
|
||||||
|
NameAndType.class\
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,143 @@ |
|||||||
|
/* |
||||||
|
* Class: MemberRef |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.editor; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* MemberRef represents a method or field (as a <tt>NameAndType</tt>) and the |
||||||
|
* class (as a <tt>Type</tt>) in which it is declared. |
||||||
|
* |
||||||
|
* @author Nate Nystrom (<a |
||||||
|
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>) |
||||||
|
* |
||||||
|
* I found it rather confusing having MemberRef refer to both fields and methods |
||||||
|
* so I have subclassed MemberRef with MethodRef for use when refering to |
||||||
|
* methods. --Arrin |
||||||
|
* @see MethodRef |
||||||
|
*/ |
||||||
|
public class MemberRef { |
||||||
|
private final ReferenceType declaringClass; |
||||||
|
|
||||||
|
private final NameAndType nameAndType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param declaringClass |
||||||
|
* The type of the class which declared the member. |
||||||
|
* @param nameAndType |
||||||
|
* The name and type of the member. |
||||||
|
*/ |
||||||
|
public MemberRef(ReferenceType declaringClass, NameAndType nameAndType) { |
||||||
|
this.declaringClass = declaringClass; |
||||||
|
this.nameAndType = nameAndType; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the type of the class which declared the member. |
||||||
|
* |
||||||
|
* @return The type of the class which declared the member. |
||||||
|
*/ |
||||||
|
public ReferenceType declaringClass() { |
||||||
|
return declaringClass; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the name of the member. |
||||||
|
* |
||||||
|
* @return The name of the member. |
||||||
|
*/ |
||||||
|
public String name() { |
||||||
|
return nameAndType.name(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the type of the member. |
||||||
|
* |
||||||
|
* @return The type of the member. |
||||||
|
*/ |
||||||
|
public Type type() { |
||||||
|
return nameAndType.type(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the name and type of the member. |
||||||
|
* |
||||||
|
* @return The name and type of the member. |
||||||
|
*/ |
||||||
|
public NameAndType nameAndType() { |
||||||
|
return nameAndType; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert the reference to a string. |
||||||
|
* |
||||||
|
* @return A string representation of the reference. |
||||||
|
*/ |
||||||
|
public String toString() { |
||||||
|
// Take advantage of PRINT_TRUNCATED in Type
|
||||||
|
String className = declaringClass.toString(); |
||||||
|
return "<" + "Field" + " " + className + "." + name() + " " + type() |
||||||
|
+ ">"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Check if an object is equal to this reference. |
||||||
|
* |
||||||
|
* @param obj |
||||||
|
* The object to compare against. |
||||||
|
* @return true if equal, false if not. |
||||||
|
*/ |
||||||
|
public boolean equals(Object obj) { |
||||||
|
return obj instanceof MemberRef |
||||||
|
&& ((MemberRef) obj).declaringClass.equals(declaringClass) |
||||||
|
&& ((MemberRef) obj).nameAndType.equals(nameAndType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Hash the member reference. |
||||||
|
* |
||||||
|
* @return The hash code. |
||||||
|
*/ |
||||||
|
public int hashCode() { |
||||||
|
return declaringClass.hashCode() ^ nameAndType.hashCode(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,117 @@ |
|||||||
|
/* |
||||||
|
* Class: MethodRef |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.editor; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* MemberRef represents a method or field (as a <tt>NameAndType</tt>) and the |
||||||
|
* class (as a <tt>Type</tt>) in which it is declared. |
||||||
|
* |
||||||
|
* @author Arrin Daley (<a |
||||||
|
* href="mailto:arrin@cs.anu.edu.au">arrin@cs.anu.edu.au</a>) |
||||||
|
* |
||||||
|
* I found it rather confusing having MemberRef refer to both fields and methods |
||||||
|
* so I have subclassed MemberRef with MethodRef for use when refering to |
||||||
|
* methods. --Arrin |
||||||
|
* @see MemberRef |
||||||
|
*/ |
||||||
|
|
||||||
|
/* |
||||||
|
* BCEL types only refer to a field or object type but BLOAT types can refer to |
||||||
|
* both a method and a field as a result I made this class to store Method |
||||||
|
* reference information |
||||||
|
*/ |
||||||
|
|
||||||
|
public class MethodRef extends MemberRef { |
||||||
|
|
||||||
|
private final Type[] params; |
||||||
|
|
||||||
|
private final Type returnType; |
||||||
|
|
||||||
|
public MethodRef(ReferenceType declaringClass, NameAndType nameAndType, |
||||||
|
Type returnType, Type[] paramTypes) { |
||||||
|
super(declaringClass, nameAndType); |
||||||
|
this.params = paramTypes; |
||||||
|
this.returnType = returnType; |
||||||
|
} |
||||||
|
|
||||||
|
public Type[] paramTypes() { |
||||||
|
return params; |
||||||
|
} |
||||||
|
|
||||||
|
public Type returnType() { |
||||||
|
return returnType; |
||||||
|
} |
||||||
|
|
||||||
|
public Type type() { |
||||||
|
return returnType; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (super.equals(obj) && obj instanceof MethodRef) { |
||||||
|
MethodRef methRef = (MethodRef) obj; |
||||||
|
Type[] paramTest = methRef.paramTypes(); |
||||||
|
if (returnType.equals(methRef.returnType()) |
||||||
|
&& params.length == paramTest.length) { |
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
if (!params[i].equals(paramTest[i])) |
||||||
|
return false; |
||||||
|
} |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} else |
||||||
|
return false; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
// Take advantage of PRINT_TRUNCATED in Type
|
||||||
|
String className = declaringClass().toString(); |
||||||
|
return "<" + "Method" + " " + className + "." + name() + " " |
||||||
|
+ Type.getMethodSignature(returnType, params) + ">"; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSignature() { |
||||||
|
return Type.getMethodSignature(returnType, params); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
/* |
||||||
|
* Class: NameAndType |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.editor; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* Methods and fields are described by their name and type descriptor. |
||||||
|
* NameAndType represents exactly that. |
||||||
|
* |
||||||
|
* @author Nate Nystrom (<a |
||||||
|
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>) |
||||||
|
* |
||||||
|
* In BLOAT NameAndType could refer to both Methods and Fields using MemberRef, |
||||||
|
* Type being used to encapsulate the parameters and return type of the method. |
||||||
|
* Types in BCEL can't do this so MethodRef is used for methods and MemberRef is |
||||||
|
* used for fields. NameAndType is still used to refer to Methods but only |
||||||
|
* encapsulates the name and return type of the method parameters are held |
||||||
|
* inside MethodRef. --Arrin |
||||||
|
*/ |
||||||
|
|
||||||
|
public class NameAndType { |
||||||
|
private final String name; |
||||||
|
|
||||||
|
private final Type type; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
*/ |
||||||
|
public NameAndType(String name, Type type) { |
||||||
|
this.name = name; |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the name. |
||||||
|
*/ |
||||||
|
public String name() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the type. |
||||||
|
*/ |
||||||
|
public Type type() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a string representation of the name and type. |
||||||
|
*/ |
||||||
|
public String toString() { |
||||||
|
return "<NameandType " + name + " " + type + ">"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Check if an object is equal to this name and type. |
||||||
|
* |
||||||
|
* @param obj |
||||||
|
* The object to compare against. |
||||||
|
* @return <tt>true</tt> if equal |
||||||
|
*/ |
||||||
|
public boolean equals(Object obj) { |
||||||
|
return obj instanceof NameAndType |
||||||
|
&& ((NameAndType) obj).name.equals(name) |
||||||
|
&& ((NameAndType) obj).type.equals(type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a hash of the name and type. |
||||||
|
*/ |
||||||
|
public int hashCode() { |
||||||
|
return name.hashCode() ^ type.hashCode(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Allows classes, methods, and fields to be edited. In addition, the |
||||||
|
representation of bytecodes (JVM instructions) is refined. Types, |
||||||
|
opcodes, local variables, and special instrcution operands are |
||||||
|
introduced.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,853 @@ |
|||||||
|
/* |
||||||
|
* Class: CallGraph |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.inline; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
import org.apache.bcel.classfile.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.ClassHierarchy; |
||||||
|
import edu.purdue.cs.bloat.editor.InstructionAdapter; |
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
import edu.purdue.cs.bloat.editor.NameAndType; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Grants access to certain information about a Java program. At least one root |
||||||
|
* method must be specified. From these root methods, the call graph and |
||||||
|
* information such as the classes that are instantiated during the Java program |
||||||
|
* is computed. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* The construction of the call graph is in the spirit of the "Program |
||||||
|
* Virtual-call Graph" presented in [Bacon97]. However, certain changes have |
||||||
|
* been made to tailor it to BLOAT and Java and to make the overall |
||||||
|
* representation smaller. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Rapid type analysis is integrated into the construction of the call graph. A |
||||||
|
* virtual method is not examined until we know that its declaring class has |
||||||
|
* been instantiated. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Some classes are created internally by the VM and are missed by our analysis. |
||||||
|
* So, we maintain a set of "pre-live" classes. We consider all of their |
||||||
|
* constructors to be live. |
||||||
|
*/ |
||||||
|
public class CallGraph { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
private static Set preLive; // "Pre-live" classes
|
||||||
|
|
||||||
|
public static boolean USEPRELIVE = true; |
||||||
|
|
||||||
|
public static boolean USE1_2 = true; |
||||||
|
|
||||||
|
private Set roots; // Root methods (MethodRefs)
|
||||||
|
|
||||||
|
private Map calls; // Maps methods to the methods they
|
||||||
|
|
||||||
|
// call (virtual calls are not resolved)
|
||||||
|
private Set liveClasses; // Classes (Types) that have been instantiated
|
||||||
|
|
||||||
|
private Map resolvesTo; // Maps methods to the methods they resolve to
|
||||||
|
|
||||||
|
private Map blocked; // Maps types to methods blocked on those types
|
||||||
|
|
||||||
|
List worklist; // Methods to process
|
||||||
|
|
||||||
|
Set liveMethods; // Methods that may be executed
|
||||||
|
|
||||||
|
InlineContext context; |
||||||
|
|
||||||
|
private ClassHierarchy hier; |
||||||
|
|
||||||
|
static void db(String s) { |
||||||
|
if (CallGraph.DEBUG) |
||||||
|
System.out.println(s); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize the set of classes that are "pre-live" |
||||||
|
*/ |
||||||
|
private static void init() { |
||||||
|
// We can't do this in the static initializer because USE1_2 might
|
||||||
|
// not have the desired value.
|
||||||
|
|
||||||
|
preLive = new LinkedHashSet(); |
||||||
|
|
||||||
|
preLive.add("java.lang.Boolean"); |
||||||
|
preLive.add("java.lang.Class"); |
||||||
|
preLive.add("java.lang.ClassLoader"); |
||||||
|
preLive.add("java.lang.Compiler"); |
||||||
|
preLive.add("java.lang.Integer"); |
||||||
|
preLive.add("java.lang.SecurityManager"); |
||||||
|
preLive.add("java.lang.String"); |
||||||
|
preLive.add("java.lang.StringBuffer"); |
||||||
|
preLive.add("java.lang.System"); |
||||||
|
preLive.add("java.lang.StackOverflowError"); |
||||||
|
preLive.add("java.lang.Thread"); |
||||||
|
preLive.add("java.lang.ThreadGroup"); |
||||||
|
|
||||||
|
preLive.add("java.io.BufferedInputStream"); |
||||||
|
preLive.add("java.io.BufferedReader"); |
||||||
|
preLive.add("java.io.BufferedOutputStream"); |
||||||
|
preLive.add("java.io.BufferedWriter"); |
||||||
|
preLive.add("java.io.File"); |
||||||
|
preLive.add("java.io.FileDescriptor"); |
||||||
|
preLive.add("java.io.InputStreamReader"); |
||||||
|
preLive.add("java.io.ObjectStreamClass"); |
||||||
|
preLive.add("java.io.OutputStreamWriter"); |
||||||
|
preLive.add("java.io.PrintStream"); |
||||||
|
preLive.add("java.io.PrintWriter"); |
||||||
|
|
||||||
|
preLive.add("java.net.URL"); |
||||||
|
|
||||||
|
preLive.add("java.security.Provider"); |
||||||
|
preLive.add("java.security.Security"); |
||||||
|
|
||||||
|
preLive.add("java.util.Hashtable"); |
||||||
|
preLive.add("java.util.ListResourceBundle"); |
||||||
|
preLive.add("java.util.Locale"); |
||||||
|
preLive.add("java.util.Properties"); |
||||||
|
preLive.add("java.util.Stack"); |
||||||
|
preLive.add("java.util.Vector"); |
||||||
|
|
||||||
|
preLive.add("java.util.zip.ZipFile"); |
||||||
|
|
||||||
|
// Some pre-live classes are only available on JDK1.2.
|
||||||
|
if (USE1_2) { |
||||||
|
preLive.add("java.lang.Package"); |
||||||
|
|
||||||
|
preLive.add("java.lang.ref.Finalizer"); |
||||||
|
preLive.add("java.lang.ref.ReferenceQueue"); |
||||||
|
|
||||||
|
preLive.add("java.io.FilePermission"); |
||||||
|
preLive.add("java.io.UnixFileSystem"); |
||||||
|
|
||||||
|
preLive.add("java.net.URLClassLoader"); |
||||||
|
|
||||||
|
preLive.add("java.security.SecureClassLoader"); |
||||||
|
preLive.add("java.security.AccessController"); |
||||||
|
|
||||||
|
preLive.add("java.text.resources.LocaleElements"); |
||||||
|
preLive.add("java.text.resources.LocaleElements_en"); |
||||||
|
|
||||||
|
preLive.add("java.util.LinkedHashMap"); |
||||||
|
|
||||||
|
preLive.add("java.util.jar.JarFile"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds (the name of) a class to the set of classes that are considered to |
||||||
|
* be "pre-live" |
||||||
|
*/ |
||||||
|
public static void addPreLive(String name) { |
||||||
|
if (preLive == null) { |
||||||
|
init(); |
||||||
|
} |
||||||
|
preLive.add(name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a class from the set of "pre-live" classes |
||||||
|
* |
||||||
|
* @return <tt>true</tt> if the class was "pre-live" |
||||||
|
*/ |
||||||
|
public static boolean removePreLive(String name) { |
||||||
|
if (preLive == null) { |
||||||
|
init(); |
||||||
|
} |
||||||
|
return (preLive.remove(name)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param context |
||||||
|
* <Tt>InlineContext</tt> used to examine classes and methods. |
||||||
|
* |
||||||
|
* @param roots |
||||||
|
* The methods (represented as <tt>MemberRef</tt>s) considered |
||||||
|
* to the roots (that is, the "main" methods) of the call graph. |
||||||
|
* Presumably, only static methods or constructors can be root |
||||||
|
* methods. |
||||||
|
*/ |
||||||
|
public CallGraph(InlineContext context, Set roots) { |
||||||
|
Assert.isTrue(roots != null, "A call graph must have roots"); |
||||||
|
Assert.isTrue(roots.size() > 0, "A call graph must have roots"); |
||||||
|
|
||||||
|
if (preLive == null) { |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
this.context = context; |
||||||
|
this.hier = context.getHierarchy(); |
||||||
|
this.roots = roots; |
||||||
|
|
||||||
|
this.liveClasses = new LinkedHashSet(); |
||||||
|
this.resolvesTo = new LinkedHashMap(); |
||||||
|
this.calls = new LinkedHashMap(); |
||||||
|
this.blocked = new LinkedHashMap(); |
||||||
|
this.worklist = new LinkedList(this.roots); |
||||||
|
this.liveMethods = new LinkedHashSet(); |
||||||
|
|
||||||
|
// To save space, make one InstructionVisitor and use it on every
|
||||||
|
// Instruction.
|
||||||
|
CallVisitor visitor = new CallVisitor(this); |
||||||
|
|
||||||
|
db("Adding pre-live classes"); |
||||||
|
doPreLive(); |
||||||
|
|
||||||
|
db("Constructing call graph"); |
||||||
|
|
||||||
|
// Examine each method in the worklist. At each constructor
|
||||||
|
// invocation make note of the type that was created. At each
|
||||||
|
// method call determine all possible methods that it can resolve
|
||||||
|
// to. Add the methods of classes that have been instantiated to
|
||||||
|
// the worklist.
|
||||||
|
while (!worklist.isEmpty()) { |
||||||
|
MethodRef caller = (MethodRef) worklist.remove(0); |
||||||
|
|
||||||
|
if (liveMethods.contains(caller)) { |
||||||
|
// We've already handled this method
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
MethodGen callerMethod = null; |
||||||
|
try { |
||||||
|
callerMethod = context.editMethod(caller); |
||||||
|
|
||||||
|
} catch (NoSuchMethodException ex1) { |
||||||
|
System.err.println("** Could not find method: " + caller); |
||||||
|
ex1.printStackTrace(System.err); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
// If the method is abstract or native, we can't do anything
|
||||||
|
// with it.
|
||||||
|
if (callerMethod.isAbstract()) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
liveMethods.add(caller); |
||||||
|
|
||||||
|
if (callerMethod.isNative()) { |
||||||
|
// We still want native methods to be live
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
db("\n Examining method " + caller); |
||||||
|
|
||||||
|
Set callees = new LinkedHashSet(); // Methods called by caller
|
||||||
|
calls.put(caller, callees); |
||||||
|
|
||||||
|
// If the method is static or is a constructor, the classes
|
||||||
|
// static initializer method must have been called. Make note
|
||||||
|
// of this.
|
||||||
|
if (callerMethod.isStatic() |
||||||
|
|| callerMethod.getName().equals("<init>")) { |
||||||
|
addClinit(new ObjectType(callerMethod.getClassName())); |
||||||
|
} |
||||||
|
|
||||||
|
// Examine the instructions in the caller method.
|
||||||
|
Iterator code = callerMethod.getInstructionList().iterator(); |
||||||
|
visitor.setCaller(callerMethod); |
||||||
|
while (code.hasNext()) { |
||||||
|
InstructionHandle o = (InstructionHandle) code.next(); |
||||||
|
Instruction inst = o.getInstruction(); |
||||||
|
visitor.visit(inst, callerMethod.getConstantPool()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// We're done constructing the call graph. Try to free up some
|
||||||
|
// memory.
|
||||||
|
blocked = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper method to add the static initializers and all constructors of the |
||||||
|
* pre-live classes to the worklist, etc. |
||||||
|
*/ |
||||||
|
private void doPreLive() { |
||||||
|
if (!USEPRELIVE) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
db("Making constructors of pre-live classes live"); |
||||||
|
|
||||||
|
Iterator iter = preLive.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
String name = (String) iter.next(); |
||||||
|
db(" " + name + " is pre-live"); |
||||||
|
name = name.replace('.', '/'); |
||||||
|
|
||||||
|
ClassGen ce = null; |
||||||
|
try { |
||||||
|
ce = context.editClass(name); |
||||||
|
|
||||||
|
} catch (ClassNotFoundException ex1) { |
||||||
|
System.err.println("** Cannot find pre-live class: " + name); |
||||||
|
ex1.printStackTrace(System.err); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
// Make class and static initializer live
|
||||||
|
liveClasses.add(new ObjectType(ce.getClassName())); |
||||||
|
addClinit(new ObjectType(ce.getClassName())); |
||||||
|
|
||||||
|
// Make all constructors live
|
||||||
|
Method[] methods = ce.getMethods(); |
||||||
|
for (int i = 0; i < methods.length; i++) { |
||||||
|
MethodGen method = context.editMethod(methods[i], ce |
||||||
|
.getClassName()); |
||||||
|
if (method.getName().equals("<init>")) { |
||||||
|
db(" " + method); |
||||||
|
MethodRef methRef = new MethodRef(new ObjectType(ce |
||||||
|
.getClassName()), new NameAndType(method.getName(), |
||||||
|
method.getReturnType()), method.getReturnType(), |
||||||
|
method.getArgumentTypes()); |
||||||
|
worklist.add(methRef); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the static initializer for a given <tt>Type</tt> to the worklist. |
||||||
|
*/ |
||||||
|
void addClinit(Type type) { |
||||||
|
try { |
||||||
|
ClassGen ce = context.editClass(type); |
||||||
|
|
||||||
|
Method[] methods = ce.getMethods(); |
||||||
|
for (int i = 0; i < methods.length; i++) { |
||||||
|
MethodGen clinit = context.editMethod(methods[i], ce |
||||||
|
.getClassName()); |
||||||
|
if (clinit.getName().equals("<clinit>")) { |
||||||
|
MethodRef methRef = new MethodRef(new ObjectType(ce |
||||||
|
.getClassName()), new NameAndType(clinit.getName(), |
||||||
|
clinit.getReturnType()), clinit.getReturnType(), |
||||||
|
clinit.getArgumentTypes()); |
||||||
|
|
||||||
|
worklist.add(methRef); |
||||||
|
context.release(clinit.getMethod(), ce.getClassName()); |
||||||
|
break; |
||||||
|
} |
||||||
|
context.release(clinit.getMethod(), ce.getClassName()); |
||||||
|
} |
||||||
|
context.release(ce.getJavaClass()); |
||||||
|
|
||||||
|
} catch (ClassNotFoundException ex1) { |
||||||
|
System.err.println("** Could not find class for " + type); |
||||||
|
ex1.printStackTrace(System.err); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles a virtual call. Determines all possible methods the call could |
||||||
|
* resolve to. Adds the method whose declaring classes are live to the |
||||||
|
* worklist. Blocks the rest on their declaring types. |
||||||
|
*/ |
||||||
|
void doVirtual(MethodGen caller, MethodRef callee) { |
||||||
|
// Figure out which methods the callee can resolve to.
|
||||||
|
Iterator resolvesToWith = hier.resolvesToWith(callee).iterator(); |
||||||
|
|
||||||
|
while (resolvesToWith.hasNext()) { |
||||||
|
ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) resolvesToWith |
||||||
|
.next(); |
||||||
|
db(" resolves to " + rtw.method); |
||||||
|
|
||||||
|
// Add all possible non-abstract methods to the call graph.
|
||||||
|
// This way, when a blocked method becomes unblocked, it will
|
||||||
|
// still be in the call graph.
|
||||||
|
addCall(caller, rtw.method); |
||||||
|
|
||||||
|
Iterator rTypes = rtw.rTypes.iterator(); |
||||||
|
boolean isLive = false; // Is one of the rTypes live?
|
||||||
|
while (rTypes.hasNext()) { |
||||||
|
Type rType = (Type) rTypes.next(); |
||||||
|
if (liveClasses.contains(rType)) { |
||||||
|
isLive = true; |
||||||
|
db(" Method " + rtw.method + " is live"); |
||||||
|
worklist.add(rtw.method); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!isLive) { |
||||||
|
// If none of the receiver types is live, then the method is
|
||||||
|
// blocked on all possible receiver types.
|
||||||
|
rTypes = rtw.rTypes.iterator(); |
||||||
|
StringBuffer sb = new StringBuffer(); |
||||||
|
while (rTypes.hasNext()) { |
||||||
|
Type rType = (Type) rTypes.next(); |
||||||
|
Set blockedMethods = (Set) blocked.get(rType); |
||||||
|
if (blockedMethods == null) { |
||||||
|
blockedMethods = new LinkedHashSet(); |
||||||
|
blocked.put(rType, blockedMethods); |
||||||
|
} |
||||||
|
blockedMethods.add(rtw.method); |
||||||
|
sb.append(rType.toString()); |
||||||
|
if (rTypes.hasNext()) { |
||||||
|
sb.append(','); |
||||||
|
} |
||||||
|
} |
||||||
|
db(" Blocked " + rtw.method + " on " + sb); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Makes note of one method calling another. This does not make the method |
||||||
|
* live. |
||||||
|
*/ |
||||||
|
void addCall(MethodGen callerMethod, MethodRef callee) { |
||||||
|
// Just maintain the calls mapping
|
||||||
|
MethodRef caller = new MethodRef(new ObjectType(callerMethod |
||||||
|
.getClassName()), new NameAndType(callerMethod.getName(), |
||||||
|
callerMethod.getReturnType()), callerMethod.getReturnType(), |
||||||
|
callerMethod.getArgumentTypes()); |
||||||
|
|
||||||
|
Set callees = (Set) this.calls.get(caller); |
||||||
|
if (callees == null) { |
||||||
|
callees = new LinkedHashSet(); |
||||||
|
this.calls.put(caller, callees); |
||||||
|
} |
||||||
|
callees.add(callee); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Marks a <tt>Type</tt> as being lives. It also unblocks any methods that |
||||||
|
* were blocked on the type. |
||||||
|
*/ |
||||||
|
void makeLive(Type type) { |
||||||
|
if (this.liveClasses.contains(type)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Make type live and unblock all methods blocked on it
|
||||||
|
db(" Making " + type + " live"); |
||||||
|
liveClasses.add(type); |
||||||
|
Set blockedMethods = (Set) blocked.remove(type); |
||||||
|
if (blockedMethods != null) { |
||||||
|
Iterator iter = blockedMethods.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
MemberRef method = (MemberRef) iter.next(); |
||||||
|
db(" Unblocking " + method); |
||||||
|
worklist.add(method); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the methods (<tt>MemberRef</tt>s) to which a given method |
||||||
|
* could resolve. Only live methods are taken into account. The methods are |
||||||
|
* sorted such that overriding methods appear before overriden methods. |
||||||
|
*/ |
||||||
|
public Set resolvesTo(MethodRef method) { |
||||||
|
TreeSet resolvesTo = (TreeSet) this.resolvesTo.get(method); |
||||||
|
|
||||||
|
if (resolvesTo == null) { |
||||||
|
resolvesTo = new TreeSet(new MemberRefComparator(context)); |
||||||
|
this.resolvesTo.put(method, resolvesTo); |
||||||
|
|
||||||
|
Set liveMethods = this.liveMethods(); |
||||||
|
Iterator rtws = hier.resolvesToWith(method).iterator(); |
||||||
|
while (rtws.hasNext()) { |
||||||
|
ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) rtws |
||||||
|
.next(); |
||||||
|
if (liveMethods.contains(rtw.method)) { |
||||||
|
resolvesTo.add(rtw.method); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Return a clone so that the set may safely be modified
|
||||||
|
return ((Set) resolvesTo.clone()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the methods (<tt>MemberRef</tt>s) to which a given method |
||||||
|
* could resolve given that the receiver is in a certain set of types. Only |
||||||
|
* live methods are taken into account. The methods are sorted such that |
||||||
|
* overriding methods appear before overriden methods. |
||||||
|
*/ |
||||||
|
public Set resolvesTo(MethodRef method, Set rTypes) { |
||||||
|
if (rTypes.isEmpty()) { |
||||||
|
return (resolvesTo(method)); |
||||||
|
} |
||||||
|
|
||||||
|
// Since we're only dealing with a subset of types, don't bother
|
||||||
|
// with the caching stuff.
|
||||||
|
TreeSet resolvesTo = new TreeSet(new MemberRefComparator(context)); |
||||||
|
|
||||||
|
Set liveMethods = this.liveMethods(); |
||||||
|
Iterator rtws = hier.resolvesToWith(method).iterator(); |
||||||
|
while (rtws.hasNext()) { |
||||||
|
ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) rtws |
||||||
|
.next(); |
||||||
|
if (liveMethods.contains(rtw.method)) { |
||||||
|
HashSet clone = (HashSet) rtw.rTypes.clone(); |
||||||
|
|
||||||
|
clone.retainAll(rTypes); |
||||||
|
if (!clone.isEmpty()) { |
||||||
|
// Only keep method that have at least one possible
|
||||||
|
// receiver type in rTypes
|
||||||
|
resolvesTo.add(rtw.method); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Return a clone so that the set may safely be modified
|
||||||
|
return ((Set) resolvesTo.clone()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the set of methods (<tt>MemberRef</tt>s) that the |
||||||
|
* construction algorithm has deemed to be live. |
||||||
|
*/ |
||||||
|
public Set liveMethods() { |
||||||
|
// Not all of the methods in the calls mapping are necessarily
|
||||||
|
// live. So, we have to maintain a separate set.
|
||||||
|
return (this.liveMethods); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the root methods (<tt>MemberRef</tt>s) of the call graph. |
||||||
|
*/ |
||||||
|
public Set roots() { |
||||||
|
return (this.roots); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the set of classes (<tt>Type</tt>s) that are instantiated in |
||||||
|
* the program. |
||||||
|
*/ |
||||||
|
public Set liveClasses() { |
||||||
|
return (this.liveClasses); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prints a textual prepresentation of the <tt>CallGraph</tt> to a |
||||||
|
* <tt>PrintWriter</tt>. |
||||||
|
* |
||||||
|
* @param out |
||||||
|
* To where we print |
||||||
|
* @param printLeaves |
||||||
|
* If <tt>true</tt>, leaf methods (methods that do not call |
||||||
|
* any other methods) are printed |
||||||
|
*/ |
||||||
|
public void print(PrintWriter out, boolean printLeaves) { |
||||||
|
|
||||||
|
Iterator callers = calls.keySet().iterator(); |
||||||
|
while (callers.hasNext()) { |
||||||
|
MethodRef caller = (MethodRef) callers.next(); |
||||||
|
|
||||||
|
Iterator callees = ((Set) calls.get(caller)).iterator(); |
||||||
|
|
||||||
|
if (!printLeaves && !callees.hasNext()) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
out.print(caller.declaringClass() + "." + caller.name() |
||||||
|
+ caller.getSignature()); |
||||||
|
if (roots.contains(caller)) { |
||||||
|
out.print(" (root)"); |
||||||
|
} |
||||||
|
out.println(""); |
||||||
|
|
||||||
|
while (callees.hasNext()) { |
||||||
|
MethodRef callee = (MethodRef) callees.next(); |
||||||
|
|
||||||
|
// Only print live methods
|
||||||
|
if (!calls.containsKey(callee)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
out.println(" " + callee.declaringClass() + "." |
||||||
|
+ callee.name() + callee.getSignature()); |
||||||
|
} |
||||||
|
|
||||||
|
out.println(""); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prints a summary of the call graph. Including the classes that are live |
||||||
|
* and which methods are blocked. |
||||||
|
*/ |
||||||
|
public void printSummary(PrintWriter out) { |
||||||
|
out.println("Instantiated classes:"); |
||||||
|
Iterator instantiated = this.liveClasses.iterator(); |
||||||
|
while (instantiated.hasNext()) { |
||||||
|
Type type = (Type) instantiated.next(); |
||||||
|
out.println(" " + type.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
out.println("\nBlocked methods:"); |
||||||
|
if (blocked != null) { |
||||||
|
Iterator types = blocked.keySet().iterator(); |
||||||
|
while (types.hasNext()) { |
||||||
|
Type type = (Type) types.next(); |
||||||
|
out.println(" " + type); |
||||||
|
|
||||||
|
Set set = (Set) blocked.get(type); |
||||||
|
if (set != null) { |
||||||
|
Iterator methods = set.iterator(); |
||||||
|
while (methods.hasNext()) { |
||||||
|
MethodRef method = (MethodRef) methods.next(); |
||||||
|
out.println(" " + method); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
out.println("\nCall graph:"); |
||||||
|
this.print(out, false); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>CallVisitor</tt> examines the instructions in a method and notices what |
||||||
|
* methods are called and which classes are created. |
||||||
|
*/ |
||||||
|
class CallVisitor extends InstructionAdapter { |
||||||
|
MethodGen caller; |
||||||
|
|
||||||
|
CallGraph cg; |
||||||
|
|
||||||
|
boolean firstSpecial; // Are we dealing with the first invokespecial?
|
||||||
|
|
||||||
|
private static void db(String s) { |
||||||
|
CallGraph.db(s); |
||||||
|
} |
||||||
|
|
||||||
|
public CallVisitor(CallGraph cg) { |
||||||
|
this.cg = cg; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCaller(MethodGen caller) { |
||||||
|
this.caller = caller; |
||||||
|
if (caller.getName().equals("<init>")) { |
||||||
|
this.firstSpecial = true; |
||||||
|
} else { |
||||||
|
this.firstSpecial = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(Instruction inst, ConstantPoolGen cpg) { |
||||||
|
if (inst instanceof InvokeInstruction) { |
||||||
|
if (inst instanceof INVOKEVIRTUAL) { |
||||||
|
visit_invokevirtual((InvokeInstruction) inst); |
||||||
|
} else if (inst instanceof INVOKEINTERFACE) { |
||||||
|
visit_invokeinterface((InvokeInstruction) inst); |
||||||
|
} else if (inst instanceof INVOKESTATIC) { |
||||||
|
visit_invokestatic((InvokeInstruction) inst); |
||||||
|
} else if (inst instanceof INVOKESPECIAL) { |
||||||
|
visit_invokespecial((InvokeInstruction) inst); |
||||||
|
} |
||||||
|
} else if (inst instanceof GETSTATIC) { |
||||||
|
visit_getstatic((GETSTATIC) inst); |
||||||
|
} else if (inst instanceof PUTSTATIC) { |
||||||
|
visit_putstatic((PUTSTATIC) inst); |
||||||
|
} else if (inst instanceof NEW) { |
||||||
|
visit_new((NEW) inst); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokevirtual(InvokeInstruction inst, ConstantPoolGen cpg) { |
||||||
|
db("\n Visiting Call: " + inst); |
||||||
|
|
||||||
|
this.firstSpecial = false; |
||||||
|
|
||||||
|
// Call doVirtual to determine which methods this call may resolve
|
||||||
|
// to are live.
|
||||||
|
MethodRef callee = new MethodRef((ObjectType) inst |
||||||
|
.getReferenceType(cpg), new NameAndType( |
||||||
|
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst |
||||||
|
.getReturnType(cpg), inst.getArgumentTypes(cpg)); |
||||||
|
cg.doVirtual(caller, callee); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokeinterface(InvokeInstruction inst, |
||||||
|
ConstantPoolGen cpg) { |
||||||
|
db("\n Visiting Call: " + inst); |
||||||
|
|
||||||
|
this.firstSpecial = false; |
||||||
|
|
||||||
|
// Pretty much the same as invokevirtual
|
||||||
|
MethodRef callee = new MethodRef((ObjectType) inst |
||||||
|
.getReferenceType(cpg), new NameAndType( |
||||||
|
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst |
||||||
|
.getReturnType(cpg), inst.getArgumentTypes(cpg)); |
||||||
|
cg.doVirtual(caller, callee); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokestatic(InvokeInstruction inst, ConstantPoolGen cpg) { |
||||||
|
db("\n Visiting call: " + inst); |
||||||
|
|
||||||
|
this.firstSpecial = false; |
||||||
|
|
||||||
|
// There's not a lot to do with static methods since there is no
|
||||||
|
// dynamic dispatch.
|
||||||
|
MethodRef callee = new MethodRef((ObjectType) inst |
||||||
|
.getReferenceType(cpg), new NameAndType( |
||||||
|
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst |
||||||
|
.getReturnType(cpg), inst.getArgumentTypes(cpg)); |
||||||
|
cg.addCall(caller, callee); |
||||||
|
cg.worklist.add(callee); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_invokespecial(InvokeInstruction inst, ConstantPoolGen cpg) { |
||||||
|
db("\n Visiting call: " + inst); |
||||||
|
|
||||||
|
// Recall that invokespecial is used to call constructors, private
|
||||||
|
// methods, and "super" methods. There is no dynamic dispatch for
|
||||||
|
// special methods.
|
||||||
|
MethodRef callee = new MethodRef((ObjectType) inst |
||||||
|
.getReferenceType(cpg), new NameAndType( |
||||||
|
inst.getMethodName(cpg), inst.getReturnType(cpg)), inst |
||||||
|
.getReturnType(cpg), inst.getArgumentTypes(cpg)); |
||||||
|
|
||||||
|
MethodGen calleeMethod = null; |
||||||
|
|
||||||
|
try { |
||||||
|
calleeMethod = cg.context.editMethod(callee); |
||||||
|
|
||||||
|
} catch (NoSuchMethodException ex1) { |
||||||
|
System.err.println("** Couldn't find method: " + callee); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
if (calleeMethod.isSynchronized() || calleeMethod.isNative()) { |
||||||
|
// Calls to synchronized and native methods are virtual
|
||||||
|
cg.doVirtual(caller, callee); |
||||||
|
|
||||||
|
} else { |
||||||
|
// Calls to everything else (superclass methods, private
|
||||||
|
// methods, etc.) do not involve a dynamic dispatch and can be
|
||||||
|
// treated like a static method.
|
||||||
|
cg.addCall(caller, callee); |
||||||
|
cg.worklist.add(callee); |
||||||
|
} |
||||||
|
|
||||||
|
cg.context.release(calleeMethod.getMethod(), calleeMethod |
||||||
|
.getClassName()); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_getstatic(GETSTATIC inst, ConstantPoolGen cpg) { |
||||||
|
// Referencing a static fields implies that its class's static
|
||||||
|
// initializer has been invoked.
|
||||||
|
db("\n Referencing static field " + inst); |
||||||
|
cg.addClinit((ObjectType) inst.getReferenceType(cpg)); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_putstatic(PUTSTATIC inst, ConstantPoolGen cpg) { |
||||||
|
// Referencing a static field implies that its class's static
|
||||||
|
// initializer has been invoked.
|
||||||
|
db("\n Referencing static field " + inst); |
||||||
|
cg.addClinit((ObjectType) inst.getReferenceType(cpg)); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit_new(NEW inst, ConstantPoolGen cpg) { |
||||||
|
// The new instruction instantiates a type and thus makes it live.
|
||||||
|
cg.makeLive(inst.getLoadClassType(cpg)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Compares <tt>MemberRef</tt>s such that overriding methods are less than |
||||||
|
* overridden methods. |
||||||
|
*/ |
||||||
|
class MemberRefComparator implements Comparator { |
||||||
|
// TypeComparator c;
|
||||||
|
|
||||||
|
public MemberRefComparator(InlineContext context) { |
||||||
|
// c = new TypeComparator(context);
|
||||||
|
} |
||||||
|
|
||||||
|
public int compare(Object o1, Object o2) { |
||||||
|
Assert.isTrue(o1 instanceof MethodRef, o1 + " is not a MethodRef"); |
||||||
|
Assert.isTrue(o2 instanceof MethodRef, o2 + " is not a MethodRef"); |
||||||
|
|
||||||
|
MethodRef ref1 = (MethodRef) o1; |
||||||
|
MethodRef ref2 = (MethodRef) o2; |
||||||
|
Type type1 = ref1.declaringClass(); |
||||||
|
Type type2 = ref2.declaringClass(); |
||||||
|
if (type1 instanceof ArrayType && type2 instanceof ArrayType) { |
||||||
|
type1 = ((ArrayType) type1).getElementType();// TODO
|
||||||
|
type2 = ((ArrayType) type2).getElementType(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
if (type1 instanceof BasicType) { |
||||||
|
if (type2 instanceof BasicType) { |
||||||
|
return (type1 == type2 ? 1 : -1); |
||||||
|
} else { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
} |
||||||
|
if (type2 instanceof BasicType) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
// Both must be ObjectTypes now
|
||||||
|
if (((ObjectType) type1).subclassOf((ObjectType) type2)) |
||||||
|
return -1; |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
// Ignore, for now.
|
||||||
|
} |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean compareTo(Object other) { |
||||||
|
return (other instanceof MemberRefComparator); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,730 @@ |
|||||||
|
/* |
||||||
|
* Class: Inline |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.inline; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
import edu.purdue.cs.bloat.editor.NameAndType; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Inlines the code of non-virtual method call sites. These sites include calls |
||||||
|
* to static methods and certain uses of the <tt>invokespecial</tt> method. |
||||||
|
* There are certain metrics that can be set to effect where and how inlining is |
||||||
|
* performed. |
||||||
|
*/ |
||||||
|
public class Inline { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
private int maxCodeSize; // Max number of instructions in method
|
||||||
|
|
||||||
|
private int maxInlineSize; // Don't inline methods larger than this
|
||||||
|
|
||||||
|
private int maxCallDepth; // Max of height of call stack
|
||||||
|
|
||||||
|
private boolean inlineExceptions; // Inline methods that throw exceptions
|
||||||
|
|
||||||
|
private InlineContext context; |
||||||
|
|
||||||
|
/** |
||||||
|
* Size of the largest method that can be inlined |
||||||
|
*/ |
||||||
|
public static int CALLEE_SIZE = 100000; |
||||||
|
|
||||||
|
private static void db(String s) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(s); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. By default the first-level calls are only inlined one level |
||||||
|
* deep, there is no max size on methods to inline, and methods that may |
||||||
|
* throw exceptions are inlined. |
||||||
|
* |
||||||
|
* @param maxCodeSize |
||||||
|
* The maximum number of instructions a method can grow to. |
||||||
|
*/ |
||||||
|
public Inline(InlineContext context, int maxCodeSize) { |
||||||
|
this.context = context; |
||||||
|
this.maxCodeSize = maxCodeSize; |
||||||
|
this.maxInlineSize = -1; |
||||||
|
this.maxCallDepth = 1; |
||||||
|
this.inlineExceptions = true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the maximum of size of a method that will be inlined. No method |
||||||
|
* larger than this will be inlined. |
||||||
|
*/ |
||||||
|
public void setMaxInlineSize(int maxInlineSize) { |
||||||
|
this.maxInlineSize = maxInlineSize; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the maximum number of nested calls we inline. |
||||||
|
*/ |
||||||
|
public void setMaxCallDepth(int maxCallDepth) { |
||||||
|
this.maxCallDepth = maxCallDepth; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets whether or not methods that may throw exceptions (that is, have a |
||||||
|
* non-empty "throws" declaration) are inlined. |
||||||
|
*/ |
||||||
|
public void setInlineExceptions(boolean inlineExceptions) { |
||||||
|
this.inlineExceptions = inlineExceptions; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Scans a method and inlines non-virtual method calls according to this |
||||||
|
* <tt>Inline</tt>'s metrics. |
||||||
|
*/ |
||||||
|
public void inline(MethodGen method) { |
||||||
|
ConstantPoolGen cpg = method.getConstantPool(); |
||||||
|
// Go through the method and look for calls to inline
|
||||||
|
StackHeightCounter stackHeight = new StackHeightCounter(method); |
||||||
|
InstructionList code = method.getInstructionList(); |
||||||
|
FlowGraph.buildBLOATInstructionList(method); |
||||||
|
boolean firstCall = true; |
||||||
|
Iterator iter = code.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
InstructionHandle ih = (InstructionHandle) iter.next(); |
||||||
|
if (FlowGraph.label(ih)) { |
||||||
|
// stackHeight.handle(ih);
|
||||||
|
// All instructions get handled later
|
||||||
|
db(" " + ih + "." + stackHeight.height() + ") " + ih |
||||||
|
+ (FlowGraph.label(ih) ? " (starts block)" : "")); |
||||||
|
} |
||||||
|
|
||||||
|
Instruction inst = ih.getInstruction(); |
||||||
|
if (inst instanceof INVOKESTATIC || inst instanceof INVOKESPECIAL) { |
||||||
|
InvokeInstruction iI = (InvokeInstruction) inst; |
||||||
|
MethodRef callee = new MethodRef((ObjectType) iI |
||||||
|
.getReferenceType(cpg), new NameAndType(iI |
||||||
|
.getMethodName(cpg), iI.getReturnType(cpg)), iI |
||||||
|
.getReturnType(cpg), iI.getArgumentTypes(cpg)); |
||||||
|
Stack callStack = new Stack(); |
||||||
|
|
||||||
|
callStack.add(new MethodRef(new ObjectType(method |
||||||
|
.getClassName()), new NameAndType(method.getName(), |
||||||
|
method.getReturnType()), method.getReturnType(), method |
||||||
|
.getArgumentTypes())); |
||||||
|
|
||||||
|
db(" Call: " + inst); |
||||||
|
|
||||||
|
stackHeight.handle(ih); |
||||||
|
int expectedHeight = stackHeight.height(); |
||||||
|
stackHeight.unhandle(ih); |
||||||
|
|
||||||
|
InstructionHandle jh = ih; |
||||||
|
ih = inline(method, callee, ih, callStack, stackHeight, |
||||||
|
firstCall); |
||||||
|
|
||||||
|
if (jh == ih) { |
||||||
|
// Call was not inlined, add it to the stack
|
||||||
|
stackHeight.handle(ih); |
||||||
|
db(" " + ih + "." + stackHeight.height() + ") " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
int newHeight = stackHeight.height(); |
||||||
|
// If an exception is thrown as the last thing in a method
|
||||||
|
// newHeight will equal 0. Let's let this one slide.
|
||||||
|
Assert.isTrue(newHeight == 0 || newHeight == expectedHeight, |
||||||
|
"Inlining did not get the stack heights right: " |
||||||
|
+ "Expected " + expectedHeight + ", got " |
||||||
|
+ newHeight); |
||||||
|
|
||||||
|
} else { |
||||||
|
stackHeight.handle(ih); |
||||||
|
db(" " + ih + "." + stackHeight.height() + ") " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
if (inst instanceof InvokeInstruction) { |
||||||
|
firstCall = false; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// method.setCode(code); WE JUST MODIFIED IT SO CHANGES ARE COMMITED
|
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
stackHeight = new StackHeightCounter(method); |
||||||
|
db("\nNew Code for " + method.getClassName() + "." |
||||||
|
+ method.getName() + method.getReturnType()); |
||||||
|
code = method.getInstructionList(); |
||||||
|
Iterator iterator = method.getInstructionList().iterator(); |
||||||
|
InstructionHandle j = null; |
||||||
|
while (iterator.hasNext()) { |
||||||
|
j = (InstructionHandle) iterator.next(); |
||||||
|
if (FlowGraph.label(j)) { |
||||||
|
|
||||||
|
// stackHeight.handle(j);
|
||||||
|
|
||||||
|
CodeExceptionGen[] tryCatches = method |
||||||
|
.getExceptionHandlers(); |
||||||
|
for (int i = 0; i < tryCatches.length; i++) { |
||||||
|
CodeExceptionGen tryCatch = tryCatches[i]; |
||||||
|
if (tryCatch.getStartPC().equals(j)) { |
||||||
|
System.out.println(" Begin protected region"); |
||||||
|
} |
||||||
|
|
||||||
|
if (tryCatch.getEndPC().equals(j)) { |
||||||
|
System.out.println(" End protected region"); |
||||||
|
} |
||||||
|
|
||||||
|
// A Label can both end a protected region and begin
|
||||||
|
// catch
|
||||||
|
// block
|
||||||
|
|
||||||
|
if (tryCatch.getHandlerPC().equals(j)) { |
||||||
|
System.out.println(" Catch " |
||||||
|
+ tryCatch.getCatchType()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
stackHeight.handle(j); |
||||||
|
System.out.println(" " + j + "." + stackHeight.height() + ") " |
||||||
|
+ j.getInstruction() |
||||||
|
+ (FlowGraph.label(j) ? " (starts block)" : "")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// Print try-catch information
|
||||||
|
CodeExceptionGen[] tryCatches = method.getExceptionHandlers(); |
||||||
|
System.out.println("Exception information:"); |
||||||
|
for (int i = 0; i < tryCatches.length; i++) { |
||||||
|
System.out.println(" " + tryCatches[i]); |
||||||
|
} |
||||||
|
System.out.println(""); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper method that does most of the work. By calling this method |
||||||
|
* recursively, we can inline more than one call deep. |
||||||
|
* |
||||||
|
* @param caller |
||||||
|
* The original caller that got all of this started. Into this |
||||||
|
* method we insert the code. |
||||||
|
* @param callee |
||||||
|
* The method to be inlined |
||||||
|
* @param index |
||||||
|
* Where in caller we insert inlined code |
||||||
|
* @param callStack |
||||||
|
* A stack of <tt>MemberRef</tt>s that represent the inlined |
||||||
|
* methods that call other methods. It is used to detect |
||||||
|
* recursion. |
||||||
|
* |
||||||
|
* @return The index into the caller's code array of the instruction |
||||||
|
* following the last inlinined instruction. Start looking here |
||||||
|
* after inline returns. |
||||||
|
*/ |
||||||
|
// isRecursiveCount added so I can be sure of getting a unique local
|
||||||
|
// variable name
|
||||||
|
private InstructionHandle inline(MethodGen caller, MethodRef callee, |
||||||
|
InstructionHandle index, Stack callStack, |
||||||
|
StackHeightCounter stackHeight, boolean firstCall) { |
||||||
|
|
||||||
|
Instruction newInst = null; |
||||||
|
int LOCALVARINDEX = caller.getMaxLocals() - 1; |
||||||
|
|
||||||
|
// Do we ignore the method being inlined?
|
||||||
|
if (context.ignoreMethod(callee)) { |
||||||
|
db(" Can't inline " + callee + ": it's ignored"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
// Can we inline this method
|
||||||
|
if (callStack.size() > maxCallDepth) { |
||||||
|
db(" Can't inline " + callee + ": max call depth (" + maxCallDepth |
||||||
|
+ ") reached"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
|
||||||
|
} else if (callStack.contains(callee)) { |
||||||
|
db(" Can't inline recursive call to " + callee); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
// Make sure we're not inlining the static-ized version of a
|
||||||
|
// method in the call stack.
|
||||||
|
String name = callee.name(); |
||||||
|
// Is this stuff that BCEL would do? or has a BLOAT optimization done it
|
||||||
|
int b = name.indexOf("$$BLOAT"); |
||||||
|
if (b != -1) { |
||||||
|
name = name.substring(0, b); |
||||||
|
|
||||||
|
// Get rid of first parameter
|
||||||
|
Type[] oldParams = callee.paramTypes(); |
||||||
|
Type[] newParams = new Type[oldParams.length - 1]; |
||||||
|
for (int p = 1; p < oldParams.length; p++) { |
||||||
|
newParams[p - 1] = oldParams[p]; |
||||||
|
} |
||||||
|
|
||||||
|
MethodRef unBloated = new MethodRef(callee.declaringClass(), |
||||||
|
new NameAndType(name, callee.returnType()), callee |
||||||
|
.returnType(), newParams); |
||||||
|
|
||||||
|
if (callStack.contains(unBloated)) { |
||||||
|
db(" Can't inline recursive call to " + callee); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
InstructionList code = caller.getInstructionList(); |
||||||
|
if (code.size() > maxCodeSize) { |
||||||
|
db(" Can't inline " + callee + ": max code size (" + maxCodeSize |
||||||
|
+ ") reached"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
MethodGen calleeMethod = null; |
||||||
|
try { |
||||||
|
calleeMethod = context.editMethod(callee); |
||||||
|
|
||||||
|
} catch (NoSuchMethodException ex) { |
||||||
|
System.err.println("Couldn't find method " + callee); |
||||||
|
ex.printStackTrace(System.err); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
if (calleeMethod.isNative()) { |
||||||
|
db(" Can't inline " + callee + ": it's a native method"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
if (calleeMethod.isSynchronized()) { |
||||||
|
db(" Can't inline " + callee + ": it's synchronized"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
if (!inlineExceptions && calleeMethod.getExceptions().length > 0) { |
||||||
|
db(" Can't inline " + callee + ": it may throw an exception"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
if (calleeMethod.getInstructionList().size() > maxInlineSize) { |
||||||
|
db(" Can't inline " + callee + ": it's too big"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
// Methods that catch exceptions are problematic. When an
|
||||||
|
// exception is thrown, it clears the stack. Ordinarily this
|
||||||
|
// isn't a problem. However, now the stack of the caller is
|
||||||
|
// cleared in addition to the stack of the callee. This is bad.
|
||||||
|
// The callee might catch the exception and deal with it.
|
||||||
|
// However, the stack has still been cleared. This really messes
|
||||||
|
// things up for the code that appears after the inlined method.
|
||||||
|
// So, if a method catches an exception, we can only inline it if
|
||||||
|
// the stack contains nothing but the parameters to the call.
|
||||||
|
if (calleeMethod.getExceptionHandlers().length > 0) { |
||||||
|
int size = 0; |
||||||
|
Type[] args = callee.paramTypes(); |
||||||
|
for (int i = 0; i < args.length; i++) { |
||||||
|
size = size + args[i].getSize(); |
||||||
|
} |
||||||
|
if (stackHeight.height() > size) { |
||||||
|
db(" Can't inline " + callee |
||||||
|
+ ": It catches an exception and there's stuff on the " |
||||||
|
+ "stack"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the callee method catches any of the same exceptions as the
|
||||||
|
// protected region that we are currently in, then we can't inline
|
||||||
|
// the method.
|
||||||
|
CodeExceptionGen[] tryCatches0 = calleeMethod.getExceptionHandlers(); |
||||||
|
for (int i = 0; i < tryCatches0.length; i++) { |
||||||
|
CodeExceptionGen tc1 = tryCatches0[i]; |
||||||
|
Iterator iter = stackHeight.tryCatches().iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
CodeExceptionGen tc2 = (CodeExceptionGen) iter.next(); |
||||||
|
Type t1 = tc1.getCatchType(); |
||||||
|
Type t2 = tc2.getCatchType(); |
||||||
|
if (t1 != null && t2 != null && t1.equals(t2)) { |
||||||
|
db(" Can't inline " + callee |
||||||
|
+ ": It catches the same type " |
||||||
|
+ tc1.getCatchType().getClassName() |
||||||
|
+ " as the current protected region"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the caller is a constructor and this is the first
|
||||||
|
// invokespecial we've seen in this callee method, we can inline
|
||||||
|
// calls to the constructors of superclasses and other
|
||||||
|
// constructors in this method. So, if this IS the first call in
|
||||||
|
// a method which IS a constructor, we can inline it.
|
||||||
|
if (calleeMethod.getName().equals("<init>") |
||||||
|
&& (!firstCall || !caller.getName().equals("<init>"))) { |
||||||
|
|
||||||
|
db(" Can't inline " + callee + ": It calls a normal constructor"); |
||||||
|
index = index.getNext(); |
||||||
|
return (index); |
||||||
|
} |
||||||
|
|
||||||
|
// Local variables are problematic. We cannot simply map the
|
||||||
|
// callee's variables to new variables in the caller because we
|
||||||
|
// cannot precisely determine the width of the variable the first
|
||||||
|
// time we see it. (For instance, Nate's generated code might use
|
||||||
|
// a local variable as a non-wide initially and then use it as a
|
||||||
|
// wide later.)
|
||||||
|
|
||||||
|
// Okay, we going to inline. Remove the calling instruction.
|
||||||
|
Instruction call = index.getInstruction(); |
||||||
|
try { |
||||||
|
code.delete(index); |
||||||
|
} catch (TargetLostException tle) { |
||||||
|
// TargetLost? Oh well, go on with inlining
|
||||||
|
} |
||||||
|
index = index.getPrev(); |
||||||
|
db(" Removing call: " + call); |
||||||
|
Assert.isTrue(call instanceof INVOKESTATIC |
||||||
|
|| call instanceof INVOKESPECIAL, |
||||||
|
"Removing the wrong call instruction:" + call); |
||||||
|
callStack.push(callee); |
||||||
|
|
||||||
|
db(" Inlining call (" + callStack.size() + ") to " |
||||||
|
+ callee.declaringClass() + "." + callee.name() + callee.type()); |
||||||
|
context.getInlineStats().noteInlined(); |
||||||
|
|
||||||
|
// ALL RIGHT, CREATE LOCALVARAIBLES FOR EACH OF THE LOCALS IN THE CALLEE
|
||||||
|
// The index should be LOCALVARINDEX + the index set in the calle code
|
||||||
|
// These will be added where they are params or garden variety locals.
|
||||||
|
// indexes shouldn't be a problem.
|
||||||
|
LocalVariableGen[] locals = calleeMethod.getLocalVariables(); |
||||||
|
for (int i = 0; i < locals.length; i++) { |
||||||
|
caller.addLocalVariable("inline" + calleeMethod.getName() + i, |
||||||
|
locals[i].getType(), index, index.getNext()); |
||||||
|
} |
||||||
|
|
||||||
|
// First we have to pop the arguments off the stack and store them
|
||||||
|
// into the local variables. Remember that wide types occupy two
|
||||||
|
// local variables.
|
||||||
|
|
||||||
|
// Mapper mapper = new Mapper(caller);
|
||||||
|
// Type[] paramTypes = callee.paramTypes();
|
||||||
|
|
||||||
|
// IS THERE ANY REASON TO GO BACKWARDS?
|
||||||
|
for (int i = locals.length - 1; i >= 0; i--) { |
||||||
|
// Map the local variables containing the arguments to new
|
||||||
|
// local variables.
|
||||||
|
Type paramType = locals[i].getType(); |
||||||
|
|
||||||
|
if (paramType == null) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
db(" Param " + i + ": of type " + paramType); |
||||||
|
|
||||||
|
// LocalVariable newVar = mapper.map(param, paramType);
|
||||||
|
// I've already created the new LocalVariable
|
||||||
|
|
||||||
|
if (paramType instanceof ReferenceType) { |
||||||
|
newInst = new ASTORE(locals[i].getIndex()); |
||||||
|
} else { |
||||||
|
if (paramType.equals(Type.BOOLEAN) |
||||||
|
|| paramType.equals(Type.BYTE) |
||||||
|
|| paramType.equals(Type.CHAR) |
||||||
|
|| paramType.equals(Type.SHORT) |
||||||
|
|| paramType.equals(Type.INT)) { |
||||||
|
newInst = new ISTORE(locals[i].getIndex()); |
||||||
|
} else if (paramType.equals(Type.DOUBLE)) { |
||||||
|
newInst = new DSTORE(locals[i].getIndex()); |
||||||
|
} else if (paramType.equals(Type.LONG)) { |
||||||
|
newInst = new LSTORE(locals[i].getIndex()); |
||||||
|
} else if (paramType.equals(Type.FLOAT)) { |
||||||
|
newInst = new FSTORE(locals[i].getIndex()); |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException("What's a " + paramType |
||||||
|
+ "doing as a method " + "parameter"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
index = caller.getInstructionList().append(index, newInst); |
||||||
|
stackHeight.handle(index); |
||||||
|
db(" " + index + "." + stackHeight.height() + "> " + newInst); |
||||||
|
} |
||||||
|
// SO ALL THE LOCALS ARE SETUP
|
||||||
|
|
||||||
|
// Before we mess with the code, we have to patch up the try-catch
|
||||||
|
// information from the inlined method to the caller method.
|
||||||
|
CodeExceptionGen[] tryCatches = calleeMethod.getExceptionHandlers(); |
||||||
|
for (int i = 0; i < tryCatches.length; i++) { |
||||||
|
CodeExceptionGen tryCatch = tryCatches[i]; |
||||||
|
|
||||||
|
// INSTRUCTIONHANDLES STAY INTACT WHEN A INSTRUCTIONLIST IS
|
||||||
|
// ADDED
|
||||||
|
// SO WE DON"T NEED TO TRANSLATE LABELS AS BLOAT DID
|
||||||
|
InstructionHandle start = tryCatch.getStartPC(); |
||||||
|
InstructionHandle end = tryCatch.getEndPC(); |
||||||
|
InstructionHandle handler = tryCatch.getHandlerPC(); |
||||||
|
|
||||||
|
caller.addExceptionHandler(start, end, handler, tryCatch |
||||||
|
.getCatchType()); |
||||||
|
} |
||||||
|
|
||||||
|
// Go through the code in the callee method and inline it. Handle
|
||||||
|
// any calls by making a recursive call to this method. Copy each
|
||||||
|
// instruction to the method in which it is being inlined. Along
|
||||||
|
// the way convert references to local variables to their mapped
|
||||||
|
// values. Also remove return instructions. Replace them with
|
||||||
|
// loads as necessary.
|
||||||
|
|
||||||
|
FlowGraph.buildBLOATInstructionList(calleeMethod); |
||||||
|
InstructionList inlineCode = calleeMethod.getInstructionList().copy(); |
||||||
|
// I want to play with the instructionlist and then add it to the caller
|
||||||
|
// code in one go which saves me messing with mapping instructionHandles
|
||||||
|
|
||||||
|
// We don't want to introduce a new end label because it confuses
|
||||||
|
// BLOAT during CFG construction. We designate the end label as
|
||||||
|
// starting a new block in hopes that it will solve problems with
|
||||||
|
// CFG construction.
|
||||||
|
InstructionHandle last = inlineCode.append(new NOP()); |
||||||
|
InstructionHandle endLabel; |
||||||
|
if (FlowGraph.label(last)) { |
||||||
|
endLabel = last; |
||||||
|
} else { |
||||||
|
FlowGraph.setLabel(last); |
||||||
|
endLabel = last; |
||||||
|
} |
||||||
|
// endLabel.setStartsBlock(true);
|
||||||
|
|
||||||
|
firstCall = true; |
||||||
|
Iterator iter = inlineCode.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
InstructionHandle instHandle = (InstructionHandle) iter.next(); |
||||||
|
Instruction inst = instHandle.getInstruction(); |
||||||
|
|
||||||
|
if (FlowGraph.label(instHandle)) { |
||||||
|
// code.add(++index, newLabel);
|
||||||
|
// stackHeight.handle(newLabel);
|
||||||
|
db(" " |
||||||
|
+ index |
||||||
|
+ "." |
||||||
|
+ stackHeight.height() |
||||||
|
+ "> " |
||||||
|
+ inst |
||||||
|
+ (FlowGraph.label(instHandle) ? " (starts block)" : "")); |
||||||
|
} |
||||||
|
|
||||||
|
// Assert.isTrue(o instanceof Instruction, "What is a " + o +
|
||||||
|
// " doing in the instruction stream?");
|
||||||
|
|
||||||
|
// int opcode = inst.opcodeClass();
|
||||||
|
|
||||||
|
if (inst instanceof LocalVariableInstruction) { |
||||||
|
// Map local variable in the callee method to local
|
||||||
|
// variables in the caller method.
|
||||||
|
// LocalVariable local = mapper.map((LocalVariable) operand,
|
||||||
|
// (inst.category() == 2 ? true : false));
|
||||||
|
// operand = local;
|
||||||
|
LocalVariableInstruction lvi = (LocalVariableInstruction) inst; |
||||||
|
lvi.setIndex(lvi.getIndex() + LOCALVARINDEX); |
||||||
|
|
||||||
|
// } else if(inst instanceof Label) {
|
||||||
|
// Map labels in the callee method to labels in the caller
|
||||||
|
// method.
|
||||||
|
// Label label = mapper.map((Label) operand);
|
||||||
|
// operand = label;
|
||||||
|
// HOPEFULLY THE InstructionHandles STAY INTACT
|
||||||
|
|
||||||
|
} else if (inst instanceof Select) { |
||||||
|
// We have to patch up the Labels involved with the Switch
|
||||||
|
// Switch oldSwitch = (Switch) operand;
|
||||||
|
|
||||||
|
// Label newDefault = mapper.map(oldSwitch.defaultTarget());
|
||||||
|
|
||||||
|
// Label[] oldTargets = oldSwitch.targets();
|
||||||
|
// Label[] newTargets = new Label[oldTargets.length];
|
||||||
|
// for(int i = 0; i < newTargets.length; i++) {
|
||||||
|
// Label newTarget = mapper.map(oldTargets[i]);
|
||||||
|
// newTargets[i] = newTarget;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// operand = new Switch(newDefault, newTargets,
|
||||||
|
// oldSwitch.values());
|
||||||
|
// HOPEFULLY THE InstructionHandles STAY INTACT
|
||||||
|
} |
||||||
|
|
||||||
|
if (inst instanceof ReturnInstruction) { |
||||||
|
// Insert a jump to the end of the inlined method. Any
|
||||||
|
// return value will be on top of the stack. This is where
|
||||||
|
// we want it.
|
||||||
|
newInst = new GOTO(endLabel); |
||||||
|
instHandle.setInstruction(newInst); |
||||||
|
// code.append(index, newInst);
|
||||||
|
index = index.getNext(); |
||||||
|
stackHeight.handle(instHandle); |
||||||
|
db(" " + index + "." + stackHeight.height() + "> " + newInst); |
||||||
|
|
||||||
|
} else if (inst instanceof INVOKESTATIC |
||||||
|
|| inst instanceof INVOKESPECIAL) { |
||||||
|
// Make a recursive call. Note that this must be done after
|
||||||
|
// we add the call instruction above. But we only want to
|
||||||
|
// visit the instruction with the stackHeight if the call was
|
||||||
|
// not inlined.
|
||||||
|
// newInst = new Instruction(opcode, operand);
|
||||||
|
// code.add(++index, newInst);
|
||||||
|
InvokeInstruction iI = (InvokeInstruction) inst; |
||||||
|
|
||||||
|
stackHeight.handle(instHandle); |
||||||
|
int expectedHeight = stackHeight.height(); |
||||||
|
stackHeight.unhandle(instHandle); |
||||||
|
ConstantPoolGen cpg = calleeMethod.getConstantPool(); |
||||||
|
MethodRef nestedCall = new MethodRef((ObjectType) iI |
||||||
|
.getReferenceType(cpg), new NameAndType(iI |
||||||
|
.getMethodName(cpg), iI.getReturnType(cpg)), iI |
||||||
|
.getReturnType(cpg), iI.getArgumentTypes(cpg)); |
||||||
|
InstructionHandle oldIndex = instHandle; |
||||||
|
instHandle = inline(caller, nestedCall, instHandle, callStack, |
||||||
|
stackHeight, firstCall); |
||||||
|
|
||||||
|
if (instHandle == oldIndex) { |
||||||
|
stackHeight.handle(instHandle); |
||||||
|
db(" " + instHandle + "." + stackHeight.height() + "> " |
||||||
|
+ inst); |
||||||
|
} |
||||||
|
|
||||||
|
int newHeight = stackHeight.height(); |
||||||
|
Assert.isTrue(newHeight == 0 || newHeight == expectedHeight, |
||||||
|
"Inlining did not get the stack heights right: " |
||||||
|
+ "Expected " + expectedHeight + ", got " |
||||||
|
+ newHeight); |
||||||
|
|
||||||
|
} else { |
||||||
|
// Add the instruction
|
||||||
|
// newInst = new Instruction(opcode, operand);
|
||||||
|
// code.add(++index, newInst);
|
||||||
|
stackHeight.handle(instHandle); |
||||||
|
db(" " + index + "." + stackHeight.height() + "> " + newInst); |
||||||
|
} |
||||||
|
|
||||||
|
// We want to do this after we've made any recursive calls to
|
||||||
|
// inline.
|
||||||
|
if (inst instanceof InvokeInstruction) { |
||||||
|
firstCall = false; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
code.append(index, inlineCode); |
||||||
|
index = endLabel.getNext(); |
||||||
|
// add the whole of the inline method code now that it has been modified
|
||||||
|
|
||||||
|
// if(addEndLabel) {
|
||||||
|
// Done inlining. Add end label.
|
||||||
|
// code.add(++index, endLabel);
|
||||||
|
// stackHeight.handle(endLabel);
|
||||||
|
// db(" " + index + "." + stackHeight.height() + "> " + endLabel +
|
||||||
|
// (endLabel.startsBlock() ? " (starts block)" : ""));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// caller.setDirty(true);
|
||||||
|
callStack.pop(); |
||||||
|
return (index); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Utility class for mapping local variables and labels. Note that when mapping |
||||||
|
* local variables we have to be careful. We can't assume that a variable will |
||||||
|
* retain its "wideness" throughout the method. I learned this one the hard way. |
||||||
|
* So, we have to keep a constant difference between the mapped variables. |
||||||
|
*/ |
||||||
|
/* |
||||||
|
* class Mapper { private Map varsMap; // Maps local variables //private Map
|
||||||
|
* labelsMap; // Maps labels private MethodGen method; // Method into which
|
||||||
|
* things are mapped //private int offset; // Start numbering new locals here
|
||||||
|
* //adding locals to method will do this for us.
|
||||||
|
* |
||||||
|
* private static void db(String s) { if(Inline.DEBUG) System.out.println(s); } |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
*/ |
||||||
|
/* |
||||||
|
* public Mapper(MethodGen method) { this.method = method; varsMap = new |
||||||
|
* HashMap(); labelsMap = new LinkedHashMap(); offset = method.maxLocals() + 1; } |
||||||
|
* |
||||||
|
* public Label map(Label label) { Label newLabel = (Label) |
||||||
|
* labelsMap.get(label); if(newLabel == null) { newLabel = |
||||||
|
* this.method.newLabel(); newLabel.setStartsBlock(label.startsBlock()); |
||||||
|
* labelsMap.put(label, newLabel); db(" " + label + " -> " + newLabel + |
||||||
|
* (newLabel.startsBlock() ? " (starts block)" : "")); } return(newLabel); } |
||||||
|
* |
||||||
|
* public LocalVariableGen map(LocalVariableGen var, Type type) { |
||||||
|
* LocalVariableGen newVar = (LocalVariableGen) varsMap.get(var); if(newVar == |
||||||
|
* null) { newVar = this.method.localAt(var.index() + offset); // newVar =
|
||||||
|
* this.method.newLocal(type); varsMap.put(var, newVar); db(" " + var + " (" + |
||||||
|
* var.index() + ") -> " + newVar + "(" + var.index() + "+" + offset + ")" + |
||||||
|
* (type.isWide() ? " (" + type + ")" : "")); } return(newVar); } |
||||||
|
* |
||||||
|
* public LocalVariable map(LocalVariable var, boolean isWide) { LocalVariable |
||||||
|
* newVar = (LocalVariable) varsMap.get(var); if(newVar == null) { newVar = |
||||||
|
* this.method.localAt(var.index() + offset); // newVar =
|
||||||
|
* this.method.newLocal(isWide); varsMap.put(var, newVar); db(" " + var + " (" + |
||||||
|
* var.index() + ") -> " + newVar + "(" + var.index() + "+" + offset + ")" + |
||||||
|
* (isWide ? " (wide)" : "")); } return(newVar); } } |
||||||
|
*/ |
||||||
|
|
@ -0,0 +1,122 @@ |
|||||||
|
/* |
||||||
|
* Class: InlineContext |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.inline; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.EditorContext; |
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
|
||||||
|
/** |
||||||
|
* An <Tt>InlineContext</tt> gives access to the <Tt>CallGraph</tt> for the |
||||||
|
* program whose classes are being operated on by BLOAT. |
||||||
|
*/ |
||||||
|
public interface InlineContext extends EditorContext { |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the call graph for the program. |
||||||
|
*/ |
||||||
|
public CallGraph getCallGraph(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the root methods for this <tt>InlineContext</tt>. |
||||||
|
* |
||||||
|
* @param roots |
||||||
|
* The root methods (<tt>MemberRef</tt>s) of the program |
||||||
|
* @throws IllegalStateException |
||||||
|
* Call graph has already been created with different roots. |
||||||
|
*/ |
||||||
|
public void setRootMethods(Set roots); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns an <tt>InlineStats</tt> object for getting statistics about |
||||||
|
* inlining. |
||||||
|
*/ |
||||||
|
public InlineStats getInlineStats(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes that all classes, methods, and fields in a package should be |
||||||
|
* "ignored" by inlining. That is, methods won't be inlined, classes won't |
||||||
|
* be involved in specialization, etc. Note that it is exceptable to just |
||||||
|
* add a prefix of a package name. For instance, adding "java" will ignore |
||||||
|
* java.lang.Object, java.io.File, etc. |
||||||
|
*/ |
||||||
|
public void addIgnorePackage(String name); |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes that a class should be ignored by inlining. That is, none of its |
||||||
|
* methods will be inlined and it won't be involved in specialization. |
||||||
|
*/ |
||||||
|
public void addIgnoreClass(Type type); |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes that a method should be ignored by inlining. That is, it will not |
||||||
|
* be inlined. |
||||||
|
*/ |
||||||
|
public void addIgnoreMethod(MethodRef method); |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes that a field should be ignored by inlining. |
||||||
|
*/ |
||||||
|
public void addIgnoreField(MemberRef field); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns <tt>true</tt> if a class should be ignored by inlining. |
||||||
|
*/ |
||||||
|
public boolean ignoreClass(Type type); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns <tt>true</tt> if a method should be ignored by inlining. |
||||||
|
*/ |
||||||
|
public boolean ignoreMethod(MethodRef method); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns <tt>true</tt> if a field should be ignored by inlining. |
||||||
|
*/ |
||||||
|
public boolean ignoreField(MemberRef field); |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets whether or not we ignore all system classes. |
||||||
|
*/ |
||||||
|
public void setIgnoreSystem(boolean ignoreSystem); |
||||||
|
} |
@ -0,0 +1,152 @@ |
|||||||
|
/* |
||||||
|
* Class: InlineStats |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.inline; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is used to gather statistics about inlining. Examples of such |
||||||
|
* statistics are the number of call sites virtual methods resolve to and the |
||||||
|
* number of live classes and methods. |
||||||
|
*/ |
||||||
|
public class InlineStats { |
||||||
|
private String configName; // Name of configuration
|
||||||
|
|
||||||
|
private Map morphicity; // Maps morphic number to count
|
||||||
|
|
||||||
|
private int nLiveClasses; // Number of live classes
|
||||||
|
|
||||||
|
private int nLiveMethods; // Number of live methods
|
||||||
|
|
||||||
|
private int nNoPreexist; // Number of non-preexistent calls
|
||||||
|
|
||||||
|
private int nInlined; // Number of methods inlined
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param configName |
||||||
|
* A string describing the configuration being run |
||||||
|
*/ |
||||||
|
public InlineStats() { |
||||||
|
this.configName = "Inlining stats"; |
||||||
|
this.morphicity = new TreeMap(); |
||||||
|
this.nLiveClasses = 0; |
||||||
|
this.nLiveMethods = 0; |
||||||
|
this.nNoPreexist = 0; |
||||||
|
this.nInlined = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the configuration name for this <tt>InlineStats</tt>. |
||||||
|
*/ |
||||||
|
public void setConfigName(String configName) { |
||||||
|
this.configName = configName; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Maintains a count of the number of methods call sites resolve to. May |
||||||
|
* give an idea as to how "dynamic" a program is. |
||||||
|
*/ |
||||||
|
public void noteMorphicity(int morphicity) { |
||||||
|
Integer r = new Integer(morphicity); |
||||||
|
Integer count = (Integer) this.morphicity.get(r); |
||||||
|
if (count == null) { |
||||||
|
this.morphicity.put(r, new Integer(1)); |
||||||
|
|
||||||
|
} else { |
||||||
|
this.morphicity.put(r, new Integer(count.intValue() + 1)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes that a call site's receiver is not preexistent. |
||||||
|
*/ |
||||||
|
public void noteNoPreexist() { |
||||||
|
nNoPreexist++; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes that a method was inlined |
||||||
|
*/ |
||||||
|
public void noteInlined() { |
||||||
|
this.nInlined++; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes the number of live methods. |
||||||
|
*/ |
||||||
|
public void noteLiveMethods(int nLiveMethods) { |
||||||
|
this.nLiveMethods = nLiveMethods; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes the number of live classes. |
||||||
|
*/ |
||||||
|
public void noteLiveClasses(int nLiveClasses) { |
||||||
|
this.nLiveClasses = nLiveClasses; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Print a summary of the statistics to a <tt>PrintWriter</tt>. |
||||||
|
*/ |
||||||
|
public void printSummary(PrintWriter pw) { |
||||||
|
pw.println("Statistics for " + this.configName + " (" + new Date() |
||||||
|
+ ")"); |
||||||
|
pw.println(" Number of live classes: " + this.nLiveClasses); |
||||||
|
pw.println(" Number of live methods: " + this.nLiveMethods); |
||||||
|
pw.println(" Call site morphism:"); |
||||||
|
|
||||||
|
Iterator morphs = this.morphicity.keySet().iterator(); |
||||||
|
int total = 0; |
||||||
|
while (morphs.hasNext()) { |
||||||
|
Integer morph = (Integer) morphs.next(); |
||||||
|
Integer count = (Integer) this.morphicity.get(morph); |
||||||
|
total += count.intValue(); |
||||||
|
pw.println(" " + morph + "\t" + count); |
||||||
|
} |
||||||
|
pw.println(" Total number of call sites: " + total); |
||||||
|
pw.println(" Number of non-preexistent call sites: " + nNoPreexist); |
||||||
|
pw.println(" Number of inlined methods: " + nInlined); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
CallGraph.class\
|
||||||
|
Inline.class\
|
||||||
|
InlineContext.class\
|
||||||
|
InlineStats.class\
|
||||||
|
InstructionStack.class\
|
||||||
|
StackHeightCounter.class
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,246 @@ |
|||||||
|
/* |
||||||
|
* Class: StackHeightCounter |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.inline; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.editor.InstructionAdapter; |
||||||
|
|
||||||
|
/** |
||||||
|
* Used to keep track of the height of the stack. As instructions are visited, |
||||||
|
* the height of the stack is adjusted accordingly. |
||||||
|
*/ |
||||||
|
public class StackHeightCounter extends InstructionAdapter { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
private int height; // Current stack height
|
||||||
|
|
||||||
|
private LinkedHashMap labelHeights; // Maps labels to their heights as
|
||||||
|
|
||||||
|
// Integers
|
||||||
|
|
||||||
|
private MethodGen method; // Method whose height we're computing
|
||||||
|
|
||||||
|
Set tryCatches; // TryCatches active at current instruction
|
||||||
|
|
||||||
|
private static void db(String s) { |
||||||
|
if (DEBUG) |
||||||
|
System.out.println(s); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param height |
||||||
|
* Initial height of stack |
||||||
|
*/ |
||||||
|
public StackHeightCounter(MethodGen method) { |
||||||
|
this.method = method; |
||||||
|
this.height = 0; |
||||||
|
this.labelHeights = new LinkedHashMap(); |
||||||
|
this.tryCatches = new LinkedHashSet(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the current height of the stack. |
||||||
|
*/ |
||||||
|
public int height() { |
||||||
|
return (this.height); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles a Label. Special provisions must be made for labels that catch |
||||||
|
* exceptions. |
||||||
|
*/ |
||||||
|
// public void handle(Label label) {
|
||||||
|
// }
|
||||||
|
// EVERYTHING IS A INSTRUCTION NOW
|
||||||
|
/** |
||||||
|
* Handles an instruction. Special provisions must be made to handle jumps, |
||||||
|
* switches, throws, and returns. |
||||||
|
*/ |
||||||
|
public void handle(InstructionHandle ih) { |
||||||
|
if (FlowGraph.label(ih)) { |
||||||
|
Integer labelHeight = (Integer) labelHeights.get(ih); |
||||||
|
if (labelHeight != null) { |
||||||
|
height = labelHeight.intValue(); |
||||||
|
} |
||||||
|
|
||||||
|
// If this label begins an exception handler, then start it off
|
||||||
|
// with a new stack with one element (the exception object) on
|
||||||
|
// it.
|
||||||
|
CodeExceptionGen[] tryCatches = method.getExceptionHandlers(); |
||||||
|
for (int i = 0; i < tryCatches.length; i++) { |
||||||
|
if (tryCatches[i].getHandlerPC().equals(ih)) { |
||||||
|
FlowGraph.setLabel(ih); |
||||||
|
height = 1; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (tryCatches[i].getStartPC().equals(ih)) { |
||||||
|
// If this block starts a protected region make note of
|
||||||
|
// the
|
||||||
|
// TryCatch block
|
||||||
|
this.tryCatches.add(tryCatches[i]); |
||||||
|
} |
||||||
|
|
||||||
|
if (tryCatches[i].getEndPC().equals(ih)) { |
||||||
|
// If this block ends a protected region, remove it from
|
||||||
|
// the
|
||||||
|
// tryCatches list
|
||||||
|
this.tryCatches.remove(tryCatches[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
}// ends the bit where we handle Labels but because a labels are
|
||||||
|
// Instructions also....
|
||||||
|
Instruction inst = ih.getInstruction(); |
||||||
|
// inst.visit(this);
|
||||||
|
// Hopefully this avoids that annoying switch statement and all
|
||||||
|
// those visits
|
||||||
|
int delta = 0; |
||||||
|
if (inst instanceof StackConsumer) |
||||||
|
delta = delta |
||||||
|
- ((StackConsumer) inst).consumeStack(method |
||||||
|
.getConstantPool()); |
||||||
|
if ((inst instanceof StackProducer))// &&!(inst instanceof
|
||||||
|
// JsrInstruction))
|
||||||
|
delta = delta |
||||||
|
- ((StackProducer) inst).produceStack(method |
||||||
|
.getConstantPool()); |
||||||
|
this.height = this.height + delta; |
||||||
|
|
||||||
|
if (inst instanceof IfInstruction || inst instanceof GotoInstruction) { |
||||||
|
BranchInstruction bI = (BranchInstruction) inst; |
||||||
|
InstructionHandle target = bI.getTarget(); |
||||||
|
FlowGraph.setLabel(target); |
||||||
|
Integer targetHeight = (Integer) labelHeights.get(target); |
||||||
|
if (targetHeight != null) { |
||||||
|
if (targetHeight.intValue() != height) { |
||||||
|
// Make sure stack heights match
|
||||||
|
db("Stack height mismatch (" + targetHeight.intValue() |
||||||
|
+ " != " + height + ") at " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
labelHeights.put(target, new Integer(height)); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (inst instanceof Select) { |
||||||
|
// Propagate height to all targets
|
||||||
|
Select sw = (Select) inst; |
||||||
|
|
||||||
|
InstructionHandle[] targets = sw.getTargets(); |
||||||
|
for (int t = 0; t < targets.length; t++) { |
||||||
|
InstructionHandle target = targets[t]; |
||||||
|
FlowGraph.setLabel(target); |
||||||
|
Integer targetHeight = (Integer) labelHeights.get(target); |
||||||
|
if (targetHeight != null) { |
||||||
|
if (targetHeight.intValue() != height) { |
||||||
|
// Make sure stack heights match
|
||||||
|
db("Stack height mismatch (" + targetHeight.intValue() |
||||||
|
+ " != " + height + ") at " + inst); |
||||||
|
} |
||||||
|
} else { |
||||||
|
labelHeights.put(target, new Integer(height)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else if (inst instanceof JsrInstruction) { |
||||||
|
// We have to account for the return address being pushed on the
|
||||||
|
// stack. Let's ignore the fact that someday in the future
|
||||||
|
// subroutines may push stuff on the stack. M'kay?
|
||||||
|
InstructionHandle subroutine = ((JsrInstruction) inst).getTarget(); |
||||||
|
FlowGraph.setLabel(subroutine); |
||||||
|
Integer subHeight = (Integer) labelHeights.get(subroutine); |
||||||
|
if (subHeight != null) { |
||||||
|
if (subHeight.intValue() != height + 1) { |
||||||
|
db("Stack height mismatch at subroutine (" |
||||||
|
+ subHeight.intValue() + " != " + (height + 1) |
||||||
|
+ ") at " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
labelHeights.put(subroutine, new Integer(height + 1)); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (inst instanceof ExceptionThrower |
||||||
|
|| inst instanceof ReturnInstruction) { |
||||||
|
// Clear the stack
|
||||||
|
height = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Simulates the effect of "backing up" over an instruction. |
||||||
|
*/ |
||||||
|
public void unhandle(InstructionHandle inst) { |
||||||
|
// Temporarily negate the stack height, perform the normal handle,
|
||||||
|
// and then negate the stack height again.
|
||||||
|
this.height = -this.height; |
||||||
|
this.handle(inst); |
||||||
|
this.height = -this.height; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the set of <tt>TryCatch</tt> objects for the protected region |
||||||
|
* that the current instruction may be in. |
||||||
|
*/ |
||||||
|
public Set tryCatches() { |
||||||
|
return (this.tryCatches); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* public void visit_lushr(Instruction inst) { // Yes, it's only -1. The
|
||||||
|
* long and the int index are popped off // and the shifted value is pushed.
|
||||||
|
* Net loss of 1. height -= 1; } |
||||||
|
* |
||||||
|
* public void visit_jsr(Instruction inst) { // Even though the jsr
|
||||||
|
* instruction itself pushes the return // address onto the stack, we don't
|
||||||
|
* want to account for that // here. It is already taken care of in the
|
||||||
|
* handle method. This // way the label following the jsr (the return site)
|
||||||
|
* will have the // stack height it had before the call. Once again, we do
|
||||||
|
* not // account for the possibility of the jsr modifying the height of //
|
||||||
|
* the stack. height += 0; } |
||||||
|
* |
||||||
|
*/ |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Classes for performing method inlining. The first step in method |
||||||
|
ininling is to create the call graph for a Java "program". Rapid Type |
||||||
|
Analysis [Bacon 1997] is used to keep the size of the call graph |
||||||
|
managable. RTA uses the class hierarchy to determine all possible |
||||||
|
methods that may be invoked at a given call site. Methods are only |
||||||
|
considered to be live if their class is instantiated somewhere in the |
||||||
|
program.</p> |
||||||
|
|
||||||
|
<p>Call sites are specialized using the resolves-to information |
||||||
|
supplied by the call graph. Each virtual method call is transformed |
||||||
|
into a "switch" statement on the possible receiver types. The |
||||||
|
receiver is cast to a given type and a static method is invoked in |
||||||
|
place of the virtual method.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,126 @@ |
|||||||
|
/* |
||||||
|
* Class: CodeGen |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.optimize; |
||||||
|
|
||||||
|
import java.text.DateFormat; |
||||||
|
import java.util.Date; |
||||||
|
import edu.purdue.cs.bloat.codegen.RegisterAllocator; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.codegen.CodeGenerator; |
||||||
|
|
||||||
|
/** |
||||||
|
* CodeGen generates the code after the other optimizations have been performed. |
||||||
|
* It's an Optimization itself, so you have to make sure it gets put in the list |
||||||
|
* of optimizations to perform. |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* CodeGen will print debugging information if the system property |
||||||
|
* <tt>edu.purdue.cs.bloat.DEBUG</tt> is set to <tt>true</tt>. |
||||||
|
* |
||||||
|
* @author Chris Bennetts |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class CodeGen implements Optimization { |
||||||
|
private RegisterAllocator alloc = null; |
||||||
|
|
||||||
|
private static DateFormat dateFormat = DateFormat.getDateTimeInstance( |
||||||
|
DateFormat.SHORT, DateFormat.LONG); |
||||||
|
|
||||||
|
private final boolean DEBUG; |
||||||
|
|
||||||
|
public CodeGen(RegisterAllocator alloc) { |
||||||
|
DEBUG = "true".equals(System.getProperty("edu.purdue.cs.bloat.DEBUG")); |
||||||
|
this.alloc = alloc; |
||||||
|
} |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
// Liveness and RegisterAllocation take place in CodeGenerator
|
||||||
|
CodeGenerator codegen = new CodeGenerator(state); |
||||||
|
|
||||||
|
// Register allocation must occur before replacePhis().
|
||||||
|
printTraceMessage(" Register allocation"); |
||||||
|
|
||||||
|
codegen.replacePhis(); |
||||||
|
printPostPhisMessage(state); |
||||||
|
|
||||||
|
codegen.simplifyControlFlow(); |
||||||
|
|
||||||
|
codegen.allocateReturnAddresses(alloc); |
||||||
|
printPostAllocationMessage(state); |
||||||
|
codegen.generateCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
|
||||||
|
return " Code Generation: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private void printTraceMessage(String root) { |
||||||
|
if (true) |
||||||
|
return; |
||||||
|
|
||||||
|
String dateString = dateFormat.format(new Date()); |
||||||
|
System.out.println(root + ": " + dateString); |
||||||
|
} |
||||||
|
|
||||||
|
private void printPostPhisMessage(MethodState state) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("After fixing Phis------------------------"); |
||||||
|
state.controlFlowGraph().print(System.out); |
||||||
|
System.out.println("End print--------------------------------"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void printPostAllocationMessage(MethodState state) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("After removing empty blocks--------------"); |
||||||
|
state.controlFlowGraph().print(System.out); |
||||||
|
System.out.println("End print--------------------------------"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
/* |
||||||
|
* Class: ConstantPoolSizePrinter |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.optimize; |
||||||
|
|
||||||
|
/** |
||||||
|
* Prints the size of the constant pool. Neatly packaged into an Optimization so |
||||||
|
* that it can be inserted at any point in the optimization cycle. |
||||||
|
* |
||||||
|
* @author Chris Bennetts |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class ConstantPoolSizePrinter implements Optimization { |
||||||
|
public void transform(MethodState state) { |
||||||
|
int size = state.methodGen().getConstantPool().getSize(); |
||||||
|
System.out.println("ConstantPool size: " + size); |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static void print(MethodState state) { |
||||||
|
(new ConstantPoolSizePrinter()).transform(state); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,921 @@ |
|||||||
|
/* |
||||||
|
* Class: Main |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.optimize; |
||||||
|
|
||||||
|
import org.apache.bcel.util.ClassPath; |
||||||
|
import org.apache.bcel.util.Repository; |
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
import org.apache.bcel.classfile.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.DominatorTree; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.cfg.VerifyCFG; |
||||||
|
import edu.purdue.cs.bloat.codegen.CodeGenerator; |
||||||
|
import edu.purdue.cs.bloat.codegen.Liveness; |
||||||
|
import edu.purdue.cs.bloat.context.BloatContext; |
||||||
|
import edu.purdue.cs.bloat.context.PersistentBloatContext; |
||||||
|
import edu.purdue.cs.bloat.diva.InductionVarAnalyzer; |
||||||
|
import edu.purdue.cs.bloat.editor.ClassHierarchy; |
||||||
|
import edu.purdue.cs.bloat.inline.StackHeightCounter; |
||||||
|
import edu.purdue.cs.bloat.ssa.SSA; |
||||||
|
import edu.purdue.cs.bloat.ssa.SSAGraph; |
||||||
|
import edu.purdue.cs.bloat.tbaa.TypeInference; |
||||||
|
import edu.purdue.cs.bloat.trans.DeadCodeElimination; |
||||||
|
import edu.purdue.cs.bloat.trans.ExprPropagation; |
||||||
|
import edu.purdue.cs.bloat.trans.Peephole; |
||||||
|
import edu.purdue.cs.bloat.trans.SSAPRE; |
||||||
|
import edu.purdue.cs.bloat.trans.StackOpt; |
||||||
|
import edu.purdue.cs.bloat.trans.StackOptimization; |
||||||
|
import edu.purdue.cs.bloat.trans.ValueFolding; |
||||||
|
import edu.purdue.cs.bloat.trans.ValueNumbering; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.codegen.RegisterAllocator; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.text.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Usage: java edu.purdue.cs.bloat.optimize.Main [-options] classes dir |
||||||
|
* |
||||||
|
* where options include: -help print out this message -v -verbose turn on |
||||||
|
* verbose mode -debug display a hideous amount of debug info -classpath |
||||||
|
* <directories separated by colons> list directories in which to look for |
||||||
|
* classes -f optimize files even if up-to-date -closure recursively optimize |
||||||
|
* referenced classes -relax-loading don't report errors if a class is not found |
||||||
|
* -skip <class|package.*> skip the given class or package -only |
||||||
|
* <class|package.*> skip all but the given class or package -preserve-debug try |
||||||
|
* to preserve debug information -[no]anno insert an annotation in the contant |
||||||
|
* pool -[no]stack-alloc try to push locals onto the operand stack -peel-loops |
||||||
|
* <n|all> peel innermost loops to enable code hoisting (n >= 0 is the maximum |
||||||
|
* loop level to peel) -[no]pre perform partial redundency elimination |
||||||
|
* -[no]appre perform partial redundency elimination on access paths -[no]dce |
||||||
|
* perform dead code elimination -diva perform demand-driven induction variable |
||||||
|
* analysis -[no]prop perform copy and constant propagation |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class Main { |
||||||
|
// the default class path to read the classes from
|
||||||
|
static String DEFAULT_CLASSPATH = "."; |
||||||
|
|
||||||
|
// Flags that can be set/unset from the command line
|
||||||
|
static boolean DEBUG = false; // Display debugging information
|
||||||
|
|
||||||
|
static boolean VERBOSE = false;// Display status information as program
|
||||||
|
|
||||||
|
// runs
|
||||||
|
|
||||||
|
public static boolean TRACE = false;// Track our progress
|
||||||
|
|
||||||
|
static boolean FORCE = false;// Optimize file even if they are
|
||||||
|
|
||||||
|
// up-to-date
|
||||||
|
|
||||||
|
static boolean CLOSURE = false;// Opimtize over entire heirarchy (i.e.
|
||||||
|
|
||||||
|
// start
|
||||||
|
|
||||||
|
// at the specified classes and recurse up the
|
||||||
|
// class heirarchy)
|
||||||
|
|
||||||
|
static DateFormat dateFormat = DateFormat.getDateTimeInstance( |
||||||
|
DateFormat.SHORT, DateFormat.LONG); |
||||||
|
|
||||||
|
static boolean DIVA = false; |
||||||
|
|
||||||
|
public static boolean PRE = true; |
||||||
|
|
||||||
|
public static boolean DCE = true; |
||||||
|
|
||||||
|
public static boolean PROP = true; |
||||||
|
|
||||||
|
public static boolean FOLD = true; // Value folding
|
||||||
|
|
||||||
|
public static boolean INFER = true; // Type inference
|
||||||
|
|
||||||
|
public static boolean NUMBER = true; // Value numbering
|
||||||
|
|
||||||
|
public static boolean PERSIST = false; // Persistent check elimination
|
||||||
|
|
||||||
|
public static boolean STACK_ALLOC = false; |
||||||
|
|
||||||
|
static boolean ANNO = true; // Note that class file was optimized
|
||||||
|
|
||||||
|
public static boolean VERIFY = true; |
||||||
|
|
||||||
|
public static boolean OPT_STACK_1 = false; // Perform stack optimizations
|
||||||
|
|
||||||
|
public static boolean OPT_STACK_2 = false; |
||||||
|
|
||||||
|
static String[] ARGS = null; // Arguments from the command line
|
||||||
|
|
||||||
|
public static List SKIP = new ArrayList(); |
||||||
|
|
||||||
|
// Classes that are specifically not optimized
|
||||||
|
static List ONLY = new ArrayList(); |
||||||
|
|
||||||
|
// Classes that are specifically optimized
|
||||||
|
static String METHOD = null; // The name of one method to edit
|
||||||
|
|
||||||
|
static BloatContext context = null; |
||||||
|
|
||||||
|
// static ClassFileLoader loader = null;//Used to load classes from
|
||||||
|
// class files
|
||||||
|
static Repository loader = null; |
||||||
|
|
||||||
|
static File outputDir = null; |
||||||
|
|
||||||
|
public static List optimizationsToPerform = null; |
||||||
|
|
||||||
|
/** |
||||||
|
* Parses the command line. The user must specify at least one class to |
||||||
|
* optimize and the directory in which to place the optimized class files. |
||||||
|
* The methods of the specified classes are then optimized according to the |
||||||
|
* command line options. |
||||||
|
* |
||||||
|
* @see ClassEditor |
||||||
|
* @see ClassFileLoader |
||||||
|
* @see ClassFile |
||||||
|
* @see MethodEditor |
||||||
|
* @see MethodInfo |
||||||
|
* |
||||||
|
* @see CompactArrayInitializer |
||||||
|
* @see FlowGraph |
||||||
|
* |
||||||
|
*/ |
||||||
|
public static void main(String[] args) { |
||||||
|
try { |
||||||
|
ClassPath classPath = new ClassPath(DEFAULT_CLASSPATH); |
||||||
|
|
||||||
|
List classes = new ArrayList(args.length); // The classes to
|
||||||
|
// optimize
|
||||||
|
boolean gotdir = false; // Has an output directory been
|
||||||
|
// specified?
|
||||||
|
|
||||||
|
ARGS = args; |
||||||
|
|
||||||
|
for (int i = 0; i < args.length; i++) { |
||||||
|
if (args[i].equals("-v") || args[i].equals("-verbose")) { |
||||||
|
VERBOSE = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-debug")) { |
||||||
|
DEBUG = true; |
||||||
|
FlowGraph.DEBUG = true; |
||||||
|
DominatorTree.DEBUG = true; |
||||||
|
Tree.DEBUG = true; |
||||||
|
CodeGenerator.DEBUG = true; |
||||||
|
Liveness.DEBUG = true; |
||||||
|
SSA.DEBUG = true; |
||||||
|
SSAGraph.DEBUG = true; |
||||||
|
// PersistentCheckElimination.DEBUG = true;
|
||||||
|
ValueNumbering.DEBUG = true; |
||||||
|
ValueFolding.DEBUG = true; |
||||||
|
ClassHierarchy.DEBUG = true; |
||||||
|
TypeInference.DEBUG = true; |
||||||
|
SSAPRE.DEBUG = true; |
||||||
|
ExprPropagation.DEBUG = true; |
||||||
|
DeadCodeElimination.DEBUG = true; |
||||||
|
CodeGenerator.DB_OPT_STACK = true; |
||||||
|
} else if (args[i].equals("-trace")) { |
||||||
|
TRACE = true; |
||||||
|
} else if (args[i].equals("-db")) { |
||||||
|
|
||||||
|
if (++i >= args.length) { |
||||||
|
System.err.println("** No debugging option specified"); |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
if (args[i].equals("bc")) { |
||||||
|
// CodeArray.DEBUG = true;
|
||||||
|
|
||||||
|
} else if (args[i].equals("cfg")) { |
||||||
|
FlowGraph.DEBUG = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("ssa")) { |
||||||
|
SSA.DEBUG = true; |
||||||
|
SSAGraph.DEBUG = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("graphs")) { |
||||||
|
FlowGraph.DB_GRAPHS = true; |
||||||
|
|
||||||
|
} else if (args[i].startsWith("-")) { |
||||||
|
i--; |
||||||
|
|
||||||
|
} else { |
||||||
|
System.err.println("** Unknown debugging option: " |
||||||
|
+ args[i]); |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (args[i].equals("-debugvf")) { |
||||||
|
ValueFolding.DUMP = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-debugbc")) { |
||||||
|
// BloatContext.DEBUG = true;
|
||||||
|
|
||||||
|
} else if (args[i].equals("-help")) { |
||||||
|
usage(); |
||||||
|
|
||||||
|
} else if (args[i].equals("-noanno")) { |
||||||
|
ANNO = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-anno")) { |
||||||
|
ANNO = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-print-flow-graph")) { |
||||||
|
FlowGraph.PRINT_GRAPH = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-preserve-debug")) { |
||||||
|
// CodeGenerator.PRESERVE_DEBUG = true;
|
||||||
|
|
||||||
|
} else if (args[i].equals("-nouse-stack-vars")) { |
||||||
|
Tree.USE_STACK = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-use-stack-vars")) { |
||||||
|
Tree.USE_STACK = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-unique-handlers")) { |
||||||
|
// CodeGenerator.UNIQUE_HANDLERS = true;
|
||||||
|
|
||||||
|
} else if (args[i].equals("-nostack-alloc")) { |
||||||
|
STACK_ALLOC = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-stack-alloc")) { |
||||||
|
STACK_ALLOC = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-no-verify")) { |
||||||
|
VERIFY = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-peel-loops")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
String n = args[i]; |
||||||
|
|
||||||
|
if (n.equals("all")) { |
||||||
|
FlowGraph.PEEL_LOOPS_LEVEL = FlowGraph.PEEL_ALL_LOOPS; |
||||||
|
|
||||||
|
} else { |
||||||
|
try { |
||||||
|
FlowGraph.PEEL_LOOPS_LEVEL = Integer.parseInt(n); |
||||||
|
|
||||||
|
if (FlowGraph.PEEL_LOOPS_LEVEL < 0) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
} catch (NumberFormatException ex) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else if (args[i].equals("-color")) { |
||||||
|
Liveness.UNIQUE = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-nocolor")) { |
||||||
|
Liveness.UNIQUE = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-only-method")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
METHOD = args[i]; |
||||||
|
|
||||||
|
} else if (args[i].equals("-classpath")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
classPath = new ClassPath(args[i]); |
||||||
|
} else if (args[i].equals("-classpath/p")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
classPath = new ClassPath(args[i]); |
||||||
|
} else if (args[i].equals("-skip")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
String pkg = args[i]; |
||||||
|
|
||||||
|
// Account for class file name on command line
|
||||||
|
if (pkg.endsWith(".class")) |
||||||
|
pkg = pkg.substring(0, pkg.lastIndexOf('.')); |
||||||
|
|
||||||
|
SKIP.add(pkg.replace('.', '/')); |
||||||
|
|
||||||
|
} else if (args[i].equals("-only")) { |
||||||
|
if (++i >= args.length) { |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
String pkg = args[i]; |
||||||
|
|
||||||
|
// Account for class file name on command line
|
||||||
|
if (pkg.endsWith(".class")) |
||||||
|
pkg = pkg.substring(0, pkg.lastIndexOf('.')); |
||||||
|
|
||||||
|
ONLY.add(pkg.replace('.', '/')); |
||||||
|
|
||||||
|
} else if (args[i].equals("-nodce")) { |
||||||
|
DCE = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-noprop")) { |
||||||
|
PROP = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-noappre")) { |
||||||
|
SSAPRE.NO_ACCESS_PATHS = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-nopre")) { |
||||||
|
PRE = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-dce")) { |
||||||
|
DCE = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-prop")) { |
||||||
|
PROP = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-appre")) { |
||||||
|
SSAPRE.NO_ACCESS_PATHS = false; |
||||||
|
|
||||||
|
} else if (args[i].equals("-pre")) { |
||||||
|
PRE = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-closure")) { |
||||||
|
CLOSURE = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-opt-stack-1")) { |
||||||
|
OPT_STACK_1 = true; |
||||||
|
CodeGenerator.OPT_STACK = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-opt-stack-2")) { |
||||||
|
OPT_STACK_2 = true; |
||||||
|
CodeGenerator.OPT_STACK_2 = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-diva")) { |
||||||
|
DIVA = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-no-thread")) { |
||||||
|
SSAPRE.NO_THREAD = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-no-precise")) { |
||||||
|
SSAPRE.NO_PRECISE = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-relax-loading")) { |
||||||
|
ClassHierarchy.RELAX = true; |
||||||
|
|
||||||
|
} else if (args[i].equals("-f") || args[i].equals("-force")) { |
||||||
|
FORCE = true; |
||||||
|
|
||||||
|
} else if (args[i].startsWith("-")) { |
||||||
|
System.err.println("No such option: " + args[i]); |
||||||
|
usage(); |
||||||
|
|
||||||
|
} else if (i == args.length - 1) { |
||||||
|
// Last argument is the name of the output directory
|
||||||
|
|
||||||
|
File f = new File(args[i]); |
||||||
|
|
||||||
|
if (f.exists() && !f.isDirectory()) { |
||||||
|
System.err.println("No such directory: " + f.getPath()); |
||||||
|
System.exit(2); |
||||||
|
} |
||||||
|
|
||||||
|
if (!f.exists()) { |
||||||
|
f.mkdirs(); |
||||||
|
} |
||||||
|
|
||||||
|
if (!f.exists()) { |
||||||
|
System.err.println("Couldn't create directory: " |
||||||
|
+ f.getPath()); |
||||||
|
System.exit(2); |
||||||
|
} |
||||||
|
|
||||||
|
// Tell class loader to put optimized classes in f
|
||||||
|
// directory
|
||||||
|
outputDir = f; |
||||||
|
gotdir = true; |
||||||
|
} else { |
||||||
|
// The argument must be a class name...
|
||||||
|
classes.add(args[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
loader = org.apache.bcel.util.SyntheticRepository |
||||||
|
.getInstance(classPath); |
||||||
|
|
||||||
|
if (!gotdir) { |
||||||
|
System.err.println("No output directory specified"); |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
if (classes.size() == 0) { |
||||||
|
System.err.println("** No classes specified"); |
||||||
|
usage(); |
||||||
|
} |
||||||
|
|
||||||
|
if (TRACE) |
||||||
|
System.setProperty("edu.purdue.cs.bloat.TRACE", "true"); |
||||||
|
if (DEBUG) |
||||||
|
System.setProperty("edu.purdue.cs.bloat.DEBUG", "true"); |
||||||
|
|
||||||
|
// Use the CachingBloatingContext
|
||||||
|
context = new PersistentBloatContext(loader, CLOSURE); |
||||||
|
|
||||||
|
buildOptimizationsToPerform(); |
||||||
|
|
||||||
|
boolean errors = false; |
||||||
|
|
||||||
|
Iterator iter = classes.iterator(); |
||||||
|
|
||||||
|
// Now that we've parsed the command line, load the classes into
|
||||||
|
// the
|
||||||
|
// class loader
|
||||||
|
while (iter.hasNext()) { |
||||||
|
String name = (String) iter.next(); |
||||||
|
|
||||||
|
try { |
||||||
|
context.loadClass(name); |
||||||
|
|
||||||
|
} catch (ClassNotFoundException ex) { |
||||||
|
System.err.println("Couldn't find class: " |
||||||
|
+ ex.getMessage()); |
||||||
|
|
||||||
|
errors = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (errors) { |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
if (!CLOSURE) { |
||||||
|
Iterator e = classes.iterator(); |
||||||
|
|
||||||
|
// Edit only the classes that were specified on the command line
|
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
String name = (String) e.next(); |
||||||
|
editClass(name); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// Edit all the classes in the class file editor and their
|
||||||
|
// superclasses
|
||||||
|
|
||||||
|
classes = null; |
||||||
|
|
||||||
|
if (TRACE) { |
||||||
|
System.out.println("Computing closure " |
||||||
|
+ dateFormat.format(new Date())); |
||||||
|
} |
||||||
|
|
||||||
|
Iterator e = context.getHierarchy().classes().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Type t = (Type) e.next(); |
||||||
|
|
||||||
|
if (t instanceof ObjectType) { |
||||||
|
editClass(((ObjectType) t).getClassName()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (ExceptionInInitializerError ex) { |
||||||
|
ex.printStackTrace(); |
||||||
|
System.out.println(ex.getException()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void usage() { |
||||||
|
System.err |
||||||
|
.println("\nUsage: java edu.purdue.cs.bloat.optimize.Main" |
||||||
|
+ "\n [-options] classes dir" |
||||||
|
+ "\n" |
||||||
|
+ "\nwhere options include:" |
||||||
|
+ "\n -help print out this message" |
||||||
|
+ "\n -v -verbose turn on verbose mode" |
||||||
|
+ "\n -debug display a hideous amount of debug info" |
||||||
|
+ "\n -classpath <directories separated by colons>" |
||||||
|
+ "\n list directories in which to look for classes" |
||||||
|
+ "\n -f optimize files even if up-to-date" |
||||||
|
+ "\n -closure recursively optimize referenced classes" |
||||||
|
+ "\n -relax-loading don't report errors if a class is not found" |
||||||
|
+ "\n -skip <class|package.*>" |
||||||
|
+ "\n skip the given class or package" |
||||||
|
+ "\n -only <class|package.*>" |
||||||
|
+ "\n skip all but the given class or package" |
||||||
|
+ "\n -preserve-debug try to preserve debug information" |
||||||
|
+ "\n -[no]anno insert an annotation in the contant pool" |
||||||
|
+ "\n -[no]stack-alloc try to push locals onto the operand stack" |
||||||
|
+ "\n -peel-loops <n|all>" |
||||||
|
+ "\n peel innermost loops to enable code hoisting" |
||||||
|
+ "\n (n >= 0 is the maximum loop level to peel)" |
||||||
|
+ "\n -[no]pre perform partial redundency elimination" |
||||||
|
+ "\n -[no]dce perform dead code elimination" |
||||||
|
+ "\n -diva perform demand-driven induction variable analysis" |
||||||
|
+ "\n -[no]prop perform copy and constant propagation" |
||||||
|
+ ""); |
||||||
|
System.exit(0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs the actual editing of a class. Does a whole mess of stuff |
||||||
|
* including reading in the classfile, building data structures to represent |
||||||
|
* the class file, converting the CFG for each method in the class into SSA |
||||||
|
* form, perform some anlayses and optimizations on the method, and finally |
||||||
|
* committing it back to the class file. Phew. |
||||||
|
*/ |
||||||
|
private static void editClass(String className) { |
||||||
|
JavaClass classFile; // Holds info about a class (implements
|
||||||
|
// ClassInfo)
|
||||||
|
File targetFile = null; |
||||||
|
// Get information about the class className
|
||||||
|
try { |
||||||
|
classFile = (JavaClass) context.loadClass(className); |
||||||
|
} catch (ClassNotFoundException ex) { |
||||||
|
System.err.println("** Couldn't find class: " + ex.getMessage()); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Check to see if the file is up-to-date (i.e. has been
|
||||||
|
// recompiled since it was last optimized). If so, do nothing
|
||||||
|
// because the FORCE flag is false.
|
||||||
|
String source = classFile.getSourceFileName(); |
||||||
|
System.out.println(source + " source file for class:" |
||||||
|
+ classFile.getClassName()); |
||||||
|
File sourceFile = new File(source); |
||||||
|
|
||||||
|
String target = outputDir.getAbsolutePath() |
||||||
|
+ File.separatorChar |
||||||
|
+ classFile.getClassName().substring( |
||||||
|
classFile.getClassName().lastIndexOf(".") + 1) |
||||||
|
+ ".class"; |
||||||
|
System.out.println(target + " selected for output of class: " |
||||||
|
+ classFile.getClassName()); |
||||||
|
targetFile = new File(target); |
||||||
|
|
||||||
|
if (!FORCE) { |
||||||
|
if (sourceFile != null && targetFile != null && sourceFile.exists() |
||||||
|
&& targetFile.exists() |
||||||
|
&& sourceFile.lastModified() < targetFile.lastModified()) { |
||||||
|
if (VERBOSE) { |
||||||
|
System.out.println(classFile.getClassName() |
||||||
|
+ " is up to date"); |
||||||
|
} |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
// return;
|
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
// Print the contents of the class file to System.out
|
||||||
|
System.out.println(classFile); |
||||||
|
} |
||||||
|
|
||||||
|
ClassGen c = context.editClass(classFile); |
||||||
|
|
||||||
|
boolean skip = false; |
||||||
|
|
||||||
|
String name = c.getClassName(); |
||||||
|
String qual = ""; |
||||||
|
if (name.lastIndexOf('/') != -1) |
||||||
|
qual = name.substring(0, name.lastIndexOf('/')) + "/*"; |
||||||
|
|
||||||
|
// Edit only classes explicitly mentioned.
|
||||||
|
if (ONLY.size() > 0) { |
||||||
|
skip = true; |
||||||
|
|
||||||
|
// Only edit classes we explicitly don't name.
|
||||||
|
for (int i = 0; i < ONLY.size(); i++) { |
||||||
|
String pkg = (String) ONLY.get(i); |
||||||
|
|
||||||
|
if (name.equals(pkg) || qual.equals(pkg)) { |
||||||
|
skip = false; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Don't edit classes we explicitly skip.
|
||||||
|
if (!skip) { |
||||||
|
for (int i = 0; i < SKIP.size(); i++) { |
||||||
|
String pkg = (String) SKIP.get(i); |
||||||
|
|
||||||
|
if (name.equals(pkg) || qual.equals(pkg)) { |
||||||
|
skip = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (skip) { |
||||||
|
if (VERBOSE) { |
||||||
|
System.out.println("Skipping " + c.getClassName()); |
||||||
|
} |
||||||
|
|
||||||
|
// We're done with this class file, decrement its reference
|
||||||
|
// count
|
||||||
|
context.release(classFile); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Touch the output file first. That is, create the file, but make
|
||||||
|
// it empty, just to make sure we can create it.
|
||||||
|
// File outputDir = loader.outputDir();
|
||||||
|
|
||||||
|
if (VERBOSE) { |
||||||
|
System.out.println("Optimizing " + c.getClassName()); |
||||||
|
} |
||||||
|
|
||||||
|
// Finally, we can start playing with the methods...
|
||||||
|
Method[] methods = c.getMethods(); |
||||||
|
|
||||||
|
int numMethods = methods.length + 1; |
||||||
|
; |
||||||
|
int whichMethod = 0; |
||||||
|
|
||||||
|
for (int j = 0; j < methods.length; j++) { |
||||||
|
final MethodGen m; |
||||||
|
|
||||||
|
try { |
||||||
|
m = context.editMethod(methods[j], c.getClassName()); |
||||||
|
} catch (ClassFormatException ex) { |
||||||
|
System.err.println(ex.getMessage()); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (TRACE) { |
||||||
|
whichMethod++; |
||||||
|
System.out |
||||||
|
.println("Optimizing " + name + "." + m.getName() |
||||||
|
+ " (method " + whichMethod + " of " |
||||||
|
+ numMethods + ")"); |
||||||
|
} |
||||||
|
|
||||||
|
if (METHOD != null) { |
||||||
|
// A method name has been specified on the command line using
|
||||||
|
// -only-method.
|
||||||
|
boolean pass = true; |
||||||
|
|
||||||
|
String t = m.getName() + m.getSignature(); |
||||||
|
|
||||||
|
if (t.equals(METHOD)) { |
||||||
|
pass = false; |
||||||
|
} |
||||||
|
|
||||||
|
t = m.getName(); |
||||||
|
|
||||||
|
if (t.equals(METHOD)) { |
||||||
|
pass = false; |
||||||
|
} |
||||||
|
|
||||||
|
if (pass) { |
||||||
|
// This isn't the method we're looking for.
|
||||||
|
// Decrement its reference count.
|
||||||
|
context.release(methods[j], c.getClassName()); |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(m); |
||||||
|
} |
||||||
|
|
||||||
|
if (m.isNative() || m.isAbstract()) { |
||||||
|
// We can't edit native or abstract methods
|
||||||
|
context.release(methods[j], c.getClassName()); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
MethodBloater bloater = new MethodBloater(optimizationsToPerform); |
||||||
|
bloater.bloatMethod(m, context); |
||||||
|
} |
||||||
|
|
||||||
|
if (ANNO) { |
||||||
|
String s = "Optimized with: edu.purdue.cs.bloat.optimize.Main"; |
||||||
|
|
||||||
|
for (int i = 0; i < ARGS.length; i++) { |
||||||
|
if (ARGS[i].indexOf(' ') >= 0 || ARGS[i].indexOf('\t') >= 0 |
||||||
|
|| ARGS[i].indexOf('\r') >= 0 |
||||||
|
|| ARGS[i].indexOf('\n') >= 0) { |
||||||
|
s += " '" + ARGS[i] + "'"; |
||||||
|
} else { |
||||||
|
s += " " + ARGS[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
System.out.println(s); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
classFile = context.editClass(classFile.getClassName()) |
||||||
|
.getJavaClass(); |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
classFile.dump(targetFile); |
||||||
|
} catch (java.io.IOException io) { |
||||||
|
System.out.println("An error occured whilst writing file: " |
||||||
|
+ targetFile.getPath()); |
||||||
|
} |
||||||
|
if (TRACE) |
||||||
|
System.out.println(context.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
public static void dumpcode(MethodGen m) { |
||||||
|
PrintWriter out = new PrintWriter(System.out, true); |
||||||
|
StackHeightCounter shc = new StackHeightCounter(m); |
||||||
|
|
||||||
|
out.println("Code for method " + m.getName() + m.getSignature()); |
||||||
|
InstructionList instructions = m.getInstructionList(); |
||||||
|
Iterator iter = instructions.iterator(); |
||||||
|
while (iter.hasNext()) { |
||||||
|
Object obj = iter.next(); |
||||||
|
shc.handle((InstructionHandle) obj); |
||||||
|
|
||||||
|
System.out |
||||||
|
.println(" " + obj + " (sh: " + shc.height() + ")"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* The following block of code is a version of buildOptimizationsToPerform |
||||||
|
* that does not use OptimizationsBuilder. If you revert to this version, |
||||||
|
* you will have to uncomment the last couple of lines of |
||||||
|
* MethodBloater#doAnOptimization(). |
||||||
|
* |
||||||
|
* private static void buildOptimizationsToPerform() { |
||||||
|
* optimizationsToPerform = new ArrayList(); |
||||||
|
* |
||||||
|
* if (COMPACT_ARRAY_INIT) optimizationsToPerform.add(new |
||||||
|
* CompactArrayInitializer()); |
||||||
|
* |
||||||
|
* optimizationsToPerform.add(new SSA()); |
||||||
|
* |
||||||
|
* if ((! Tree.USE_STACK) && PROP) optimizationsToPerform.add(new |
||||||
|
* ExprPropagation()); |
||||||
|
* |
||||||
|
* if (DCE) optimizationsToPerform.add(new DeadCodeElimination()); |
||||||
|
* |
||||||
|
* if (INFER) optimizationsToPerform.add(new TypeInference()); |
||||||
|
* |
||||||
|
* if (NUMBER) optimizationsToPerform.add(new ValueNumbering()); |
||||||
|
* |
||||||
|
* if (FOLD) optimizationsToPerform.add(new ValueFolding()); |
||||||
|
* |
||||||
|
* if (PRE) optimizationsToPerform.add(new SSAPRE()); |
||||||
|
* |
||||||
|
* if (FOLD) optimizationsToPerform.add(new ValueFolding()); |
||||||
|
* |
||||||
|
* if (PROP) optimizationsToPerform.add(new ExprPropagation()); // make sure
|
||||||
|
* we've done at least one thing since the last DCE if (DCE && (INFER || |
||||||
|
* NUMBER || FOLD || PRE || PROP)) optimizationsToPerform.add(new |
||||||
|
* DeadCodeElimination()); //doDeadCodeElimination(cfg, context); /* if
|
||||||
|
* (PERSIST) (new PersistentCheckElimination()).transform(cfg); |
||||||
|
*/ |
||||||
|
/* |
||||||
|
* if (DIVA) optimizationsToPerform.add(new InductionVarAnalyzer()); |
||||||
|
* //doInductionVarAnalysis(cfg, context);
|
||||||
|
* |
||||||
|
* if (OPT_STACK_2) { optimizationsToPerform.add(new StackOpt()); |
||||||
|
* optimizationsToPerform.add(new SSA()); optimizationsToPerform.add(new |
||||||
|
* DeadCodeElimination()); } |
||||||
|
* |
||||||
|
* if (CodeGenerator.OPT_STACK) { optimizationsToPerform.add(new |
||||||
|
* StackOptimization()); } |
||||||
|
* |
||||||
|
* if (VERIFY) optimizationsToPerform.add(new VerifyCFG()); |
||||||
|
* |
||||||
|
* optimizationsToPerform.add(new CodeGen()); optimizationsToPerform.add(new |
||||||
|
* ConstantPoolSizePrinter()); optimizationsToPerform.add(new Peephole()); } |
||||||
|
*/ |
||||||
|
|
||||||
|
public static void buildOptimizationsToPerform() { |
||||||
|
|
||||||
|
OptimizationsBuilder builder = new OptimizationsBuilder(); |
||||||
|
|
||||||
|
builder.add(new SSA()); |
||||||
|
|
||||||
|
if ((!Tree.USE_STACK) && PROP) |
||||||
|
builder.add(new ExprPropagation()); |
||||||
|
|
||||||
|
if (DCE) |
||||||
|
builder.add(new DeadCodeElimination()); |
||||||
|
|
||||||
|
if (INFER) |
||||||
|
builder.add(new TypeInference()); |
||||||
|
|
||||||
|
if (NUMBER) |
||||||
|
builder.add(new ValueNumbering()); |
||||||
|
|
||||||
|
if (FOLD) |
||||||
|
builder.add(new ValueFolding()); |
||||||
|
|
||||||
|
if (PRE) |
||||||
|
builder.add(new SSAPRE()); |
||||||
|
|
||||||
|
if (FOLD) |
||||||
|
builder.add(new ValueFolding()); |
||||||
|
|
||||||
|
if (PROP) |
||||||
|
builder.add(new ExprPropagation()); |
||||||
|
|
||||||
|
// make sure we've done at least one thing since the last DCE
|
||||||
|
if (DCE && (INFER || NUMBER || FOLD || PRE || PROP)) |
||||||
|
builder.add(new DeadCodeElimination()); |
||||||
|
|
||||||
|
/* |
||||||
|
* if (PERSIST) (new PersistentCheckElimination()).transform(cfg); |
||||||
|
*/ |
||||||
|
|
||||||
|
if (DIVA) |
||||||
|
builder.add(new InductionVarAnalyzer()); |
||||||
|
|
||||||
|
if (OPT_STACK_2) { |
||||||
|
builder.add(new StackOpt()); |
||||||
|
builder.add(new SSA()); |
||||||
|
builder.add(new DeadCodeElimination()); |
||||||
|
} |
||||||
|
RegisterAllocator alloc = new RegisterAllocator(); |
||||||
|
builder.add(alloc); |
||||||
|
|
||||||
|
if (CodeGenerator.OPT_STACK) { |
||||||
|
builder.add(new StackOptimization()); |
||||||
|
} |
||||||
|
|
||||||
|
if (VERIFY) |
||||||
|
builder.add(new VerifyCFG()); |
||||||
|
|
||||||
|
builder.add(new CodeGen(alloc)); |
||||||
|
// builder.add(new ConstantPoolSizePrinter());
|
||||||
|
builder.add(new Peephole()); |
||||||
|
|
||||||
|
optimizationsToPerform = builder.getList(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* OptimizationsBuilder is a little utility class intended to simplify the |
||||||
|
* creation of the list of optimizations. In particular, it will |
||||||
|
* automatically add a VerifyCFG call after each optimization whenever we're |
||||||
|
* in debug mode. This simplifies the creation of the list, and |
||||||
|
* {@link MethodBloater#doAnOptimization(Optimization, MethodState)} too. |
||||||
|
* |
||||||
|
* @author Chris Bennetts |
||||||
|
* |
||||||
|
*/ |
||||||
|
static class OptimizationsBuilder { |
||||||
|
private List _optimizations = new ArrayList(); |
||||||
|
|
||||||
|
public List getList() { |
||||||
|
return _optimizations; |
||||||
|
} |
||||||
|
|
||||||
|
public OptimizationsBuilder add(Optimization opt) { |
||||||
|
_optimizations.add(opt); |
||||||
|
if (DEBUG) |
||||||
|
_optimizations.add(new VerifyCFG()); |
||||||
|
|
||||||
|
return this; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
CodeGen.class \
|
||||||
|
ConstantPoolSizePrinter.class \
|
||||||
|
Main.class \
|
||||||
|
MethodBloater.class \
|
||||||
|
MethodState.class \
|
||||||
|
Optimization.class
|
||||||
|
|
||||||
|
include ../class.mk |
||||||
|
|
@ -0,0 +1,243 @@ |
|||||||
|
/* |
||||||
|
* Class: MethodBloater |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.optimize; |
||||||
|
|
||||||
|
import java.text.DateFormat; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.LocalVariableGen; |
||||||
|
import org.apache.bcel.generic.CodeExceptionGen; |
||||||
|
import org.apache.bcel.generic.MethodGen; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.context.BloatContext; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs BLOAT-ing on a method. A single MethodBloater object may be safely |
||||||
|
* reused for multiple methods. |
||||||
|
* |
||||||
|
* Extra debugging information will be printed if the system property |
||||||
|
* <tt>edu.purdue.cs.bloat.DEBUG</tt> is set to <tt>true</tt>. |
||||||
|
* |
||||||
|
* @author Chris Bennetts |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class MethodBloater { |
||||||
|
static DateFormat dateFormat = DateFormat.getDateTimeInstance( |
||||||
|
DateFormat.SHORT, DateFormat.LONG); |
||||||
|
|
||||||
|
static boolean DEBUG = "true".equals(System |
||||||
|
.getProperty("edu.purdue.cs.bloat.DEBUG")); |
||||||
|
|
||||||
|
List optimizationsToPerform; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new MethodBloater. |
||||||
|
* |
||||||
|
* @param optimizationsToPerform |
||||||
|
* The optimizations to be performed. |
||||||
|
*/ |
||||||
|
public MethodBloater(List optimizationsToPerform) { |
||||||
|
this.optimizationsToPerform = optimizationsToPerform; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* BLOAT a single method. Creates the {@link MethodState method state}, |
||||||
|
* runs the optimizations, and commits any changes back to the context |
||||||
|
* object. |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Will return prematurely if there is a problem creating the control flow |
||||||
|
* graph. |
||||||
|
*/ |
||||||
|
public void bloatMethod(MethodGen methodGen, BloatContext context) { |
||||||
|
try { |
||||||
|
MethodBloater.printMethodGenInfo(methodGen); |
||||||
|
|
||||||
|
MethodState state = new MethodState(methodGen, context); |
||||||
|
if (state.controlFlowGraph() == null) |
||||||
|
return; |
||||||
|
|
||||||
|
performOptimizations(state); |
||||||
|
state.commitChanges(); |
||||||
|
|
||||||
|
// ConstantPoolSizePrinter.print(state);
|
||||||
|
MethodBloater.printMethodGenInfo(methodGen); |
||||||
|
} catch (IllegalArgumentException e) { |
||||||
|
System.out.println(" NOTE: CFG did not verify while bloating " |
||||||
|
+ methodGen.getName() |
||||||
|
+ " after all optimizations. Exception: " + e); |
||||||
|
e.printStackTrace(); |
||||||
|
} catch (Exception e) { |
||||||
|
String msg = "** Exception while optimizing " + methodGen.getName() |
||||||
|
+ methodGen.getSignature() + " of class " |
||||||
|
+ methodGen.getClassName(); |
||||||
|
System.err.println(msg); |
||||||
|
System.err.println(e.getMessage()); |
||||||
|
e.printStackTrace(System.err); |
||||||
|
System.exit(1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs all optimizations on the method. |
||||||
|
* |
||||||
|
* @param state |
||||||
|
* The method to perform the optimizations on. |
||||||
|
* @throws Exception |
||||||
|
* Any exception that may be thrown by the optimizations. |
||||||
|
*/ |
||||||
|
public void performOptimizations(MethodState state) throws Exception { |
||||||
|
Assert.isNotNull(optimizationsToPerform); |
||||||
|
|
||||||
|
Iterator it = optimizationsToPerform.iterator(); |
||||||
|
|
||||||
|
while (it.hasNext()) { |
||||||
|
Optimization opt = (Optimization) it.next(); |
||||||
|
doAnOptimization(opt, state); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Print the trace message for an optimization. |
||||||
|
* |
||||||
|
* @see Optimization#traceMessage(String) |
||||||
|
*/ |
||||||
|
private void printTraceMessage(Optimization o) { |
||||||
|
if (!DEBUG) |
||||||
|
return; |
||||||
|
|
||||||
|
String dateString = dateFormat.format(new Date()); |
||||||
|
String message = o.traceMessage(dateString); |
||||||
|
|
||||||
|
if (message != null) |
||||||
|
System.out.println(message); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Print a debug message for an optimization. Called before the |
||||||
|
* transformation is performed. |
||||||
|
* |
||||||
|
* @see Optimization#preDebugMessage() |
||||||
|
*/ |
||||||
|
private void printPreDebugMessage(Optimization o) { |
||||||
|
if (!DEBUG) |
||||||
|
return; |
||||||
|
|
||||||
|
String message = o.preDebugMessage(); |
||||||
|
|
||||||
|
if (message != null) |
||||||
|
System.out.println(message); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Print a debug message for an optimization. Called after the |
||||||
|
* transformation is performed. |
||||||
|
* |
||||||
|
* @see Optimization#postDebugMessage() |
||||||
|
*/ |
||||||
|
private void printPostDebugMessage(Optimization o) { |
||||||
|
if (!DEBUG) |
||||||
|
return; |
||||||
|
|
||||||
|
String message = o.postDebugMessage(); |
||||||
|
|
||||||
|
if (message != null) |
||||||
|
System.out.println(message); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Apply an optimization to a method. |
||||||
|
* |
||||||
|
* @param optimization |
||||||
|
* The optimization to be performed. |
||||||
|
* @param state |
||||||
|
* The method to perform the optimization on. |
||||||
|
* @throws Exception |
||||||
|
* Any exception thrown by the optimization. |
||||||
|
* |
||||||
|
* @see Optimization#transform(MethodState) |
||||||
|
*/ |
||||||
|
private void doAnOptimization(Optimization optimization, MethodState state) |
||||||
|
throws Exception { |
||||||
|
printTraceMessage(optimization); |
||||||
|
printPreDebugMessage(optimization); |
||||||
|
|
||||||
|
optimization.transform(state); |
||||||
|
|
||||||
|
printPostDebugMessage(optimization); |
||||||
|
|
||||||
|
// FIXME: VerifyCFG can itself now be called as an Optimization.
|
||||||
|
// Use a Builder or something to encapsulate this bit of behaviour.
|
||||||
|
// This is currently implemented by Main.OptimizationsBuilder, and
|
||||||
|
// MainG2 allows it to just be inserted into the list of optimizations.
|
||||||
|
|
||||||
|
// if (DEBUG)
|
||||||
|
// VerifyCFG.verify(state.controlFlowGraph());
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Print some debugging info about the MethodGen. |
||||||
|
*/ |
||||||
|
static void printMethodGenInfo(MethodGen methodGen) { |
||||||
|
if (!DEBUG) |
||||||
|
return; |
||||||
|
|
||||||
|
LocalVariableGen[] locals = null; |
||||||
|
CodeExceptionGen[] excptns = null; |
||||||
|
System.out.println("Method: " + methodGen); |
||||||
|
System.out.println(methodGen.getMethod().getCode()); |
||||||
|
System.out.println(); |
||||||
|
locals = methodGen.getLocalVariables(); |
||||||
|
if (locals != null) { |
||||||
|
System.out.println("LocalVariables: "); |
||||||
|
for (int j = 0; j < locals.length; j++) |
||||||
|
System.out.println(" " + locals[j]); |
||||||
|
} |
||||||
|
excptns = methodGen.getExceptionHandlers(); |
||||||
|
if (excptns != null) { |
||||||
|
System.out.println("ExceptionHandlers: "); |
||||||
|
for (int j = 0; j < excptns.length; j++) |
||||||
|
System.out.println(" " + excptns[j]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,140 @@ |
|||||||
|
/* |
||||||
|
* Class: MethodState |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.optimize; |
||||||
|
|
||||||
|
import org.apache.bcel.classfile.ClassFormatException; |
||||||
|
import org.apache.bcel.generic.MethodGen; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.context.BloatContext; |
||||||
|
|
||||||
|
/** |
||||||
|
* MethodState encapsulates three related items for a method: |
||||||
|
* |
||||||
|
* <ul> |
||||||
|
* <li>its MethodGen,</li> |
||||||
|
* <li>its Control Flow Graph,</li> |
||||||
|
* <li>its context.</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* These tend to be passed around and updated together, so it made sense to |
||||||
|
* group them together. |
||||||
|
* |
||||||
|
* Note that this class has no "setters". If they appear necessary, |
||||||
|
* move the code that would need them in to this class, instead of taking the |
||||||
|
* shortcut. |
||||||
|
* |
||||||
|
* @author Chris Bennetts |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class MethodState { |
||||||
|
private MethodGen _methodGen; |
||||||
|
|
||||||
|
private FlowGraph _controlFlowGraph; |
||||||
|
|
||||||
|
private BloatContext _context; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new MethodState object. The control flow graph is generated |
||||||
|
* automatically. |
||||||
|
*/ |
||||||
|
public MethodState(MethodGen methodGen, BloatContext context) { |
||||||
|
_methodGen = methodGen; |
||||||
|
_context = context; |
||||||
|
|
||||||
|
rebuildFlowGraph(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Obtain the MethodGen. |
||||||
|
*/ |
||||||
|
public MethodGen methodGen() { |
||||||
|
return _methodGen; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Obtain the control flow graph. In general, favour |
||||||
|
* {@link #controlFlowGraph() controlFlowGraph()}. |
||||||
|
*/ |
||||||
|
public FlowGraph cfg() { |
||||||
|
return controlFlowGraph(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Obtain the control flow graph. |
||||||
|
*/ |
||||||
|
public FlowGraph controlFlowGraph() { |
||||||
|
return _controlFlowGraph; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Obtain the current context. |
||||||
|
*/ |
||||||
|
public BloatContext context() { |
||||||
|
return _context; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Rebuild the control flow graph. Use if it falls out of sync with the |
||||||
|
* MethodGen. |
||||||
|
* |
||||||
|
*/ |
||||||
|
public void rebuildFlowGraph() { |
||||||
|
try { |
||||||
|
_controlFlowGraph = new FlowGraph(_methodGen); |
||||||
|
} catch (ClassFormatException ex) { |
||||||
|
System.err.println(ex.getMessage()); |
||||||
|
_context.release(_methodGen.getMethod(), _methodGen.getClassName()); |
||||||
|
_controlFlowGraph = null; |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
_controlFlowGraph.initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Commit changes to the method to the context. |
||||||
|
* |
||||||
|
*/ |
||||||
|
public void commitChanges() { |
||||||
|
_context.commit(_methodGen); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
/* |
||||||
|
* Class: Optimization |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.optimize; |
||||||
|
|
||||||
|
/** |
||||||
|
* Optimization provides a uniform interface to all transformations provided by |
||||||
|
* BLOAT. As well as the transform() method, Optimization also specifies a |
||||||
|
* number of trace/debug methods. |
||||||
|
* |
||||||
|
* There's no actual requirement for Optimizations to actually transform the |
||||||
|
* code. It is perfectly acceptable to create "optimizations" that print some |
||||||
|
* kind of debugging information without actually changing the method state. |
||||||
|
* |
||||||
|
* In addition to the four methods that this interface declares, all |
||||||
|
* implementers must provide a public zero-argument constructor. |
||||||
|
* |
||||||
|
* @author Chris Bennetts |
||||||
|
* |
||||||
|
*/ |
||||||
|
public interface Optimization { |
||||||
|
|
||||||
|
/** |
||||||
|
* Perform the optimization. |
||||||
|
* |
||||||
|
* @param state |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
void transform(MethodState state) throws Exception; |
||||||
|
|
||||||
|
/** |
||||||
|
* Print a trace message. Called before #preDebugMessage(). |
||||||
|
* |
||||||
|
* @param dateString |
||||||
|
* The current timestamp. |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
String traceMessage(String dateString); |
||||||
|
|
||||||
|
/** |
||||||
|
* Print a debugging message. Called before #transform(). |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
String preDebugMessage(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Print a debugging message. Called after #transform(). |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
String postDebugMessage(); |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Contains a program that optimizes Java classes.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* Class: ClassFormatException |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.reflect; |
||||||
|
|
||||||
|
public class ClassFormatException extends RuntimeException { |
||||||
|
// serialVersionUID is strongly recommended for all classes implementing
|
||||||
|
// Serializable
|
||||||
|
public static final long serialVersionUID = 1L; |
||||||
|
|
||||||
|
public ClassFormatException(String msg) { |
||||||
|
super(msg); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
ClassFormatException.class\
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,14 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
|
||||||
|
<p>Provides an abstract API for working with Java classfiles. In this |
||||||
|
package, names and types are represent by indices into the constant |
||||||
|
pool. Modifier flags, the constant pool, exception handlers, and |
||||||
|
debugging information are also modeled directly in this package. The |
||||||
|
classes and interfaces in this package exist to give an opaque and |
||||||
|
abstract view of the underlying representation of the Java class.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* Class: ComponentVisitor |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.ssa; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* ComponentVisitor is used to visit the strongly connected components (SSC) of |
||||||
|
* a control flow graph. |
||||||
|
* |
||||||
|
* @see SSAGraph |
||||||
|
*/ |
||||||
|
public abstract class ComponentVisitor { |
||||||
|
public abstract void visitComponent(List component); |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
PhiReturnStmt.class\
|
||||||
|
SSAConstructionInfo.class\
|
||||||
|
ComponentVisitor.class\
|
||||||
|
SSAGraph.class\
|
||||||
|
SSA.class
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,162 @@ |
|||||||
|
/* |
||||||
|
* Class: PhiReturnStmt |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.ssa; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Subroutine; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
|
||||||
|
/** |
||||||
|
* A PhiReturnStmt is placed at the return site of a subroutine. This is |
||||||
|
* necessary because variables that are not referrenced inside a subroutine |
||||||
|
* (finally block) retain their value. This is a problem for SSA when a variable |
||||||
|
* is assigned to inside an exception handler. At the beginning of the finally |
||||||
|
* block, there would be a merge of two occurrences of the variable (one from |
||||||
|
* the the exception handler and another from the "outside world") and a phi |
||||||
|
* function should be placed accordingly. If the type of the variable was |
||||||
|
* changed inside the exception handler, the operands of phi function would be |
||||||
|
* of different types and that would be bad. To avoid this situation |
||||||
|
* PhiReturnStmt are placed before the next instruction to be executed after the |
||||||
|
* subroutine has returned. Note that each PhiReturnStmt has only one operand |
||||||
|
* that is the same variable as its target. The two variables will have |
||||||
|
* different version numbers, however. |
||||||
|
* <p> |
||||||
|
* The following diagram demonstrates PhiReturnStmt: |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* a1 = 1 a2 = 2 |
||||||
|
* b1 = 1 b2 = 2 |
||||||
|
* jsr jsr |
||||||
|
* \ / |
||||||
|
* \ / |
||||||
|
* \ / |
||||||
|
* * |
||||||
|
* a3 = PhiJoinStmt(a1, a2) |
||||||
|
* b3 = PhiJoinStmt(b1, b2) |
||||||
|
* | |
||||||
|
* b4 = 4 // b is defined in subrountine
|
||||||
|
* | |
||||||
|
* ret |
||||||
|
* * |
||||||
|
* / \ |
||||||
|
* / \ |
||||||
|
* / \ |
||||||
|
* / \ |
||||||
|
* a4 = PhiReturnStmt(a3) a5 = PhiReturnStmt(a3) |
||||||
|
* b5 = PhiReturnStmt(b4) b6 = PhiReturnStmt(b4) |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* After transformation, the PhiReturnStmts will become |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* a1 a2 |
||||||
|
* b4 b4 |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* The variable <tt>a</tt> is not modified in the subroutine, so it retains |
||||||
|
* its value from before the jsr. The variable <tt>b</tt> is modified in the |
||||||
|
* subroutine, so its value after the ret is the value it was assigned in the |
||||||
|
* subroutine. |
||||||
|
*/ |
||||||
|
class PhiReturnStmt extends PhiStmt { |
||||||
|
final Subroutine sub; |
||||||
|
|
||||||
|
final Expr operand; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param target |
||||||
|
* Local variable to which the result of this phi statement is to |
||||||
|
* be assigned. |
||||||
|
* @param sub |
||||||
|
* The subroutine from which we are returning. |
||||||
|
*/ |
||||||
|
public PhiReturnStmt(VarExpr target, Subroutine sub) { |
||||||
|
super(target); |
||||||
|
this.sub = sub; |
||||||
|
this.operand = (VarExpr) target.clone(); |
||||||
|
operand.setParent(this); |
||||||
|
operand.setDef(null); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
operand.visit(visitor); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitChildren(visitor); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the subroutine associated with this <tt>PhiReturnStmt</tt>. |
||||||
|
*/ |
||||||
|
public Subroutine sub() { |
||||||
|
return sub; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a collection containing the operands to the phi statement. In |
||||||
|
* this case the collection contains the one operand. |
||||||
|
*/ |
||||||
|
public Collection operands() { |
||||||
|
ArrayList v = new ArrayList(); |
||||||
|
v.add(operand); |
||||||
|
return v; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the operand of this <tt>PhiReturnStmt</tt> statement. A |
||||||
|
* <tt>PhiReturnStmt</tt> has only one operand because the block that |
||||||
|
* begins an exception handler may have only one incoming edge (critical |
||||||
|
* edges were split). |
||||||
|
*/ |
||||||
|
public Expr operand() { |
||||||
|
return operand; |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return "" + target() + " := Phi-Return(" + operand + ", " + sub + ")"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,594 @@ |
|||||||
|
/* |
||||||
|
* Class: SSA |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.ssa; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.cfg.Handler; |
||||||
|
import edu.purdue.cs.bloat.cfg.Subroutine; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.tree.DefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiJoinStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StackExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Stmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Compute the SSA form of the control flow graph and build FUD chains. |
||||||
|
* <p> |
||||||
|
* The SSA algorithm is from: |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* R. Cytron, J. Ferrante J, B. K. Rosen, M. N. Wegman, and F. K. Zadeck, |
||||||
|
* "Efficiently Computing Static Single Assignment Form and the Control |
||||||
|
* Dependence Graph", TOPLAS, 13(4): 451-490, October 1991. |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* I made modifications to the algorithm to compute FUD chains and to run the |
||||||
|
* algorithm separately for each variable similar to the SSAPRE algorithm. |
||||||
|
* Making a separate pass for each variable allows variables to be added |
||||||
|
* incrementally. |
||||||
|
*/ |
||||||
|
public class SSA implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
transform(state.controlFlowGraph()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Transforms a control flow graph into Single Static Assignment (SSA) form. |
||||||
|
* First, the CFG is traversed and a list of all variables (both local and |
||||||
|
* stack) eligible for SSA renaming is compiled. Variables are represented |
||||||
|
* by instances of <tt>SSAConstructionInfo</tt>. Each of these variables |
||||||
|
* is then transformed. |
||||||
|
* |
||||||
|
* @see #transform |
||||||
|
* @see SSAConstructionInfo |
||||||
|
*/ |
||||||
|
private void transform(FlowGraph cfg) { |
||||||
|
Iterator e = collectVars(cfg); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
SSAConstructionInfo info = (SSAConstructionInfo) e.next(); |
||||||
|
transform(cfg, info); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs the actions necessary to convert a CFG into SSA form with |
||||||
|
* respect to one variable. The variable's information is stored in the |
||||||
|
* <tt>SSAConstructionInfo</tt>. |
||||||
|
*/ |
||||||
|
public void transform(FlowGraph cfg, SSAConstructionInfo info) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("transforming " + info.prototype + " (" |
||||||
|
+ info.prototype.type() + ")"); |
||||||
|
} |
||||||
|
|
||||||
|
placePhiFunctions(cfg, info); |
||||||
|
rename(cfg, info); |
||||||
|
insertCode(cfg, info); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Visits the nodes in a control flow graph and constructs |
||||||
|
* <tt>SSAConstructionInfo</tt> objects for each variable in the CFG. |
||||||
|
* Returns the <tt>SSAConstructionInfo</tt>s for the variables in the |
||||||
|
* CFG. |
||||||
|
*/ |
||||||
|
private Iterator collectVars(final FlowGraph cfg) { |
||||||
|
// SSAConstructionInfo objects for cfg
|
||||||
|
final Map infos = new LinkedHashMap(); |
||||||
|
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
// Visit all statements in the CFG. Remove any pre-existing
|
||||||
|
// PhiStmts.
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
Iterator iter = tree.stmts().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Stmt stmt = (Stmt) iter.next(); |
||||||
|
|
||||||
|
if (stmt instanceof PhiStmt) { |
||||||
|
iter.remove(); |
||||||
|
|
||||||
|
} else { |
||||||
|
stmt.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Recall that VarExprs represent variables. If we have not
|
||||||
|
// already created a SSAConstructionInfo for a variable
|
||||||
|
// (VarExpr), do so. Make note of the fact that this is a real
|
||||||
|
// occurrence of the variable.
|
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
|
||||||
|
expr.setDef(null); |
||||||
|
|
||||||
|
Object key = expr.comparator(); |
||||||
|
|
||||||
|
SSAConstructionInfo info = (SSAConstructionInfo) infos.get(key); |
||||||
|
|
||||||
|
if (info == null) { |
||||||
|
info = new SSAConstructionInfo(cfg, expr); |
||||||
|
infos.put(key, info); |
||||||
|
} |
||||||
|
|
||||||
|
info.addReal(expr); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return infos.values().iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Places phi statements at the appropriate locations in the CFG. This |
||||||
|
* implementation only places phi functions for variables that are live on |
||||||
|
* entry to at least one block. That is, if a variable is only used within |
||||||
|
* one block, we don't bother searching for a place to put phi functions for |
||||||
|
* it. |
||||||
|
* |
||||||
|
* @param cfg |
||||||
|
* The CFG in which phi functions are placed. |
||||||
|
* @param info |
||||||
|
* The variable for which phi functions will be placed. |
||||||
|
*/ |
||||||
|
private void placePhiFunctions(FlowGraph cfg, SSAConstructionInfo info) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Placing phi-functions for " + info); |
||||||
|
} |
||||||
|
|
||||||
|
// Phis are only placed for variables which are live on entry to
|
||||||
|
// at least one block.
|
||||||
|
//
|
||||||
|
// This is the semi-pruned form described in "Practical
|
||||||
|
// Improvements to the Construction and Destruction of Static
|
||||||
|
// Single Assignment Form" by Briggs, Cooper, Harvey, Simpson
|
||||||
|
//
|
||||||
|
|
||||||
|
// Blocks in which the variable in the SSAConstructionInfo is
|
||||||
|
// defined. That is, variables that are defined in this block.
|
||||||
|
BitSet killed = new BitSet(cfg.size()); |
||||||
|
|
||||||
|
// Is the variable used in more than one block?
|
||||||
|
boolean nonLocal = false; |
||||||
|
|
||||||
|
Iterator reals = info.reals().iterator(); |
||||||
|
|
||||||
|
// Look at all real (not in phi statement) occurrences of the
|
||||||
|
// variable in the SSAConstructionInfo. Determine which variables
|
||||||
|
// are live on entry to some basic block (i.e. "non-local"). If
|
||||||
|
// a variable is not live on entry to some basic block, it is only
|
||||||
|
// used within the block in which it is defined, so don't bother
|
||||||
|
// adding a phi statement for it.
|
||||||
|
while (reals.hasNext()) { |
||||||
|
VarExpr real = (VarExpr) reals.next(); |
||||||
|
|
||||||
|
Block block = real.block(); // Block in which variable occurs
|
||||||
|
|
||||||
|
if (real.isDef()) { |
||||||
|
killed.set(cfg.preOrderIndex(block)); |
||||||
|
|
||||||
|
} else if (!killed.get(cfg.preOrderIndex(block))) { |
||||||
|
// There is a use of the variable as an operand that is not
|
||||||
|
// defined in the block in which it occurs. Therefore, the
|
||||||
|
// variable is non-local.
|
||||||
|
nonLocal = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!nonLocal) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// We've decided that this variable is used in multiple blocks,
|
||||||
|
// so go ahead and place phi functions for it.
|
||||||
|
|
||||||
|
// Iterate over all of the catch blocks (blocks that begin an
|
||||||
|
// exception handler) in the CFG and instert PhiCatchStmts where
|
||||||
|
// appropriate.
|
||||||
|
Iterator catchBlocks = cfg.catchBlocks().iterator(); |
||||||
|
|
||||||
|
while (catchBlocks.hasNext()) { |
||||||
|
Block block = (Block) catchBlocks.next(); |
||||||
|
info.addCatchPhi(block); |
||||||
|
info.addDefBlock(block); |
||||||
|
} |
||||||
|
|
||||||
|
// Iterate over all of the subroutines (finally blocks) and insert
|
||||||
|
// PhiReturnStmts where appropriate.
|
||||||
|
Iterator subs = cfg.subroutines().iterator(); |
||||||
|
|
||||||
|
while (subs.hasNext()) { |
||||||
|
Subroutine sub = (Subroutine) subs.next(); |
||||||
|
info.addRetPhis(sub); |
||||||
|
|
||||||
|
Iterator paths = sub.paths().iterator(); |
||||||
|
|
||||||
|
while (paths.hasNext()) { |
||||||
|
Block[] path = (Block[]) paths.next(); |
||||||
|
info.addDefBlock(path[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Now we add real phi functions to the CFG. Phi functions are
|
||||||
|
// placed at the (blocks in the) iterated dominance fontier of each
|
||||||
|
// of the blocks containing a definition of the variable.
|
||||||
|
Iterator df = cfg.iteratedDomFrontier(info.defBlocks()).iterator(); |
||||||
|
|
||||||
|
while (df.hasNext()) { |
||||||
|
Block block = (Block) df.next(); |
||||||
|
|
||||||
|
// Don't place phi-statements in the exit block because one of
|
||||||
|
// the operands will always have a null definition.
|
||||||
|
if (block != cfg.sink()) |
||||||
|
info.addPhi(block); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If the block resides in a protected region and there is a |
||||||
|
* <tt>PhiCatchStmt</tt> for the variable in question in the handler of |
||||||
|
* the exception thrown by the protected region (meaning that the variable |
||||||
|
* is used in the protected region), the variable becomes an operand to the |
||||||
|
* <tt>PhiCatchStmt</tt>. |
||||||
|
* |
||||||
|
* @param info |
||||||
|
* The variable (LocalExpr) that we're dealing with |
||||||
|
* @param block |
||||||
|
* The block in a potentially protected region. If the block is |
||||||
|
* indeed in a protected region, the occurrence of the the |
||||||
|
* variable represented by info becomes an operand to the |
||||||
|
* PhiCatchStmt at the beginning of the protected region's |
||||||
|
* handler. |
||||||
|
* @param def |
||||||
|
* The defining occurrence of the variable stored in info. |
||||||
|
*/ |
||||||
|
private void addCatchPhiOperands(SSAConstructionInfo info, Block block, |
||||||
|
LocalExpr def) { |
||||||
|
Iterator handlers = block.graph().handlers().iterator(); |
||||||
|
|
||||||
|
// Iterate over all of the exception handlers in the CFG. If
|
||||||
|
// the block we are dealing with is a protected block (that is,
|
||||||
|
// is inside a try block), then the variable represented by info
|
||||||
|
// becomes an operand to the PhiCatchStmt residing at the
|
||||||
|
// beginning of the protected block's handler.
|
||||||
|
while (handlers.hasNext()) { |
||||||
|
Handler handler = (Handler) handlers.next(); |
||||||
|
|
||||||
|
if (handler.protectedBlocks().contains(block)) { |
||||||
|
PhiCatchStmt phi = (PhiCatchStmt) info.phiAtBlock(handler |
||||||
|
.catchBlock()); |
||||||
|
|
||||||
|
if (phi != null && !phi.hasOperandDef(def)) { |
||||||
|
LocalExpr operand = (LocalExpr) info.prototype.clone(); |
||||||
|
operand.setDef(def); // ???
|
||||||
|
phi.addOperand(operand); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The actual renamining is done by the search method. This method just |
||||||
|
* takes care of <Tt>PhiReturnStmts</tt>. |
||||||
|
*/ |
||||||
|
private void rename(FlowGraph cfg, SSAConstructionInfo info) { |
||||||
|
search(cfg, info, null, cfg.source()); |
||||||
|
|
||||||
|
// Eliminate PhiReturns by replacing their uses with the defs live
|
||||||
|
// at the end of the returning sub or live on the same path on entry
|
||||||
|
// to the sub (if the variable did not occur in the subroutine).
|
||||||
|
|
||||||
|
// Examine each PhiReturnStmt in the CFG. Recall that
|
||||||
|
// PhiReturnStmts are "inserted" at blocks that begin exceptions
|
||||||
|
boolean changed = true; |
||||||
|
|
||||||
|
while (changed) { |
||||||
|
changed = false; |
||||||
|
|
||||||
|
Iterator subs = cfg.subroutines().iterator(); |
||||||
|
|
||||||
|
while (subs.hasNext()) { |
||||||
|
Subroutine sub = (Subroutine) subs.next(); |
||||||
|
Iterator paths = sub.paths().iterator(); |
||||||
|
|
||||||
|
PhiJoinStmt entry = (PhiJoinStmt) info.phiAtBlock(sub.entry()); |
||||||
|
|
||||||
|
if (entry == null) { |
||||||
|
// If there was no PhiJoinStmt for the variable in the
|
||||||
|
// subroutine, who cares? We don't.
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
while (paths.hasNext()) { |
||||||
|
Block[] path = (Block[]) paths.next(); |
||||||
|
|
||||||
|
PhiReturnStmt ret = (PhiReturnStmt) info |
||||||
|
.phiAtBlock(path[1]); |
||||||
|
|
||||||
|
if (ret != null) { |
||||||
|
DefExpr def = ret.operand().def(); |
||||||
|
|
||||||
|
if (def != entry.target()) { |
||||||
|
// If the operand of the PhiReturnStmt is
|
||||||
|
// different from
|
||||||
|
// the new SSA variable defined by the
|
||||||
|
// PhiCatchStmt at
|
||||||
|
// the beginning of the subroutine, then the
|
||||||
|
// variable
|
||||||
|
// was defined in the subroutine, so the operand
|
||||||
|
// to the
|
||||||
|
// PhiReturnStmt is the correct SSA variable.
|
||||||
|
// This is
|
||||||
|
// like the variable "b" in figure 3.5 in Nate's
|
||||||
|
// Thesis.
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Replace all uses of the target of the PhiReturnStmt
|
||||||
|
// with the SSA variable corresponding to the block in
|
||||||
|
// which the jsr occured. This is like variable "a" in
|
||||||
|
// figure 3.5 in Nate's Thesis.
|
||||||
|
def = ((VarExpr) entry.operandAt(path[0])).def(); |
||||||
|
|
||||||
|
Iterator uses = ret.target().uses().iterator(); |
||||||
|
|
||||||
|
while (uses.hasNext()) { |
||||||
|
VarExpr use = (VarExpr) uses.next(); |
||||||
|
use.setDef(def); |
||||||
|
} |
||||||
|
|
||||||
|
// The PhiReturnStmt is no longer needed
|
||||||
|
info.removePhiAtBlock(path[1]); |
||||||
|
changed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Iterator subs = cfg.subroutines().iterator(); |
||||||
|
|
||||||
|
// Examine any remaining PhiReturnStmts. Replace all uses of the
|
||||||
|
// target of the PhiReturnStmt with its operand.
|
||||||
|
while (subs.hasNext()) { |
||||||
|
Subroutine sub = (Subroutine) subs.next(); |
||||||
|
|
||||||
|
Iterator paths = sub.paths().iterator(); |
||||||
|
|
||||||
|
while (paths.hasNext()) { |
||||||
|
Block[] path = (Block[]) paths.next(); |
||||||
|
|
||||||
|
PhiReturnStmt ret = (PhiReturnStmt) info.phiAtBlock(path[1]); |
||||||
|
|
||||||
|
if (ret != null) { |
||||||
|
DefExpr def = ret.operand().def(); |
||||||
|
|
||||||
|
Iterator uses = ret.target().uses().iterator(); |
||||||
|
|
||||||
|
while (uses.hasNext()) { |
||||||
|
VarExpr use = (VarExpr) uses.next(); |
||||||
|
use.setDef(def); |
||||||
|
} |
||||||
|
|
||||||
|
info.removePhiAtBlock(path[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Does the actual renaming. It keeps track of the most recent occurrence of |
||||||
|
* an (SSA numbered) variable and recalculates the definitions of variables |
||||||
|
* appropriately. |
||||||
|
* |
||||||
|
* @param info |
||||||
|
* SSAConstructionInfo representing the variable being converted |
||||||
|
* into SSA form. |
||||||
|
* @param top |
||||||
|
* "Top" of the variable stack for the variable in question. Each |
||||||
|
* variable has a "stack" associated with it. The top of the |
||||||
|
* stack contains the current SSA name of the variable. It can |
||||||
|
* also be thought of as the "most recent definition" of the |
||||||
|
* variable. |
||||||
|
* @param block |
||||||
|
* Basic block in which the variable is being renamed. |
||||||
|
*/ |
||||||
|
private void search(FlowGraph cfg, SSAConstructionInfo info, VarExpr top, |
||||||
|
Block block) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("renaming " + info.prototype + " in " + block); |
||||||
|
} |
||||||
|
|
||||||
|
// If appropriate, add top as an operand of a PhiCatchStmt
|
||||||
|
if (top instanceof LocalExpr) { |
||||||
|
addCatchPhiOperands(info, block, (LocalExpr) top); |
||||||
|
} |
||||||
|
|
||||||
|
// First handle any phi in the block.
|
||||||
|
PhiStmt phi = info.phiAtBlock(block); |
||||||
|
|
||||||
|
if (phi != null) { |
||||||
|
top = phi.target(); |
||||||
|
|
||||||
|
if (top instanceof LocalExpr) { |
||||||
|
addCatchPhiOperands(info, block, (LocalExpr) top); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the block in which the variable is being renamed begins an
|
||||||
|
// exception handler and we're dealing with a stack variable, then
|
||||||
|
// there is no most recent definition of the variable because the
|
||||||
|
// stack is cleared when an exception is handled. I dunno.
|
||||||
|
if (cfg.catchBlocks().contains(block) |
||||||
|
&& info.prototype instanceof StackExpr) { |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(" Killing TOS at " + block); |
||||||
|
} |
||||||
|
|
||||||
|
// The operand stack is popped down to 0 at catch blocks.
|
||||||
|
top = null; |
||||||
|
} |
||||||
|
|
||||||
|
Iterator e = info.realsAtBlock(block).iterator(); |
||||||
|
|
||||||
|
// Examine each occurrence of the variable in the block of
|
||||||
|
// interest. When we encounter a definition of the variable, make
|
||||||
|
// that definition to the most recent SSA variable (top). For
|
||||||
|
// each use, make this most recent SSA variable be its defining
|
||||||
|
// expression.
|
||||||
|
while (e.hasNext()) { |
||||||
|
VarExpr real = (VarExpr) e.next(); |
||||||
|
|
||||||
|
if (real.isDef()) { |
||||||
|
real.setDef(null); |
||||||
|
|
||||||
|
top = real; // A definition means a new SSA variable
|
||||||
|
|
||||||
|
if (top instanceof LocalExpr) { |
||||||
|
addCatchPhiOperands(info, block, (LocalExpr) top); |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(" TOS = " + top); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// Make sure that the variable is defined somewhere else
|
||||||
|
// (somewhere that we have already seen).
|
||||||
|
Assert.isTrue(top != null, "Null def for " + real); |
||||||
|
real.setDef(top); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Iterator succs = cfg.succs(block).iterator(); |
||||||
|
|
||||||
|
// Examine all successors of the block in question. If the
|
||||||
|
// successor contains a PhiJoinStmt for the variable, then set the
|
||||||
|
// operand corresponding to the block to be defined by the most
|
||||||
|
// recent SSA variable. Similarly for a PhiReturnStmt.
|
||||||
|
while (succs.hasNext()) { |
||||||
|
Block succ = (Block) succs.next(); |
||||||
|
|
||||||
|
PhiStmt succPhi = info.phiAtBlock(succ); |
||||||
|
|
||||||
|
if (succPhi instanceof PhiJoinStmt) { |
||||||
|
PhiJoinStmt f = (PhiJoinStmt) succPhi; |
||||||
|
VarExpr operand = (VarExpr) f.operandAt(block); |
||||||
|
operand.setDef(top); |
||||||
|
|
||||||
|
} else if (succPhi instanceof PhiReturnStmt) { |
||||||
|
PhiReturnStmt f = (PhiReturnStmt) succPhi; |
||||||
|
VarExpr operand = (VarExpr) f.operand(); |
||||||
|
operand.setDef(top); |
||||||
|
} |
||||||
|
|
||||||
|
// Adjust the operands of any PhiCatchStmts if the sucessor node
|
||||||
|
// is protected.
|
||||||
|
if (top instanceof LocalExpr) { |
||||||
|
addCatchPhiOperands(info, succ, (LocalExpr) top); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Iterator children = cfg.domChildren(block).iterator(); |
||||||
|
|
||||||
|
// Visit the children in the dominator tree. Keep the same most
|
||||||
|
// recent SSA variable (top).
|
||||||
|
while (children.hasNext()) { |
||||||
|
Block child = (Block) children.next(); |
||||||
|
search(cfg, info, top, child); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Iterates over the blocks in the CFG and inserts the phi statement |
||||||
|
* associated with that block. Up until this point, the phi statement is |
||||||
|
* only maintained in SSAConstructionInfo. Note that the phi statement |
||||||
|
* cannot be a return phi. |
||||||
|
* |
||||||
|
* @param cfg |
||||||
|
* The CFG into which to insert phi statements. |
||||||
|
* @param info |
||||||
|
* Represents the variable whose phi statements we are inserting. |
||||||
|
* |
||||||
|
* @see PhiReturnStmt |
||||||
|
*/ |
||||||
|
private void insertCode(FlowGraph cfg, SSAConstructionInfo info) { |
||||||
|
Iterator blocks = cfg.nodes().iterator(); |
||||||
|
|
||||||
|
while (blocks.hasNext()) { |
||||||
|
Block block = (Block) blocks.next(); |
||||||
|
|
||||||
|
PhiStmt phi = info.phiAtBlock(block); |
||||||
|
|
||||||
|
if (phi != null) { |
||||||
|
Assert.isFalse(phi instanceof PhiReturnStmt); |
||||||
|
block.tree().prependStmt(phi); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Transforming to SSA: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,296 @@ |
|||||||
|
/* |
||||||
|
* Class: SSAConstructionInfo |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.ssa; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.cfg.Subroutine; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiJoinStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>SSAConstructionInfo</tt> contains information needed to convert a CFG |
||||||
|
* into SSA form. Each variable (VarExpr) has an SSAConstructionInfo associated |
||||||
|
* with it. Each <tt>SSAConstructionInfo</tt> keeps track of information such |
||||||
|
* as the <tt>PhiStmt</tt>s that define copies of the variable, the |
||||||
|
* <tt>Block</tt>s in which the variable is defined, and the occurrences |
||||||
|
* (uses) of the variable in both phi and non-phi statements. Note that no |
||||||
|
* <tt>PhiStmt</tt> is really inserted into a basic block. We just keep track |
||||||
|
* of the mapping. It should also be noted that once a phi statement for a given |
||||||
|
* variable is "inserted" into a block, no other phi statement for that variable |
||||||
|
* is inserted. Thus, the order of insertion determines the precedence of the |
||||||
|
* phi statements: <tt>PhiReturnStmt</tt> > <tt>PhiCatchStmt</tt> > |
||||||
|
* <tt>PhiJoinStmt</tt>. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Additionally, <tt>SSAConstruction</tt> has methods to insert various |
||||||
|
* flavors of <tt>PhiStmt</tt>s whose targets are the variable associated |
||||||
|
* with the <tt>SSAConstruction</tt> into <tt>Block</tt>s. |
||||||
|
* |
||||||
|
* @see SSA |
||||||
|
* @see PhiStmt |
||||||
|
* @see PhiCatchStmt |
||||||
|
* @see PhiJoinStmt |
||||||
|
* @see PhiReturnStmt |
||||||
|
*/ |
||||||
|
public class SSAConstructionInfo { |
||||||
|
FlowGraph cfg; // The cfg we're converting into SSA form
|
||||||
|
|
||||||
|
VarExpr prototype; // The variable we're converting into SSA form
|
||||||
|
|
||||||
|
LinkedList[] reals; // The real (non-phi) occurrences associated
|
||||||
|
|
||||||
|
// with a given node (block)
|
||||||
|
LinkedList allReals; // All the real occurrences of the variable
|
||||||
|
|
||||||
|
PhiStmt[] phis; // Phi statement associated with a given block
|
||||||
|
|
||||||
|
Set defBlocks; // Blocks in which variable is defined
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param cfg |
||||||
|
* The control flow graph that is being converted to SSA form. |
||||||
|
* @param expr |
||||||
|
* A variable in the CFG on which SSA analysis is being done. |
||||||
|
*/ |
||||||
|
public SSAConstructionInfo(FlowGraph cfg, VarExpr expr) { |
||||||
|
this.cfg = cfg; |
||||||
|
|
||||||
|
prototype = (VarExpr) expr.clone(); |
||||||
|
prototype.setDef(null); |
||||||
|
|
||||||
|
reals = new LinkedList[cfg.size()]; |
||||||
|
allReals = new LinkedList(); |
||||||
|
|
||||||
|
defBlocks = new LinkedHashSet(); |
||||||
|
|
||||||
|
phis = new PhiStmt[cfg.size()]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the program variable associated with this |
||||||
|
* <tt>SSAConstructionInfo</tt>. |
||||||
|
*/ |
||||||
|
public VarExpr prototype() { |
||||||
|
return prototype; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Makes note of a <tt>Block</tt> in which the variable is defined by a |
||||||
|
* <tt>PhiStmt</tt>. |
||||||
|
*/ |
||||||
|
public void addDefBlock(Block block) { |
||||||
|
defBlocks.add(block); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the phi statement for the variable represented by this |
||||||
|
* SSAConstructionInfo at a given block in the CFG. |
||||||
|
*/ |
||||||
|
public PhiStmt phiAtBlock(Block block) { |
||||||
|
return phis[cfg.preOrderIndex(block)]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes the phi statement for this variable at a given block. |
||||||
|
*/ |
||||||
|
public void removePhiAtBlock(Block block) { |
||||||
|
PhiStmt phi = phis[cfg.preOrderIndex(block)]; |
||||||
|
|
||||||
|
if (phi != null) { |
||||||
|
if (SSA.DEBUG) { |
||||||
|
System.out.println(" removing " + phi + " at " + block); |
||||||
|
} |
||||||
|
|
||||||
|
phi.cleanup(); |
||||||
|
phis[cfg.preOrderIndex(block)] = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a <tt>PhiJoinStmt</tt> for the variable represented by this |
||||||
|
* <tt>SSAConstructionInfo</tt> to a given <tt>Block</tt>. |
||||||
|
*/ |
||||||
|
public void addPhi(Block block) { |
||||||
|
if (phis[cfg.preOrderIndex(block)] != null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
VarExpr target = (VarExpr) prototype.clone(); |
||||||
|
|
||||||
|
PhiJoinStmt phi = new PhiJoinStmt(target, block); |
||||||
|
phis[cfg.preOrderIndex(block)] = phi; |
||||||
|
|
||||||
|
if (SSA.DEBUG) { |
||||||
|
System.out.println(" place " + phi + " in " + block); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a <tt>PhiReturnStmt</tt> to all of the <tt>Block</tt>s that are |
||||||
|
* executed upon returning from a given <tt>Subroutine</tt>. |
||||||
|
* |
||||||
|
* @see PhiReturnStmt |
||||||
|
* @see Subroutine#paths |
||||||
|
*/ |
||||||
|
public void addRetPhis(Subroutine sub) { |
||||||
|
Iterator paths = sub.paths().iterator(); |
||||||
|
|
||||||
|
while (paths.hasNext()) { |
||||||
|
Block[] path = (Block[]) paths.next(); |
||||||
|
addRetPhi(sub, path[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Inserts a <tt>PhiCatchStmt</tt> (whose target is the variable |
||||||
|
* represented by this <tt>SSAConstructionInfo</tt>) into a given |
||||||
|
* <tt>Block</tt>. |
||||||
|
* |
||||||
|
* @see PhiCatchStmt |
||||||
|
*/ |
||||||
|
public void addCatchPhi(Block block) { |
||||||
|
if (phis[cfg.preOrderIndex(block)] != null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (prototype instanceof LocalExpr) { |
||||||
|
LocalExpr target = (LocalExpr) prototype.clone(); |
||||||
|
|
||||||
|
PhiCatchStmt phi = new PhiCatchStmt(target); |
||||||
|
phis[cfg.preOrderIndex(block)] = phi; |
||||||
|
|
||||||
|
if (SSA.DEBUG) { |
||||||
|
System.out.println(" place " + phi + " in " + block); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a <tt>PhiReturnStmt</tt> associated with a given |
||||||
|
* <tt>Subroutine</tt>. The <tt>PhiReturnStmt</tt> is placed in a given |
||||||
|
* block. |
||||||
|
* |
||||||
|
* @see PhiReturnStmt |
||||||
|
*/ |
||||||
|
private void addRetPhi(Subroutine sub, Block block) { |
||||||
|
if (phis[cfg.preOrderIndex(block)] != null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
VarExpr target = (VarExpr) prototype.clone(); |
||||||
|
|
||||||
|
PhiReturnStmt phi = new PhiReturnStmt(target, sub); |
||||||
|
phis[cfg.preOrderIndex(block)] = phi; |
||||||
|
|
||||||
|
if (SSA.DEBUG) { |
||||||
|
System.out.println(" place " + phi + " in " + block); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notes a real occurrence (that is, a use that is not an operand to a phi |
||||||
|
* statement) of the variable represented by this |
||||||
|
* <tt>SSAConstructionInfo</tt>. |
||||||
|
* |
||||||
|
* @see PhiStmt |
||||||
|
*/ |
||||||
|
public void addReal(VarExpr real) { |
||||||
|
if (real.stmt() instanceof PhiStmt) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
Block block = real.block(); |
||||||
|
|
||||||
|
if (real.isDef()) { |
||||||
|
defBlocks.add(block); |
||||||
|
} |
||||||
|
|
||||||
|
Assert.isTrue(block != null, real + " not in a " + block); |
||||||
|
|
||||||
|
LinkedList l = reals[cfg.preOrderIndex(block)]; |
||||||
|
|
||||||
|
if (l == null) { |
||||||
|
l = new LinkedList(); |
||||||
|
reals[cfg.preOrderIndex(block)] = l; |
||||||
|
} |
||||||
|
|
||||||
|
l.add(real); |
||||||
|
allReals.add(real); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all of the real occurrences of this variable. |
||||||
|
*/ |
||||||
|
public Collection reals() { |
||||||
|
return allReals; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all of the real occurrences of this variable in a given block. |
||||||
|
*/ |
||||||
|
public Collection realsAtBlock(Block block) { |
||||||
|
LinkedList l = reals[cfg.preOrderIndex(block)]; |
||||||
|
|
||||||
|
if (l == null) { |
||||||
|
l = new LinkedList(); |
||||||
|
reals[cfg.preOrderIndex(block)] = l; |
||||||
|
} |
||||||
|
|
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the Blocks containing a definition of the variable represented by |
||||||
|
* this SSAConstruction info. |
||||||
|
*/ |
||||||
|
public Collection defBlocks() { |
||||||
|
return defBlocks; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,731 @@ |
|||||||
|
/* |
||||||
|
* Class: SSAGraph |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.ssa; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import java.io.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.tree.CheckExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StackExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackManipStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* The SSA graph (also called the value graph) represents the nesting of |
||||||
|
* expression in a control flow graph. Each node in the SSA graph represents an |
||||||
|
* expression. If the expression is a definition, the it is labeled with the |
||||||
|
* variable it defines. Each node has directed edges to the nodes representing |
||||||
|
* its operands. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* <tt>SSAGraph</tt> is a representation of the definitions found in a CFG in |
||||||
|
* the following form: Each node in the graph is an expression that defines a |
||||||
|
* variable (a <tt>VarExpr</tt>, <tt>PhiStmt</tt>, or a |
||||||
|
* <tt>StackManipStmt</tt>). Edges in the graph point to the nodes whose |
||||||
|
* expressions define the operands of the expression in the source node. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* This class is used primarily get the strongly connected components of the SSA |
||||||
|
* graph in support of value numbering and induction variable analysis. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Nate warns: Do not modify the CFG while using the SSA graph! The effects of |
||||||
|
* such modification are undefined and will probably lead to nasty things |
||||||
|
* occuring. |
||||||
|
* |
||||||
|
* @see edu.purdue.cs.bloat.trans.ValueNumbering ValueNumbering |
||||||
|
*/ |
||||||
|
public class SSAGraph { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
FlowGraph cfg; |
||||||
|
|
||||||
|
LinkedHashMap equiv; // A mapping between a Node and all its equivalent
|
||||||
|
// Nodes
|
||||||
|
|
||||||
|
/** |
||||||
|
* Grumble. |
||||||
|
*/ |
||||||
|
public SSAGraph(FlowGraph cfg, boolean useless) { |
||||||
|
this(cfg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Traverse the control flow graph and determines which Nodes |
||||||
|
* are of an equivalent Type. |
||||||
|
* |
||||||
|
* @param cfg |
||||||
|
* The control flow graph to examine |
||||||
|
*/ |
||||||
|
public SSAGraph(FlowGraph cfg) { |
||||||
|
this.cfg = cfg; |
||||||
|
this.equiv = new LinkedHashMap(); |
||||||
|
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
// The CheckExpr and the Expr is checks are equivalent.
|
||||||
|
public void visitCheckExpr(CheckExpr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
makeEquiv(expr, expr.expr()); |
||||||
|
} |
||||||
|
|
||||||
|
// The target of the PhiStmt and the PhiStmt are equivalent
|
||||||
|
public void visitPhiStmt(PhiStmt stmt) { |
||||||
|
stmt.visitChildren(this); |
||||||
|
makeEquiv(stmt.target(), stmt); |
||||||
|
} |
||||||
|
|
||||||
|
// The use of a variable and its defining variable are
|
||||||
|
// equivalent
|
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
if (!expr.isDef()) { |
||||||
|
VarExpr def = (VarExpr) expr.def(); |
||||||
|
|
||||||
|
if (def != null) { |
||||||
|
makeEquiv(expr, def); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// With StackManipStmts the stack slot (StackExpr) after the
|
||||||
|
// StackManipStmt is equivalent to its corresponding slot before
|
||||||
|
// the StackManipStmt.
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
StackExpr[] target = stmt.target(); |
||||||
|
StackExpr[] source = stmt.source(); |
||||||
|
|
||||||
|
switch (stmt.kind()) { |
||||||
|
case StackManipStmt.SWAP: |
||||||
|
// 0 1 -> 1 0
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 2, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0 }); |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP: |
||||||
|
// 0 -> 0 0
|
||||||
|
Assert.isTrue(source.length == 1 && target.length == 2, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 0, 0 }); |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP_X1: |
||||||
|
// 0 1 -> 1 0 1
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP_X2: |
||||||
|
if (source.length == 3) { |
||||||
|
// 0 1 2 -> 2 0 1 2
|
||||||
|
Assert.isTrue(source.length == 3 && target.length == 4, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 2, 0, 1, 2 }); |
||||||
|
} else { |
||||||
|
// 0-1 2 -> 2 0-1 2
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP2: |
||||||
|
if (source.length == 2) { |
||||||
|
// 0 1 -> 0 1 0 1
|
||||||
|
Assert.isTrue(target.length == 4, "Illegal statement: " |
||||||
|
+ stmt); |
||||||
|
manip(source, target, new int[] { 0, 1, 0, 1 }); |
||||||
|
} else { |
||||||
|
// 0-1 -> 0-1 0-1
|
||||||
|
Assert.isTrue(source.length == 1 && target.length == 2, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 0, 0 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP2_X1: |
||||||
|
if (source.length == 3) { |
||||||
|
// 0 1 2 -> 1 2 0 1 2
|
||||||
|
Assert.isTrue(target.length == 5, "Illegal statement: " |
||||||
|
+ stmt); |
||||||
|
manip(source, target, new int[] { 1, 2, 0, 1, 2 }); |
||||||
|
} else { |
||||||
|
// 0 1-2 -> 1-2 0 1-2
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP2_X2: |
||||||
|
if (source.length == 4) { |
||||||
|
// 0 1 2 3 -> 2 3 0 1 2 3
|
||||||
|
Assert.isTrue(target.length == 6, "Illegal statement: " |
||||||
|
+ stmt); |
||||||
|
manip(source, target, new int[] { 2, 3, 0, 1, 2, 3 }); |
||||||
|
} else if (source.length == 3) { |
||||||
|
if (target.length == 5) { |
||||||
|
// 0-1 2 3 -> 2 3 0-1 2 3
|
||||||
|
manip(source, target, new int[] { 1, 2, 0, 1, 2 }); |
||||||
|
} else { |
||||||
|
// 0 1 2-3 -> 2-3 0 1 2-3
|
||||||
|
Assert.isTrue(target.length == 4, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 2, 0, 1, 2 }); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// 0-1 2-3 -> 2-3 0-1 2-3
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
stmt.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
// Determines equivalence of the StackExprs invovled in a
|
||||||
|
// StackManipStmt. Recall that StackManipStmt are things like
|
||||||
|
// the dup and swap instructions. So, elements (StackExprs) of
|
||||||
|
// the "new" stack will be equivalent to elements of the "old"
|
||||||
|
// stack. The s array defines the transformation.
|
||||||
|
private void manip(StackExpr[] source, StackExpr[] target, int[] s) { |
||||||
|
for (int i = 0; i < s.length; i++) { |
||||||
|
makeEquiv(target[i], source[s[i]]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The StoreExpr is equivalent to the expression being stored.
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
makeEquiv(expr, expr.expr()); |
||||||
|
|
||||||
|
if (expr.target() instanceof VarExpr) { |
||||||
|
makeEquiv(expr.target(), expr.expr()); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the <tt>FlowGraph</tt> that this <tt>SSAGraph</tt> is built |
||||||
|
* around. |
||||||
|
*/ |
||||||
|
public FlowGraph cfg() { |
||||||
|
return (this.cfg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a set of nodes whose value is equivalent to a given node. For |
||||||
|
* example, the LHS and RHS of an assignment are equivalent. As are all |
||||||
|
* local variables with the same definition. |
||||||
|
*/ |
||||||
|
public Set equivalent(Node node) { |
||||||
|
Set s = (Set) equiv.get(node); |
||||||
|
|
||||||
|
if (s == null) { |
||||||
|
s = new LinkedHashSet(1); |
||||||
|
s.add(node); // A node is equivalent to itself
|
||||||
|
equiv.put(node, s); |
||||||
|
} |
||||||
|
|
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Makes node1 equivalent to node2 by adding the equivlance Set of node2 to |
||||||
|
* the equivalance Set of node1, and vice versa. |
||||||
|
*/ |
||||||
|
void makeEquiv(Node node1, Node node2) { |
||||||
|
Set s1 = equivalent(node1); |
||||||
|
Set s2 = equivalent(node2); |
||||||
|
|
||||||
|
if (s1 != s2) { |
||||||
|
s1.addAll(s2); |
||||||
|
|
||||||
|
Iterator iter = s2.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node n = (Node) iter.next(); |
||||||
|
equiv.put(n, s1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the children (that is, the operands) of a given Node in the SSA |
||||||
|
* Graph. |
||||||
|
*/ |
||||||
|
public List children(Node node) { |
||||||
|
final ArrayList c = new ArrayList(); |
||||||
|
|
||||||
|
if (node instanceof StoreExpr) { |
||||||
|
StoreExpr store = (StoreExpr) node; |
||||||
|
|
||||||
|
// Add the grand children of RHS. The RHS is equivalent to
|
||||||
|
// this node.
|
||||||
|
store.expr().visitChildren(new TreeVisitor() { |
||||||
|
public void visitNode(Node node) { |
||||||
|
c.add(node); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// The LHS is equivalent to this node if it is a VarExpr and not
|
||||||
|
// a child.
|
||||||
|
if (!(store.target() instanceof VarExpr)) { |
||||||
|
c.add(store.target()); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (node instanceof PhiStmt) { |
||||||
|
PhiStmt phi = (PhiStmt) node; |
||||||
|
c.addAll(phi.operands()); |
||||||
|
|
||||||
|
} else { |
||||||
|
node.visitChildren(new TreeVisitor() { |
||||||
|
public void visitNode(Node node) { |
||||||
|
c.add(node); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the Sets of Nodes whose values are equivalent. |
||||||
|
*/ |
||||||
|
public Collection equivalences() { |
||||||
|
return equiv.values(); |
||||||
|
} |
||||||
|
|
||||||
|
class Count { |
||||||
|
int value = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Calculates the strongly connected components (SCC) of the SSA graph. SSCs |
||||||
|
* are represented by a List of <tt>Node</tt>s. The SCCs are then visited |
||||||
|
* by the ComponentVistor. |
||||||
|
*/ |
||||||
|
public void visitComponents(final ComponentVisitor visitor) { |
||||||
|
// Number the nodes reverse post order (i.e. topological order).
|
||||||
|
|
||||||
|
final Count count = new Count(); |
||||||
|
|
||||||
|
final List postOrder = cfg.postOrder(); |
||||||
|
ListIterator iter = postOrder.listIterator(postOrder.size()); |
||||||
|
|
||||||
|
// Perform a depth-first ordering of the nodes in the CFG to give
|
||||||
|
// each node a unique identifier. This is accomplished by
|
||||||
|
// visiting the blocks in the CFG in post-order and numbering the
|
||||||
|
// Nodes in the block's expression Tree in depth-first order.
|
||||||
|
while (iter.hasPrevious()) { |
||||||
|
Block block = (Block) iter.previous(); |
||||||
|
|
||||||
|
block.visit(new TreeVisitor() { |
||||||
|
public void visitTree(Tree tree) { |
||||||
|
tree.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
node.visitChildren(this); |
||||||
|
node.setKey(count.value++); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// Build the (strongly connected) components and call
|
||||||
|
// visitor.visitComponent for each.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
ArrayList stack = new ArrayList(); |
||||||
|
|
||||||
|
BitSet onStack = new BitSet(count.value + 1); |
||||||
|
|
||||||
|
int[] low = new int[count.value + 1]; |
||||||
|
|
||||||
|
int[] dfs = new int[count.value + 1]; |
||||||
|
|
||||||
|
int dfsNumber = 1; |
||||||
|
|
||||||
|
Node parent; // Parent in the SSA graph
|
||||||
|
|
||||||
|
// Visit the blocks in the CFG in reverse postorder
|
||||||
|
public void visitFlowGraph(FlowGraph cfg) { |
||||||
|
ListIterator e = postOrder.listIterator(postOrder.size()); |
||||||
|
|
||||||
|
while (e.hasPrevious()) { |
||||||
|
Block block = (Block) e.previous(); |
||||||
|
block.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
parent = null; |
||||||
|
tree.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
// This method is essentially Figure 4.6 in Taylor Simpson's PhD
|
||||||
|
// Thesis: www.cs.rice.edu/~lts. The implementation is a little
|
||||||
|
// funky, though, because someone wanted to use visitors.
|
||||||
|
// Grumble.
|
||||||
|
public void visitNode(Node node) { |
||||||
|
int dfn = dfs[node.key()]; |
||||||
|
// System.out.println("visit " + node + " key=" + node.key() +
|
||||||
|
// " dfn=" + dfn);
|
||||||
|
|
||||||
|
if (dfn == 0) { |
||||||
|
// The node in question has not yet been visited. Assign
|
||||||
|
// it
|
||||||
|
// the next dfNumber and add it to the stack. Mark all
|
||||||
|
// nodes that are equivalent to the node in question as
|
||||||
|
// being visited.
|
||||||
|
|
||||||
|
dfn = dfsNumber++; |
||||||
|
low[dfn] = dfn; |
||||||
|
|
||||||
|
stack.add(node); |
||||||
|
onStack.set(dfn); |
||||||
|
|
||||||
|
Iterator equiv = equivalent(node).iterator(); |
||||||
|
|
||||||
|
while (equiv.hasNext()) { |
||||||
|
Node e = (Node) equiv.next(); |
||||||
|
dfs[e.key()] = dfn; |
||||||
|
} |
||||||
|
|
||||||
|
// Again examine each node, e, equivalent to the node in
|
||||||
|
// question. Then recursively visit the children of e in
|
||||||
|
// the SSA Graph.
|
||||||
|
Node grandParent = parent; |
||||||
|
parent = node; |
||||||
|
|
||||||
|
equiv = equivalent(node).iterator(); |
||||||
|
|
||||||
|
while (equiv.hasNext()) { |
||||||
|
Node e = (Node) equiv.next(); |
||||||
|
|
||||||
|
Iterator children = children(e).iterator(); |
||||||
|
|
||||||
|
while (children.hasNext()) { |
||||||
|
Node child = (Node) children.next(); |
||||||
|
child.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
parent = grandParent; // Restore true parent
|
||||||
|
|
||||||
|
// Now we finally get to the point where we can
|
||||||
|
// construct a
|
||||||
|
// strongly connected component. Pop all of the nodes
|
||||||
|
// off
|
||||||
|
// the stack until the node in question is reached.
|
||||||
|
if (low[dfn] == dfn) { |
||||||
|
ArrayList scc = new ArrayList(); |
||||||
|
|
||||||
|
while (!stack.isEmpty()) { |
||||||
|
Node v = (Node) stack.remove(stack.size() - 1); |
||||||
|
onStack.clear(dfs[v.key()]); |
||||||
|
scc.addAll(equivalent(v)); |
||||||
|
|
||||||
|
if (v == node) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Sort the nodes in the SCC by their reverse
|
||||||
|
// post order numbers.
|
||||||
|
Collections.sort(scc, new Comparator() { |
||||||
|
public int compare(Object a, Object b) { |
||||||
|
int ka = ((Node) a).key(); |
||||||
|
int kb = ((Node) b).key(); |
||||||
|
return ka - kb; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.print("SCC ="); |
||||||
|
|
||||||
|
Iterator e = scc.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Node v = (Node) e.next(); |
||||||
|
System.out.print(" " + v + "{" + v.key() + "}"); |
||||||
|
} |
||||||
|
|
||||||
|
System.out.println(); |
||||||
|
} |
||||||
|
|
||||||
|
// Visit the SCC with the visitor that was passed in.
|
||||||
|
visitor.visitComponent(scc); |
||||||
|
} |
||||||
|
|
||||||
|
if (parent != null) { |
||||||
|
int parentDfn = dfs[parent.key()]; |
||||||
|
low[parentDfn] = Math.min(low[parentDfn], low[dfn]); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// We've already visited the node in question
|
||||||
|
if (parent != null) { |
||||||
|
int parentDfn = dfs[parent.key()]; |
||||||
|
|
||||||
|
// (parent, node) is either a cross edge or a back edge.
|
||||||
|
if (dfn < parentDfn && onStack.get(dfn)) { |
||||||
|
low[parentDfn] = Math.min(low[parentDfn], dfn); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Visits the strongly connected component that contains a given |
||||||
|
* <tt>Node</tt>. |
||||||
|
*/ |
||||||
|
public void visitComponent(final Node startNode, |
||||||
|
final ComponentVisitor visitor) { |
||||||
|
// Number the nodes reverse post order (i.e. topological order).
|
||||||
|
|
||||||
|
final Count count = new Count(); |
||||||
|
|
||||||
|
final List postOrder = cfg.postOrder(); |
||||||
|
ListIterator iter = postOrder.listIterator(postOrder.size()); |
||||||
|
|
||||||
|
// Perform a depth-first ordering of the nodes in the CFG to give
|
||||||
|
// each node a unique identifier. This is accomplished by
|
||||||
|
// visiting the blocks in the CFG in post-order and numbering the
|
||||||
|
// Nodes in the block's expression Tree in depth-first order.
|
||||||
|
while (iter.hasPrevious()) { |
||||||
|
Block block = (Block) iter.previous(); |
||||||
|
|
||||||
|
block.visit(new TreeVisitor() { |
||||||
|
public void visitTree(Tree tree) { |
||||||
|
tree.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
node.visitChildren(this); |
||||||
|
node.setKey(count.value++); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// Build the (strongly connected) components and call
|
||||||
|
// visitor.visitComponent for each.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
ArrayList stack = new ArrayList(); |
||||||
|
|
||||||
|
BitSet onStack = new BitSet(count.value + 1); |
||||||
|
|
||||||
|
int[] low = new int[count.value + 1]; |
||||||
|
|
||||||
|
int[] dfs = new int[count.value + 1]; |
||||||
|
|
||||||
|
int dfsNumber = 1; |
||||||
|
|
||||||
|
Node parent; // Parent in the SSA graph
|
||||||
|
|
||||||
|
// Visit the blocks in the CFG in reverse postorder
|
||||||
|
public void visitFlowGraph(FlowGraph cfg) { |
||||||
|
ListIterator e = postOrder.listIterator(postOrder.size()); |
||||||
|
|
||||||
|
while (e.hasPrevious()) { |
||||||
|
Block block = (Block) e.previous(); |
||||||
|
block.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
parent = null; |
||||||
|
tree.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
// This method is essentially Figure 4.6 in Taylor Simpson's PhD
|
||||||
|
// Thesis: www.cs.rice.edu/~lts. The implementation is a little
|
||||||
|
// funky, though, because someone wanted to use visitors.
|
||||||
|
// Grumble.
|
||||||
|
public void visitNode(Node node) { |
||||||
|
int dfn = dfs[node.key()]; |
||||||
|
// System.out.println("visit " + node + " key=" + node.key() +
|
||||||
|
// " dfn=" + dfn);
|
||||||
|
|
||||||
|
if (dfn == 0) { |
||||||
|
// If this node isn't equivalent to the node the care
|
||||||
|
// about,
|
||||||
|
// fergit it!
|
||||||
|
if (!equivalent(node).contains(startNode)) |
||||||
|
return; |
||||||
|
|
||||||
|
// The node in question has not yet been visited. Assign
|
||||||
|
// it
|
||||||
|
// the next dfNumber and add it to the stack. Mark all
|
||||||
|
// nodes that are equivalent to the node in question as
|
||||||
|
// being visited.
|
||||||
|
|
||||||
|
dfn = dfsNumber++; |
||||||
|
low[dfn] = dfn; |
||||||
|
|
||||||
|
stack.add(node); |
||||||
|
onStack.set(dfn); |
||||||
|
|
||||||
|
Iterator equiv = equivalent(node).iterator(); |
||||||
|
|
||||||
|
while (equiv.hasNext()) { |
||||||
|
Node e = (Node) equiv.next(); |
||||||
|
dfs[e.key()] = dfn; |
||||||
|
} |
||||||
|
|
||||||
|
// Again examine each node, e, equivalent to the node in
|
||||||
|
// question. Then recursively visit the children of e in
|
||||||
|
// the SSA Graph.
|
||||||
|
Node grandParent = parent; |
||||||
|
parent = node; |
||||||
|
|
||||||
|
equiv = equivalent(node).iterator(); |
||||||
|
|
||||||
|
while (equiv.hasNext()) { |
||||||
|
Node e = (Node) equiv.next(); |
||||||
|
|
||||||
|
Iterator children = children(e).iterator(); |
||||||
|
|
||||||
|
while (children.hasNext()) { |
||||||
|
Node child = (Node) children.next(); |
||||||
|
child.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
parent = grandParent; // Restore true parent
|
||||||
|
|
||||||
|
// Now we finally get to the point where we can
|
||||||
|
// construct a
|
||||||
|
// strongly connected component. Pop all of the nodes
|
||||||
|
// off
|
||||||
|
// the stack until the node in question is reached.
|
||||||
|
if (low[dfn] == dfn) { |
||||||
|
ArrayList scc = new ArrayList(); |
||||||
|
|
||||||
|
while (!stack.isEmpty()) { |
||||||
|
Node v = (Node) stack.remove(stack.size() - 1); |
||||||
|
onStack.clear(dfs[v.key()]); |
||||||
|
scc.addAll(equivalent(v)); |
||||||
|
|
||||||
|
if (v == node) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Sort the nodes in the SCC by their reverse
|
||||||
|
// post order numbers.
|
||||||
|
Collections.sort(scc, new Comparator() { |
||||||
|
public int compare(Object a, Object b) { |
||||||
|
int ka = ((Node) a).key(); |
||||||
|
int kb = ((Node) b).key(); |
||||||
|
return ka - kb; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.print("SCC ="); |
||||||
|
|
||||||
|
Iterator e = scc.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Node v = (Node) e.next(); |
||||||
|
System.out.print(" " + v + "{" + v.key() + "}"); |
||||||
|
} |
||||||
|
|
||||||
|
System.out.println(); |
||||||
|
} |
||||||
|
|
||||||
|
// Visit the SCC with the visitor that was passed in.
|
||||||
|
visitor.visitComponent(scc); |
||||||
|
} |
||||||
|
|
||||||
|
if (parent != null) { |
||||||
|
int parentDfn = dfs[parent.key()]; |
||||||
|
low[parentDfn] = Math.min(low[parentDfn], low[dfn]); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// We've already visited the node in question
|
||||||
|
if (parent != null) { |
||||||
|
int parentDfn = dfs[parent.key()]; |
||||||
|
|
||||||
|
// (parent, node) is either a cross edge or a back edge.
|
||||||
|
if (dfn < parentDfn && onStack.get(dfn)) { |
||||||
|
low[parentDfn] = Math.min(low[parentDfn], dfn); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prints a textual representation of the strongly connected components of |
||||||
|
* the SSAGraph to a PrintWriter. |
||||||
|
*/ |
||||||
|
public void printSCCs(PrintWriter pw) { |
||||||
|
Collection equivs = this.equivalences(); // A Collection of Sets
|
||||||
|
Iterator iter = equivs.iterator(); |
||||||
|
|
||||||
|
pw.println("Strongly Connected Components of the SSAGraph"); |
||||||
|
|
||||||
|
for (int i = 1; iter.hasNext(); i++) { |
||||||
|
Set scc = (Set) iter.next(); |
||||||
|
Iterator sccIter = scc.iterator(); |
||||||
|
|
||||||
|
pw.println(" Component " + i); |
||||||
|
|
||||||
|
while (sccIter.hasNext()) { |
||||||
|
Node node = (Node) sccIter.next(); |
||||||
|
pw.println(" " + node + " [VN = " + node.valueNumber() |
||||||
|
+ ", ID = " + System.identityHashCode(node) + "]"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Converts a control flow graph into static single assignment (SSA) |
||||||
|
form. In SSA form, each variable in the method has a number |
||||||
|
associated with it. Each target of an assignment statement is |
||||||
|
assigned a new number. Subsequent uses of that variable are assigned |
||||||
|
the same number. Thus, we have a compact form of definition-use |
||||||
|
information. Many of the optimiations we do take advantage of SSA form.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,26 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
TBAA.class\
|
||||||
|
TypeInference.class
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,296 @@ |
|||||||
|
/* |
||||||
|
* Class: TBAA |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tbaa; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
import org.apache.bcel.classfile.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.ClassHierarchy; |
||||||
|
import edu.purdue.cs.bloat.editor.EditorContext; |
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.FieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MemRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StaticFieldExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs Type-Based Alias Analysis (TBAA) to determine if one expression can |
||||||
|
* alias another. An expression may alias another expression if there is the |
||||||
|
* possibility that they refer to the same location in memory. BLOAT models |
||||||
|
* expressions that may reference memory locations with <tt>MemRefExpr</tt>s. |
||||||
|
* There are two kinds of "access expressions" in Java: field accesses (<tt>FieldExpr</tt> |
||||||
|
* and <tt>StaticFieldExpr</tt>) and array references (<tt>ArrayRefExpr</tt>). |
||||||
|
* Access paths consist of one or more access expressions. For instance, |
||||||
|
* <tt>a.b[i].c</tt> is an access expression. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* TBAA uses the FieldTypeDecl relation to determine whether or not two access |
||||||
|
* paths may refer to the same memory location. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* <table> |
||||||
|
* <th> |
||||||
|
* <td>AP1 </td> |
||||||
|
* <td>AP2 </td> |
||||||
|
* <td>FieldTypeDecl(AP1, Ap2)</td> |
||||||
|
* </th> |
||||||
|
* <tr> |
||||||
|
* <Td>p </td> |
||||||
|
* <Td>p </td> |
||||||
|
* <td>true </td> |
||||||
|
* </tr> |
||||||
|
* <tr> |
||||||
|
* <td>p.f </td> |
||||||
|
* <td>q.g </td> |
||||||
|
* <td>(f = g) && FieldTypeDecl(p, q)</td> |
||||||
|
* </tr> |
||||||
|
* <tr> |
||||||
|
* <td>p.f </td> |
||||||
|
* <Td>q[i]</td> |
||||||
|
* <td>false </td> |
||||||
|
* </tr> |
||||||
|
* <tr> |
||||||
|
* <td>p[i]</td> |
||||||
|
* <td>q[j]</td> |
||||||
|
* <td>FieldTypeDecl(p, q) </td> |
||||||
|
* </tr> |
||||||
|
* <tr> |
||||||
|
* <td>p </td> |
||||||
|
* <td>q </td> |
||||||
|
* <td>TypeDecl(p, q) </td> |
||||||
|
* </tr> |
||||||
|
* </table> |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* The TypeDecl(AP1, AP2) relation is defined as: |
||||||
|
* <p align=center> |
||||||
|
* Subtypes(Type(AP1)) INTERSECT Subtypes(Type(AP2)) != EMPTY |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* The subtype relationships are determined by the <tt>ClassHierarchy</tt>. |
||||||
|
* |
||||||
|
* @see ClassHierarchy |
||||||
|
* @see MemRefExpr |
||||||
|
* @see FieldExpr |
||||||
|
* @see StaticFieldExpr |
||||||
|
* @see ArrayRefExpr |
||||||
|
*/ |
||||||
|
public class TBAA { |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true, if expression <tt>a</tt> can alias expression <tt>b</tt>. |
||||||
|
*/ |
||||||
|
public static boolean canAlias(EditorContext context, Expr a, Expr b) { |
||||||
|
// Only memory reference expressions can have aliases.
|
||||||
|
if (!(a instanceof MemRefExpr)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Only memory reference expressions can have aliases.
|
||||||
|
if (!(b instanceof MemRefExpr)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Equal expressions can be aliases.
|
||||||
|
if (a.equalsExpr(b)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
MemberRef af = null; // Field accessed by expression a
|
||||||
|
MemberRef bf = null; // Field accessed by expression b
|
||||||
|
|
||||||
|
if (a instanceof FieldExpr) { |
||||||
|
af = ((FieldExpr) a).field(); |
||||||
|
} |
||||||
|
|
||||||
|
if (a instanceof StaticFieldExpr) { |
||||||
|
af = ((StaticFieldExpr) a).field(); |
||||||
|
} |
||||||
|
|
||||||
|
if (b instanceof FieldExpr) { |
||||||
|
bf = ((FieldExpr) b).field(); |
||||||
|
} |
||||||
|
|
||||||
|
if (b instanceof StaticFieldExpr) { |
||||||
|
bf = ((StaticFieldExpr) b).field(); |
||||||
|
} |
||||||
|
|
||||||
|
// Arrays and fields cannot alias the same location.
|
||||||
|
if (a instanceof ArrayRefExpr && bf != null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Arrays and fields cannot alias the same location.
|
||||||
|
if (b instanceof ArrayRefExpr && af != null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
Collection types = new LinkedHashSet(); |
||||||
|
types.add(a.type()); |
||||||
|
types.add(b.type()); |
||||||
|
ClassHierarchy hier = new ClassHierarchy(context, types, true); |
||||||
|
|
||||||
|
// Only type-compatible arrays can alias the same location.
|
||||||
|
if (a instanceof ArrayRefExpr && b instanceof ArrayRefExpr) { |
||||||
|
ArrayRefExpr aa = (ArrayRefExpr) a; |
||||||
|
ArrayRefExpr bb = (ArrayRefExpr) b; |
||||||
|
|
||||||
|
Type aaIndexType = aa.index().type(); |
||||||
|
Type bbIndexType = bb.index().type(); |
||||||
|
Type aaArrayType = aa.array().type(); |
||||||
|
Type bbArrayType = bb.array().type(); |
||||||
|
|
||||||
|
Assert.isTrue(Assert.isIntegral(aaIndexType), aa.index() + " in " |
||||||
|
+ aa + " (" + aaIndexType + ") is not an integer"); |
||||||
|
Assert.isTrue(Assert.isIntegral(bbIndexType), bb.index() + " in " |
||||||
|
+ bb + " (" + bbIndexType + ") is not an integer"); |
||||||
|
Assert.isTrue(aaArrayType instanceof ArrayType |
||||||
|
|| aaArrayType.equals(Type.OBJECT) |
||||||
|
|| aaArrayType.equals(new ObjectType( |
||||||
|
"java.lang.Serializable")) |
||||||
|
|| aaArrayType.equals(new ObjectType("jav.lang.Cloneable")) |
||||||
|
|| aaArrayType.equals(Type.NULL), aa.array() + " in " + aa |
||||||
|
+ " (" + aaArrayType + ") is not an array"); |
||||||
|
Assert.isTrue(bbArrayType instanceof ArrayType |
||||||
|
|| bbArrayType.equals(Type.OBJECT) |
||||||
|
|| bbArrayType.equals(new ObjectType( |
||||||
|
"java.lang.Serializable")) |
||||||
|
|| bbArrayType.equals(new ObjectType("jav.lang.Cloneable")) |
||||||
|
|| bbArrayType.equals(Type.NULL), bb.array() + " in " + bb |
||||||
|
+ " (" + bbArrayType + ") is not an array"); |
||||||
|
|
||||||
|
// Optimization: if constant indices. Only equal indices can
|
||||||
|
// alias the same location.
|
||||||
|
if (aa.index() instanceof ConstantExpr |
||||||
|
&& bb.index() instanceof ConstantExpr) { |
||||||
|
|
||||||
|
ConstantExpr ai = (ConstantExpr) aa.index(); |
||||||
|
ConstantExpr bi = (ConstantExpr) bb.index(); |
||||||
|
|
||||||
|
if (ai.value() != null && bi.value() != null) { |
||||||
|
if (!ai.value().equals(bi.value())) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return intersects(hier, aaArrayType, bbArrayType); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
if (af != null) { |
||||||
|
ClassGen klass = context.editClass(((ObjectType) af |
||||||
|
.declaringClass()).getClassName()); |
||||||
|
Field e = klass.containsField(af.name()); |
||||||
|
if (e == null) { |
||||||
|
throw new NoSuchFieldException("Field: " + af.name() |
||||||
|
+ "not found in class " + af.declaringClass()); |
||||||
|
} |
||||||
|
|
||||||
|
if (e.isVolatile()) { |
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (e.isFinal()) { |
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
// WE NEVER STARTED EDITING SO DON'T HAVE TO RELEASE IT
|
||||||
|
} |
||||||
|
|
||||||
|
if (bf != null) { |
||||||
|
ClassGen klass = context.editClass(((ObjectType) bf |
||||||
|
.declaringClass()).getClassName()); |
||||||
|
Field e = klass.containsField(bf.name()); |
||||||
|
if (e == null) { |
||||||
|
throw new NoSuchFieldException("Field: " + bf.name() |
||||||
|
+ "not found in class " + bf.declaringClass()); |
||||||
|
} |
||||||
|
|
||||||
|
if (e.isVolatile()) { |
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (e.isFinal()) { |
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
// WE NEVER STARTED EDITING SO DON'T HAVE TO RELEASE IT
|
||||||
|
} |
||||||
|
|
||||||
|
} catch (NoSuchFieldException e) { |
||||||
|
// A field wasn't found. Silently assume there is an alias.
|
||||||
|
return true; |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
// A field wasn't found. Silently assume there is an alias.
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// Only fields with the same name can alias the same location.
|
||||||
|
if (af != null && bf != null) { |
||||||
|
return af.equals(bf); |
||||||
|
} |
||||||
|
|
||||||
|
// Default case. This shouldn't happen.
|
||||||
|
return intersects(hier, a.type(), b.type()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns <tt>true</tt> if type a and type c intersect. That is, the two |
||||||
|
* types have a non-null intersection. |
||||||
|
*/ |
||||||
|
private static boolean intersects(ClassHierarchy hier, Type a, Type b) { |
||||||
|
return !hier.intersectType(a, b).equals(Type.NULL); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,829 @@ |
|||||||
|
/* |
||||||
|
* Class: TypeInference |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tbaa; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.context.BloatContext; |
||||||
|
import edu.purdue.cs.bloat.editor.ClassHierarchy; |
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.ssa.ComponentVisitor; |
||||||
|
import edu.purdue.cs.bloat.ssa.SSAGraph; |
||||||
|
import edu.purdue.cs.bloat.tree.ArithExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayLengthExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallMethodExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallStaticExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CastExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CatchExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CheckExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.FieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.InitStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.InstanceOfExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NegExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ReturnAddressExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ShiftExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackManipStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StaticFieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Typed-based alias analysis requires that we know the types of all entities in |
||||||
|
* a method. However, local variables and stack variables do not have declared |
||||||
|
* types. Thus, we have to infer them. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* <tt>TypeInference</tt> uses a simpilified version of everyone's favorite |
||||||
|
* type inference algorithm from <u>Object-Oriented Type Systems</u> by |
||||||
|
* Palsberg and Schwartzbach. It is simplified in that no interprocedural type |
||||||
|
* information is calculated. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Here's how it works. Entities such as method arguments, fields, and constants |
||||||
|
* have a known type. This known type is expressed in a constraint that |
||||||
|
* constraints the entity to its type. Operations involving assignment (also |
||||||
|
* phi-statements and stack operations) propagate these constraints to the |
||||||
|
* targets of the assignments. |
||||||
|
*/ |
||||||
|
public class TypeInference implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
static final Type UNDEF = Type.getType("Lundef!;"); |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
transform(state.controlFlowGraph(), state.context()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Traverses the control flow graph and with the help of a number of vistors |
||||||
|
* performs type-based alias analysis. |
||||||
|
* |
||||||
|
* @param cfg |
||||||
|
* The control flow graph on which to perform TBAA. |
||||||
|
* @param context |
||||||
|
* Used to obtain a class heirarchy used for getting information |
||||||
|
* about Types (classes). |
||||||
|
* |
||||||
|
* @see SSAGraph |
||||||
|
* @see ComponentVisitor |
||||||
|
* @see TreeVisitor |
||||||
|
* |
||||||
|
*/ |
||||||
|
public void transform(FlowGraph cfg, BloatContext context) { |
||||||
|
ClassHierarchy hier = context.getHierarchy(); |
||||||
|
|
||||||
|
// First go through the CFG and determine the type of the local
|
||||||
|
// variables corresponding to method arguments. Assign those
|
||||||
|
// types to all uses of those local variables.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
// a := INIT
|
||||||
|
// [declared param type] <= [a]
|
||||||
|
|
||||||
|
MethodGen method = stmt.block().graph().method(); |
||||||
|
|
||||||
|
LocalExpr[] t = stmt.targets(); |
||||||
|
|
||||||
|
for (int i = 0; i < t.length; i++) { |
||||||
|
LocalExpr var = t[i]; |
||||||
|
|
||||||
|
int index = var.index(); |
||||||
|
|
||||||
|
// If the method is static, there is no this pointer in
|
||||||
|
// the
|
||||||
|
// local variable table, so decrement index to point to
|
||||||
|
// the
|
||||||
|
// indexth local variable. This is needed with indexing
|
||||||
|
// into method.type().indexedParamTypes().
|
||||||
|
if (!method.isStatic()) { |
||||||
|
index--; |
||||||
|
} |
||||||
|
|
||||||
|
Type type; |
||||||
|
|
||||||
|
if (index == -1) { |
||||||
|
// If the index is -1, then we're dealing with local
|
||||||
|
// variable 0 of a non-static method. This local
|
||||||
|
// variable
|
||||||
|
// is the this pointer. Its type is the type of the
|
||||||
|
// class
|
||||||
|
// in which the method is declared.
|
||||||
|
type = new ObjectType(method.getClassName()); |
||||||
|
|
||||||
|
} else { |
||||||
|
// One of the method's arguments is being initialized.
|
||||||
|
// Figure out its type.
|
||||||
|
type = method.getArgumentType(index); |
||||||
|
} |
||||||
|
|
||||||
|
var.setType(type); |
||||||
|
|
||||||
|
Iterator uses = var.uses().iterator(); |
||||||
|
|
||||||
|
// Set the type of the uses of the local variable, also.
|
||||||
|
while (uses.hasNext()) { |
||||||
|
LocalExpr use = (LocalExpr) uses.next(); |
||||||
|
use.setType(type); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
|
||||||
|
// We don't know the type of the expression yet.
|
||||||
|
expr.setType(UNDEF); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
SSAGraph ssaGraph = new SSAGraph(cfg); |
||||||
|
|
||||||
|
final TypeInferenceVisitor visitor = new TypeInferenceVisitor(hier, |
||||||
|
ssaGraph); |
||||||
|
|
||||||
|
// Visit each strong connected component in the SSAGraph and
|
||||||
|
// compute the type information using the TypeInferenceVisitor.
|
||||||
|
ssaGraph.visitComponents(new ComponentVisitor() { |
||||||
|
public void visitComponent(List scc) { |
||||||
|
visitor.changed = true; |
||||||
|
|
||||||
|
while (visitor.changed) { |
||||||
|
visitor.changed = false; |
||||||
|
|
||||||
|
Iterator iter = scc.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node node = (Node) iter.next(); |
||||||
|
node.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// Convert POS_SHORT types back into SHORT types and POS_BYTE
|
||||||
|
// types back into BYTE types.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
|
||||||
|
if (expr.type().equals(ClassHierarchy.POS_SHORT)) { |
||||||
|
expr.setType(Type.SHORT); |
||||||
|
|
||||||
|
} else if (expr.type().equals(ClassHierarchy.POS_BYTE)) { |
||||||
|
expr.setType(Type.BYTE); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
// Print out all the type information and do some checking.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
|
||||||
|
System.out.println("typeof(" + expr + ") = " + expr.type()); |
||||||
|
|
||||||
|
if (expr.type().equals(UNDEF)) { |
||||||
|
System.out.println("WARNING: typeof(" + expr |
||||||
|
+ ") = UNDEF"); |
||||||
|
} |
||||||
|
|
||||||
|
Assert |
||||||
|
.isFalse(expr.type().equals( |
||||||
|
ClassHierarchy.POS_SHORT)); |
||||||
|
Assert.isFalse(expr.type().equals(ClassHierarchy.POS_BYTE)); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return "---------Doing type inference--------"; |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Type Inferencing: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Does most of the type inference work. It generates the type constraints for |
||||||
|
* the expressions in the CFG. |
||||||
|
*/ |
||||||
|
class TypeInferenceVisitor extends TreeVisitor { |
||||||
|
public boolean changed; |
||||||
|
|
||||||
|
public ClassHierarchy hier; |
||||||
|
|
||||||
|
SSAGraph ssaGraph; |
||||||
|
|
||||||
|
public TypeInferenceVisitor(ClassHierarchy hier, SSAGraph ssaGraph) { |
||||||
|
this.hier = hier; |
||||||
|
this.ssaGraph = ssaGraph; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
throw new RuntimeException(expr + " not supported"); |
||||||
|
} |
||||||
|
|
||||||
|
// Make a new start constraint for the expression being shifted.
|
||||||
|
public void visitShiftExpr(ShiftExpr expr) { |
||||||
|
if (Assert.isIntegral(expr.expr().type()) |
||||||
|
|| expr.expr().type().equals(ClassHierarchy.POS_SHORT) |
||||||
|
|| expr.expr().type().equals(ClassHierarchy.POS_BYTE)) { |
||||||
|
|
||||||
|
start(expr, Type.INT); |
||||||
|
|
||||||
|
} else { |
||||||
|
prop(expr, expr.expr()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If either of the ArithExpr's operands has type INTEGER, then the
|
||||||
|
// entire expression must have type INTEGER. Otherwise, the type of
|
||||||
|
// one of the operands must be undefined, or both operands have the
|
||||||
|
// same type. If the ArithExpr is one of the compare operations,
|
||||||
|
// then it has an INTEGER type.
|
||||||
|
public void visitArithExpr(ArithExpr expr) { |
||||||
|
if (Assert.isIntegral(expr.left().type()) |
||||||
|
|| expr.left().type().equals(ClassHierarchy.POS_SHORT) |
||||||
|
|| expr.left().type().equals(ClassHierarchy.POS_BYTE)) { |
||||||
|
|
||||||
|
start(expr, Type.INT); |
||||||
|
|
||||||
|
} else if (Assert.isIntegral(expr.right().type()) |
||||||
|
|| expr.right().type().equals(ClassHierarchy.POS_SHORT) |
||||||
|
|| expr.right().type().equals(ClassHierarchy.POS_BYTE)) { |
||||||
|
|
||||||
|
start(expr, Type.INT); |
||||||
|
|
||||||
|
} else { |
||||||
|
Assert.isTrue(expr.left().type().equals(TypeInference.UNDEF) |
||||||
|
|| expr.right().type().equals(TypeInference.UNDEF) |
||||||
|
|| expr.left().type().equals(expr.right().type()), expr |
||||||
|
.left() |
||||||
|
+ ".type() = " |
||||||
|
+ expr.left().type() |
||||||
|
+ " != " |
||||||
|
+ expr.right() |
||||||
|
+ ".type() = " + expr.right().type()); |
||||||
|
|
||||||
|
if (expr.operation() == ArithExpr.CMP |
||||||
|
|| expr.operation() == ArithExpr.CMPL |
||||||
|
|| expr.operation() == ArithExpr.CMPG) { |
||||||
|
|
||||||
|
start(expr, Type.INT); |
||||||
|
|
||||||
|
} else { |
||||||
|
prop(expr, expr.left()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the expression being negated has an integral type, then the
|
||||||
|
// type of the expression in an INTEGER.
|
||||||
|
public void visitNegExpr(NegExpr expr) { |
||||||
|
if (Assert.isIntegral(expr.expr().type()) |
||||||
|
|| expr.expr().type().equals(ClassHierarchy.POS_SHORT) |
||||||
|
|| expr.expr().type().equals(ClassHierarchy.POS_BYTE)) { |
||||||
|
|
||||||
|
start(expr, Type.INT); |
||||||
|
|
||||||
|
} else { |
||||||
|
prop(expr, expr.expr()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnAddressExpr(ReturnAddressExpr expr) { |
||||||
|
start(expr, ReturnaddressType.NO_TARGET); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCheckExpr(CheckExpr expr) { |
||||||
|
prop(expr, expr.expr()); |
||||||
|
} |
||||||
|
|
||||||
|
// Why does it start the expression with an INTEGER type???
|
||||||
|
// Ans: Because instanceof returns a boolean, which is dealt with as an
|
||||||
|
// int.
|
||||||
|
public void visitInstanceOfExpr(InstanceOfExpr expr) { |
||||||
|
start(expr, Type.INT); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
start(expr, Type.INT); |
||||||
|
} |
||||||
|
|
||||||
|
// If a VarExpr does not define a variable, then propagate the type
|
||||||
|
// of the expression that does define the variable to the VarExpr.
|
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
if (!expr.isDef()) { |
||||||
|
if (expr.def() != null) { |
||||||
|
prop(expr, expr.def()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Not surprisingly, StackManipStmts are ugly looking. The type
|
||||||
|
// information is propagated from the "before" stack variable to the
|
||||||
|
// appropriate "after" stack variable. As seen in other places, the
|
||||||
|
// transformation is given by an integer array.
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
// a := b
|
||||||
|
// [b] <= [a]
|
||||||
|
|
||||||
|
StackExpr[] target = stmt.target(); |
||||||
|
StackExpr[] source = stmt.source(); |
||||||
|
|
||||||
|
switch (stmt.kind()) { |
||||||
|
case StackManipStmt.SWAP: |
||||||
|
// 0 1 -> 1 0
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 2, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0 }); |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP: |
||||||
|
// 0 -> 0 0
|
||||||
|
Assert.isTrue(source.length == 1 && target.length == 2, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 0, 0 }); |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP_X1: |
||||||
|
// 0 1 -> 1 0 1
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP_X2: |
||||||
|
if (source.length == 3) { |
||||||
|
// 0 1 2 -> 2 0 1 2
|
||||||
|
Assert.isTrue(source.length == 3 && target.length == 4, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 2, 0, 1, 2 }); |
||||||
|
} else { |
||||||
|
// 0-1 2 -> 2 0-1 2
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP2: |
||||||
|
if (source.length == 2) { |
||||||
|
// 0 1 -> 0 1 0 1
|
||||||
|
Assert.isTrue(target.length == 4, "Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 0, 1, 0, 1 }); |
||||||
|
} else { |
||||||
|
// 0-1 -> 0-1 0-1
|
||||||
|
Assert.isTrue(source.length == 1 && target.length == 2, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 0, 0 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP2_X1: |
||||||
|
if (source.length == 3) { |
||||||
|
// 0 1 2 -> 1 2 0 1 2
|
||||||
|
Assert.isTrue(target.length == 5, "Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 2, 0, 1, 2 }); |
||||||
|
} else { |
||||||
|
// 0 1-2 -> 1-2 0 1-2
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
case StackManipStmt.DUP2_X2: |
||||||
|
if (source.length == 4) { |
||||||
|
// 0 1 2 3 -> 2 3 0 1 2 3
|
||||||
|
Assert.isTrue(target.length == 6, "Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 2, 3, 0, 1, 2, 3 }); |
||||||
|
} else if (source.length == 3) { |
||||||
|
if (target.length == 5) { |
||||||
|
// 0-1 2 3 -> 2 3 0-1 2 3
|
||||||
|
manip(source, target, new int[] { 1, 2, 0, 1, 2 }); |
||||||
|
} else { |
||||||
|
// 0 1 2-3 -> 2-3 0 1 2-3
|
||||||
|
Assert.isTrue(target.length == 4, "Illegal statement: " |
||||||
|
+ stmt); |
||||||
|
manip(source, target, new int[] { 2, 0, 1, 2 }); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// 0-1 2-3 -> 2-3 0-1 2-3
|
||||||
|
Assert.isTrue(source.length == 2 && target.length == 3, |
||||||
|
"Illegal statement: " + stmt); |
||||||
|
manip(source, target, new int[] { 1, 0, 1 }); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
stmt.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
private void manip(StackExpr[] source, StackExpr[] target, int[] s) { |
||||||
|
for (int i = 0; i < s.length; i++) { |
||||||
|
prop(target[i], source[s[i]]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The type of the expression being stored flows into the target of
|
||||||
|
// the store. The type of the target flows into the StoreExpr.
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
// a := b
|
||||||
|
// [b] <= [a]
|
||||||
|
|
||||||
|
prop(expr.target(), expr.expr()); |
||||||
|
prop(expr, expr.target()); |
||||||
|
} |
||||||
|
|
||||||
|
// The type of the exception being caught flows into the type of the
|
||||||
|
// CatchExpr.
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
// Catch(t)
|
||||||
|
// t <= [Catch(t)]
|
||||||
|
|
||||||
|
Type catchType = expr.catchType(); |
||||||
|
|
||||||
|
if (catchType == Type.NULL) { |
||||||
|
catchType = Type.THROWABLE; |
||||||
|
} |
||||||
|
|
||||||
|
start(expr, catchType); |
||||||
|
} |
||||||
|
|
||||||
|
// The type information of each of the PhiStmt's operands flows into
|
||||||
|
// the target. If an operand is undefined, the type of the target
|
||||||
|
// flows into that operand so that it will have a type.
|
||||||
|
public void visitPhiStmt(PhiStmt stmt) { |
||||||
|
// a := Phi(b, c)
|
||||||
|
// [b] <= [a]
|
||||||
|
// [c] <= [a]
|
||||||
|
|
||||||
|
List back = new ArrayList(stmt.operands().size()); |
||||||
|
|
||||||
|
Iterator e = stmt.operands().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Expr expr = (Expr) e.next(); |
||||||
|
|
||||||
|
if (expr instanceof VarExpr && expr.def() == null) { |
||||||
|
back.add(expr); |
||||||
|
|
||||||
|
} else { |
||||||
|
prop(stmt.target(), expr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Propagate the type back to the operands which are undefined.
|
||||||
|
// Otherwise, they won't be able to get a type.
|
||||||
|
e = back.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Expr expr = (Expr) e.next(); |
||||||
|
|
||||||
|
if (expr.def() == null) { |
||||||
|
prop(expr, stmt.target()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the ArrayRefExpr is not a definition, then the type of the
|
||||||
|
// elements in the array flows into the type of the ArrayRefExpr.
|
||||||
|
// This is all contingent upon the type of the array elements being
|
||||||
|
// defined, non-object, not serializable, not clonable, and not
|
||||||
|
// null.
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
// a[i]
|
||||||
|
// [a[i]] <= [element type of a]
|
||||||
|
|
||||||
|
Expr array = expr.array(); |
||||||
|
|
||||||
|
if (!expr.isDef()) { |
||||||
|
if (!array.type().equals(TypeInference.UNDEF) |
||||||
|
&& !array.type().equals(Type.OBJECT) |
||||||
|
&& !array.type().equals( |
||||||
|
new ObjectType("java.lang.Serializable")) |
||||||
|
&& !array.type().equals( |
||||||
|
new ObjectType("java.lang.Cloneable")) |
||||||
|
&& !array.type().equals(Type.NULL)) { |
||||||
|
|
||||||
|
Assert.isTrue(array.type() instanceof ArrayType, array + " in " |
||||||
|
+ expr + " (" + array.type() + ") is not an array"); |
||||||
|
start(expr, ((ArrayType) expr.array().type()).getElementType()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The return type of the method flow into the CallMethodExpr.
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
// x.m(a), m in class C
|
||||||
|
// [x] <= C
|
||||||
|
// [a] <= [declared param type]
|
||||||
|
// [declared return type] <= [x.m(a)]
|
||||||
|
|
||||||
|
MethodRef method = expr.method(); |
||||||
|
|
||||||
|
Type returnType = method.returnType(); |
||||||
|
|
||||||
|
start(expr, returnType); |
||||||
|
} |
||||||
|
|
||||||
|
// The return type of the method flows into the CallStaticExpr.
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
// m(a)
|
||||||
|
// [a] <= [declared param type]
|
||||||
|
// [declared return type] <= [m(a)]
|
||||||
|
|
||||||
|
MethodRef method = expr.method(); |
||||||
|
|
||||||
|
Type returnType = method.returnType(); |
||||||
|
|
||||||
|
start(expr, returnType); |
||||||
|
} |
||||||
|
|
||||||
|
// The type to which an expression is cast flows into the CastExpr.
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
// (C) a
|
||||||
|
// [(C) a] <= C
|
||||||
|
|
||||||
|
start(expr, expr.castType()); |
||||||
|
} |
||||||
|
|
||||||
|
// The type of the constant flows into the type of the ConstantExpr.
|
||||||
|
public void visitConstantExpr(ConstantExpr expr) { |
||||||
|
// "a"
|
||||||
|
// String <= ["a"]
|
||||||
|
|
||||||
|
Object value = expr.value(); |
||||||
|
|
||||||
|
if (value == null) { |
||||||
|
start(expr, Type.NULL); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (value instanceof String) { |
||||||
|
start(expr, Type.STRING); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (value instanceof Boolean) { |
||||||
|
start(expr, Type.BOOLEAN); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (value instanceof Integer) { |
||||||
|
start(expr, Type.INT); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (value instanceof Long) { |
||||||
|
start(expr, Type.LONG); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (value instanceof Float) { |
||||||
|
start(expr, Type.FLOAT); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (value instanceof Double) { |
||||||
|
start(expr, Type.DOUBLE); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
int v; |
||||||
|
|
||||||
|
if (value instanceof Byte) { |
||||||
|
v = ((Byte) value).byteValue(); |
||||||
|
|
||||||
|
} else if (value instanceof Short) { |
||||||
|
v = ((Short) value).shortValue(); |
||||||
|
|
||||||
|
} else if (value instanceof Character) { |
||||||
|
v = ((Character) value).charValue(); |
||||||
|
|
||||||
|
} else { |
||||||
|
throw new RuntimeException(); |
||||||
|
} |
||||||
|
|
||||||
|
if (v >= 0) { |
||||||
|
if (v <= 1) { |
||||||
|
start(expr, Type.BOOLEAN); // It'll fit in a BOOLEAN
|
||||||
|
|
||||||
|
} else if (v <= Byte.MAX_VALUE) { |
||||||
|
start(expr, ClassHierarchy.POS_BYTE); |
||||||
|
|
||||||
|
} else if (v <= Short.MAX_VALUE) { |
||||||
|
start(expr, ClassHierarchy.POS_SHORT); |
||||||
|
|
||||||
|
} else if (v <= Character.MAX_VALUE) { |
||||||
|
start(expr, Type.CHAR); |
||||||
|
|
||||||
|
} else { |
||||||
|
start(expr, Type.INT); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// The constant's value is negative
|
||||||
|
if (Byte.MIN_VALUE <= v) { |
||||||
|
start(expr, Type.BYTE); // It'll fit in a BYTE
|
||||||
|
|
||||||
|
} else if (Short.MIN_VALUE <= v) { |
||||||
|
start(expr, Type.SHORT); |
||||||
|
|
||||||
|
} else { |
||||||
|
start(expr, Type.INT); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the FieldExpr is a definition, the type of the field flows
|
||||||
|
// into the type of the FieldExpr.
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
// a.f, f in class C
|
||||||
|
// [a] <= C
|
||||||
|
// [declared field type] <= [a.f]
|
||||||
|
|
||||||
|
MemberRef field = expr.field(); |
||||||
|
|
||||||
|
// if (! expr.isDef()) {
|
||||||
|
start(expr, field.type()); |
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
// If the expression representing the type of the array being
|
||||||
|
// created is defined, then and array of that type flows into the
|
||||||
|
// type of the NewArrayExpr.
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
// new t[i]
|
||||||
|
// array-1-of-t <= [new t[i]]
|
||||||
|
|
||||||
|
if (!expr.elementType().equals(TypeInference.UNDEF)) { |
||||||
|
start(expr, new ArrayType(expr.elementType(), 1)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The type of the object being created flows into the NewExpr.
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
// new C
|
||||||
|
// C <= [new C]
|
||||||
|
|
||||||
|
start(expr, expr.objectType()); |
||||||
|
} |
||||||
|
|
||||||
|
// If the type of the expression specifying the type of the array
|
||||||
|
// being created is defined, then that type flows into the type of
|
||||||
|
// the NewMultiArrayExpr.
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
// new t[i][j][k]
|
||||||
|
// array-dim-of-t <= [new t[i][j][k]]
|
||||||
|
|
||||||
|
if (!expr.elementType().equals(TypeInference.UNDEF)) { |
||||||
|
start(expr, new ArrayType(expr.elementType(), |
||||||
|
expr.dimensions().length)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If the field reference is a definition, then the type of the
|
||||||
|
// field flows into the type of the StaticFieldExpr.
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr expr) { |
||||||
|
// C.f
|
||||||
|
// [declared field type] <= [C.f]
|
||||||
|
|
||||||
|
MemberRef field = expr.field(); |
||||||
|
|
||||||
|
if (!expr.isDef()) { |
||||||
|
start(expr, field.type()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Initializes the constraint propagation by assigning a type to a
|
||||||
|
// given expression.
|
||||||
|
private void start(Expr expr, Type type) { |
||||||
|
if (TypeInference.DEBUG) { |
||||||
|
System.out.println("start " + expr + " <- " + type); |
||||||
|
} |
||||||
|
|
||||||
|
if (type.equals(TypeInference.UNDEF)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!expr.type().equals(TypeInference.UNDEF)) { |
||||||
|
if (TypeInference.DEBUG) { |
||||||
|
System.out.print("union of " + expr.type() + " and " + type); |
||||||
|
} |
||||||
|
|
||||||
|
if (!Assert.isIntegral(type) |
||||||
|
&& !type.equals(ClassHierarchy.POS_BYTE) |
||||||
|
&& !type.equals(ClassHierarchy.POS_SHORT)) { |
||||||
|
Assert.isTrue(Assert.simple(type).equals( |
||||||
|
Assert.simple(expr.type()))); |
||||||
|
|
||||||
|
if (type instanceof ReferenceType) { |
||||||
|
// The expr and type may have different types. So, deal
|
||||||
|
// with the common supertype of both type and
|
||||||
|
// expr.type().
|
||||||
|
// That is, the type to which both belong.
|
||||||
|
|
||||||
|
type = hier.unionType(type, expr.type()); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// We're dealing with one of the integral types. Take the
|
||||||
|
// union of the two types and work with that.
|
||||||
|
BitSet v1 = ClassHierarchy.typeToSet(type); |
||||||
|
BitSet v2 = ClassHierarchy.typeToSet(expr.type()); |
||||||
|
v1.or(v2); |
||||||
|
type = ClassHierarchy.setToType(v1); |
||||||
|
} |
||||||
|
|
||||||
|
if (TypeInference.DEBUG) { |
||||||
|
System.out.println(" is " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Set the type of all nodes equivalent to expr to the type we're
|
||||||
|
// working with.
|
||||||
|
Iterator iter = ssaGraph.equivalent(expr).iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node node = (Node) iter.next(); |
||||||
|
|
||||||
|
if (node instanceof Expr) { |
||||||
|
Expr e = (Expr) node; |
||||||
|
|
||||||
|
if (e.setType(type)) { |
||||||
|
changed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Propagates the type of the source expression to all expressions
|
||||||
|
// equivalent to the other expr.
|
||||||
|
private void prop(Expr expr, Expr source) { |
||||||
|
if (TypeInference.DEBUG) { |
||||||
|
System.out.println("prop " + expr + " <- " + source); |
||||||
|
} |
||||||
|
start(expr, source.type()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Performs type-base alias analysis (TBAA) on a control flow graph. |
||||||
|
Type-based alias analysis considers the types of variables when |
||||||
|
deciding whether or not two variable can refer to the same object. |
||||||
|
Before TBAA can occur, the types of variables are inferred. Type |
||||||
|
inference requires information about the class hierarchy of classes |
||||||
|
being BLOATed.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,19 @@ |
|||||||
|
package edu.purdue.cs.bloat.tests; |
||||||
|
|
||||||
|
public class BloatTester1 { |
||||||
|
|
||||||
|
int testDepth(int a) throws Exception { |
||||||
|
while (String.class != null) |
||||||
|
if (this.getClass().getMethods()[0].hashCode() == a) |
||||||
|
do { |
||||||
|
try { |
||||||
|
this.getClass().getMethod("testDepth", |
||||||
|
new Class[] { Integer.TYPE }).invoke(this, |
||||||
|
new Object[] { new Integer(2) }); |
||||||
|
} catch (ArrayIndexOutOfBoundsException e) { |
||||||
|
throw new ClassNotFoundException("foo", e); |
||||||
|
} |
||||||
|
} while (0 == 5); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package edu.purdue.cs.bloat.tests; |
||||||
|
|
||||||
|
public class BloatTester2 { |
||||||
|
|
||||||
|
public static BloatTester2 frob() throws Exception { |
||||||
|
try { |
||||||
|
System.in.close(); |
||||||
|
System.out.println((new Object() { |
||||||
|
public String snap() { |
||||||
|
try { |
||||||
|
return "" + "snap"; |
||||||
|
} catch (NullPointerException e) { |
||||||
|
throw new IllegalArgumentException(e.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
}).snap()); |
||||||
|
} catch (IllegalArgumentException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package edu.purdue.cs.bloat.tests; |
||||||
|
|
||||||
|
public class BloatTester3 { |
||||||
|
void frob() { |
||||||
|
try { |
||||||
|
int x = 5; |
||||||
|
int y = 50 * x; |
||||||
|
|
||||||
|
if (x > 9) |
||||||
|
throw new ClassNotFoundException(); |
||||||
|
|
||||||
|
if (y < 99) { |
||||||
|
try { |
||||||
|
String in = "elvis"; |
||||||
|
in.toLowerCase(); |
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
BloatTester1.class \
|
||||||
|
BloatTester2.class \
|
||||||
|
BloatTester3.class
|
||||||
|
|
||||||
|
include ../class.mk |
||||||
|
|
@ -0,0 +1,712 @@ |
|||||||
|
/* |
||||||
|
* Class: DeadCodeElimintation |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.tree.AddressStoreStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ArithExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayLengthExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallMethodExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallStaticExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CastExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CatchExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.DefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.ExprStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.FieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.GotoStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.IfStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.InitStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.JsrStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.JumpStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.LabelStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MonitorStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.NewArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.RCExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.RetStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ReturnExprStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ReturnStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SCStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SRStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StackExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackManipStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Stmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.SwitchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ThrowStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.UCExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.VarExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ZeroCheckExpr; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* DeadCodeElimination performs SSA-based dead code elimination as described in |
||||||
|
* [Cytron, et. al. 91]. The idea behind dead code elimination is that there are |
||||||
|
* some instructions that do not contribute anything useful to the result of the |
||||||
|
* program. Most dead code is introduced by other optimizations. |
||||||
|
* |
||||||
|
* A program statement is live if one or more of the following holds: |
||||||
|
* |
||||||
|
* <ol> |
||||||
|
* |
||||||
|
* <li>The statement effects program output. In Java this is a lot more than |
||||||
|
* just I/O. We must be conservative and assume that exceptions and monitor |
||||||
|
* expression are always live. |
||||||
|
* |
||||||
|
* <li>The statement is an assignment statement whose target is used in a live |
||||||
|
* statement. |
||||||
|
* |
||||||
|
* <li>The statement is a conditional branch and there are live statements |
||||||
|
* whose execution depend on the conditional branch. |
||||||
|
* |
||||||
|
* <ol> |
||||||
|
* |
||||||
|
* Basically, the algorithm proceeds by marking a number of statements as being |
||||||
|
* pre-live and then uses a worklist to determine which statements must also be |
||||||
|
* live by the above three conditions. |
||||||
|
*/ |
||||||
|
public class DeadCodeElimination implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
private static final int DEAD = 0; |
||||||
|
|
||||||
|
private static final int LIVE = 1; |
||||||
|
|
||||||
|
// Keep a work list of expressions that need to be made live.
|
||||||
|
LinkedList worklist; |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
transform(state.controlFlowGraph()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs dead code elimination. |
||||||
|
*/ |
||||||
|
private void transform(FlowGraph cfg) { |
||||||
|
// Mark all nodes in the tree as DEAD.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitNode(Node node) { |
||||||
|
node.visitChildren(this); |
||||||
|
node.setKey(DEAD); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
worklist = new LinkedList(); |
||||||
|
|
||||||
|
// Visit the nodes in the tree and mark nodes that we know must be
|
||||||
|
// LIVE.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitMonitorStmt(MonitorStmt stmt) { |
||||||
|
// NullPointerException, IllegalMonitorStateException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
// Needed to correctly initialize the formal parameters when
|
||||||
|
// coloring
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitAddressStoreStmt(AddressStoreStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSRStmt(SRStmt stmt) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt stmt) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
// Memory allocation
|
||||||
|
// NegativeArraySizeException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
// Memory allocation
|
||||||
|
// NegativeArraySizeException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
// Memory allocation
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackExpr(StackExpr expr) { |
||||||
|
if (expr.stmt() instanceof PhiStmt) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Stack change
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitZeroCheckExpr(ZeroCheckExpr expr) { |
||||||
|
// NullPointerException or DivideByZeroException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRCExpr(RCExpr expr) { |
||||||
|
// Residency check
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitUCExpr(UCExpr expr) { |
||||||
|
// Update check
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
// ClassCastException
|
||||||
|
if (expr.castType() instanceof ReferenceType) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} else { |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArithExpr(ArithExpr expr) { |
||||||
|
// DivideByZeroException
|
||||||
|
if (expr.operation() == ArithExpr.DIV |
||||||
|
|| expr.operation() == ArithExpr.REM) { |
||||||
|
|
||||||
|
if (Assert.isIntegral(expr.type())) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
// NullPointerException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
// NullPointerException, ArrayIndexOutOfBoundsException,
|
||||||
|
// ArrayStoreException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
// NullPointerException
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
// Call
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
// Call
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
// Stack change
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
// Stack change
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitThrowStmt(ThrowStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfStmt(IfStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnStmt(ReturnStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnExprStmt(ReturnExprStmt stmt) { |
||||||
|
// Branch
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(stmt + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
// Can change a variable visible outside the method.
|
||||||
|
if (!(expr.target() instanceof LocalExpr)) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println(expr + " is prelive"); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(expr); |
||||||
|
|
||||||
|
} else { |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// Go through the nodes in the worklist and make the nodes that
|
||||||
|
// defined the VarExprs live.
|
||||||
|
while (!worklist.isEmpty()) { |
||||||
|
VarExpr expr = (VarExpr) worklist.removeFirst(); |
||||||
|
|
||||||
|
DefExpr def = expr.def(); |
||||||
|
|
||||||
|
if (def != null) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live def of " + expr); |
||||||
|
System.out.println(" def = " + def); |
||||||
|
} |
||||||
|
|
||||||
|
makeLive(def.parent()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Remove dead stores.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
Expr lhs = expr.target(); |
||||||
|
Expr rhs = expr.expr(); |
||||||
|
|
||||||
|
if (lhs.key() == DEAD && rhs.key() == LIVE) { |
||||||
|
rhs.setParent(null); |
||||||
|
expr.replaceWith(rhs, false); |
||||||
|
|
||||||
|
lhs.cleanup(); |
||||||
|
expr.cleanupOnly(); |
||||||
|
|
||||||
|
lhs.setKey(DEAD); |
||||||
|
expr.setKey(DEAD); |
||||||
|
|
||||||
|
rhs.visit(this); |
||||||
|
|
||||||
|
} else { |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// Pull out live expressions from their dead parents. Gee, Nate,
|
||||||
|
// what a lovely sentiment. I'll think I'll send that one to
|
||||||
|
// Hallmark.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitStmt(Stmt stmt) { |
||||||
|
if (stmt.key() == DEAD) { |
||||||
|
stmt.visitChildren(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
if (expr.key() == DEAD) { |
||||||
|
expr.visitChildren(this); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
Node parent = expr.parent(); |
||||||
|
|
||||||
|
if (parent.key() == LIVE) { |
||||||
|
// expr will removed later
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (parent instanceof ExprStmt) { |
||||||
|
// The expr and its parent are both dead, but expr
|
||||||
|
// resides
|
||||||
|
// in an ExprStmt. We want the parent after all.
|
||||||
|
parent.setKey(LIVE); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// We are going to remove the expr's parent, but keep the
|
||||||
|
// expr. Add eval(expr) [ExprStmt] before the stmt containing
|
||||||
|
// the expr. This is safe, since any exprs to the left in the
|
||||||
|
// statement's tree which are live have already been
|
||||||
|
// extracted.
|
||||||
|
|
||||||
|
Stmt oldStmt = expr.stmt(); |
||||||
|
|
||||||
|
Tree tree = parent.block().tree(); |
||||||
|
|
||||||
|
// Replace the expr with an unused stack expr.
|
||||||
|
StackExpr t = tree.newStack(expr.type()); |
||||||
|
expr.replaceWith(t, false); |
||||||
|
t.setValueNumber(expr.valueNumber()); |
||||||
|
|
||||||
|
ExprStmt stmt = new ExprStmt(expr); |
||||||
|
stmt.setValueNumber(expr.valueNumber()); |
||||||
|
stmt.setKey(LIVE); |
||||||
|
|
||||||
|
tree.addStmtBefore(stmt, oldStmt); |
||||||
|
|
||||||
|
// The old statement is dead and will be removed later.
|
||||||
|
Assert.isTrue(oldStmt.key() == DEAD, oldStmt |
||||||
|
+ " should be dead"); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// Finally, remove the dead statements from the Tree.
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitTree(Tree tree) { |
||||||
|
Iterator e = tree.stmts().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Stmt stmt = (Stmt) e.next(); |
||||||
|
|
||||||
|
if (stmt.key() == DEAD) { |
||||||
|
if (stmt instanceof LabelStmt) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (stmt instanceof JumpStmt) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Removing DEAD " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
e.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
worklist = null; |
||||||
|
} |
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Make all of a statement's children LIVE. I don't think its used.
|
||||||
|
// *
|
||||||
|
// * @param stmt
|
||||||
|
// * A statement whose children to make live.
|
||||||
|
// */
|
||||||
|
// void reviveStmt(Stmt stmt) {
|
||||||
|
// stmt.visit(new TreeVisitor() {
|
||||||
|
// public void visitExpr(Expr expr) {
|
||||||
|
// expr.setKey(LIVE);
|
||||||
|
// expr.visitChildren(this);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
/** |
||||||
|
* Make a node and all of its children (recursively) LIVE. |
||||||
|
* |
||||||
|
* @param node |
||||||
|
* A node to make LIVE. |
||||||
|
*/ |
||||||
|
void makeLive(Node node) { |
||||||
|
|
||||||
|
if (node instanceof StoreExpr) { |
||||||
|
// Make the StoreExpr, its target, and its RHS live. Add the
|
||||||
|
// target and the RHS to the worklist.
|
||||||
|
|
||||||
|
StoreExpr expr = (StoreExpr) node; |
||||||
|
|
||||||
|
if (expr.key() == DEAD) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live " + expr + " in " |
||||||
|
+ expr.parent()); |
||||||
|
} |
||||||
|
|
||||||
|
expr.setKey(LIVE); |
||||||
|
} |
||||||
|
|
||||||
|
if (expr.target().key() == DEAD) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live " + expr.target() + " in " |
||||||
|
+ expr); |
||||||
|
} |
||||||
|
|
||||||
|
expr.target().setKey(LIVE); |
||||||
|
|
||||||
|
if (expr.target() instanceof VarExpr) { |
||||||
|
worklist.add(expr.target()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (expr.expr().key() == DEAD) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live " + expr.expr() + " in " |
||||||
|
+ expr); |
||||||
|
} |
||||||
|
|
||||||
|
expr.expr().setKey(LIVE); |
||||||
|
|
||||||
|
if (expr.expr() instanceof VarExpr) { |
||||||
|
worklist.add(expr.expr()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (node instanceof Expr) { |
||||||
|
// If one expression inside an ExprStmt is live, then the entire
|
||||||
|
// ExprStmt is live.
|
||||||
|
Node parent = ((Expr) node).parent(); |
||||||
|
|
||||||
|
if (parent instanceof ExprStmt) { |
||||||
|
node = parent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
node.visit(new TreeVisitor() { |
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
// Don't make local variable targets live yet. If the
|
||||||
|
// variable is used in a live expression, the target will be
|
||||||
|
// made live later.
|
||||||
|
if (expr.target() instanceof LocalExpr) { |
||||||
|
expr.expr().visit(this); |
||||||
|
|
||||||
|
} else { |
||||||
|
visitExpr(expr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
if (expr.key() == DEAD) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live " + expr + " in " |
||||||
|
+ expr.parent()); |
||||||
|
} |
||||||
|
|
||||||
|
expr.setKey(LIVE); |
||||||
|
worklist.add(expr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
if (expr.key() == DEAD) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live " + expr + " in " |
||||||
|
+ expr.parent()); |
||||||
|
} |
||||||
|
|
||||||
|
expr.setKey(LIVE); |
||||||
|
} |
||||||
|
|
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStmt(Stmt stmt) { |
||||||
|
if (stmt.key() == DEAD) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("making live " + stmt); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.setKey(LIVE); |
||||||
|
} |
||||||
|
|
||||||
|
stmt.visitChildren(this); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Dead Code Elimination: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return "---Before Dead Code Elimination--"; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return "---After Dead Code Elimination---"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,301 @@ |
|||||||
|
/* |
||||||
|
* Class: ExprPropagation |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import java.util.Iterator; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.LeafExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MemExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ReplaceVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.Stmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs copy and constant propagation on the blocks in a control flow graph. |
||||||
|
*/ |
||||||
|
public class ExprPropagation implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
FlowGraph cfg; |
||||||
|
|
||||||
|
boolean changed; // Did the cfg change?
|
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
transform(state.controlFlowGraph()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs the propagation. |
||||||
|
*/ |
||||||
|
private void transform(FlowGraph cfg) { |
||||||
|
this.cfg = cfg; |
||||||
|
changed = true; |
||||||
|
|
||||||
|
while (changed) { |
||||||
|
changed = false; |
||||||
|
propagate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Propagate expressions through the control flow graph in hopes of reducing |
||||||
|
* the number of local variables. |
||||||
|
*/ |
||||||
|
private void propagate() { |
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
Iterator iter; |
||||||
|
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
iter = tree.stmts().iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Stmt stmt = (Stmt) iter.next(); |
||||||
|
stmt.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
expr.visitChildren(this); |
||||||
|
|
||||||
|
if (!(expr.target() instanceof LocalExpr)) { |
||||||
|
// If we're not assigning to a local variable, fergit it
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
LocalExpr lhs = (LocalExpr) expr.target(); |
||||||
|
Expr rhs = expr.expr(); |
||||||
|
|
||||||
|
// L := (M := E)
|
||||||
|
// use L
|
||||||
|
// use M
|
||||||
|
//
|
||||||
|
// -->
|
||||||
|
//
|
||||||
|
// L := E
|
||||||
|
// use L
|
||||||
|
// use L
|
||||||
|
//
|
||||||
|
// Since we've already visited (M := E), M could not be
|
||||||
|
// eliminated. So, after propagating M to L, we won't be
|
||||||
|
// able to eliminate L either, so don't even try.
|
||||||
|
//
|
||||||
|
if (rhs instanceof StoreExpr) { |
||||||
|
StoreExpr store = (StoreExpr) rhs; |
||||||
|
|
||||||
|
MemExpr rhsLHS = store.target(); |
||||||
|
Expr rhsRHS = store.expr(); |
||||||
|
|
||||||
|
if (rhsLHS instanceof LocalExpr) { |
||||||
|
// Replace uses of M with L.
|
||||||
|
|
||||||
|
// We need to make a copy of the lhs since it is a
|
||||||
|
// def an consequently does not contain a pointer to
|
||||||
|
// a def.
|
||||||
|
LocalExpr copy = (LocalExpr) lhs.clone(); |
||||||
|
copy.setDef(lhs); |
||||||
|
|
||||||
|
if (propExpr(expr.block(), (LocalExpr) rhsLHS, copy)) { |
||||||
|
// If all uses of the rhsRHS local variable were
|
||||||
|
// replaced, replace all occurrences of the rhs
|
||||||
|
// with the
|
||||||
|
// local variable of rhsRHS.
|
||||||
|
changed = true; |
||||||
|
|
||||||
|
expr.visit(new ReplaceVisitor(rhs, rhsRHS)); |
||||||
|
rhsLHS.cleanup(); |
||||||
|
rhs.cleanupOnly(); |
||||||
|
} |
||||||
|
|
||||||
|
// Be sure to cleanup the copy.
|
||||||
|
copy.cleanup(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
// This next part is awful and comented out. Propagating
|
||||||
|
// local variables like this fails to take into account
|
||||||
|
// the live ranges. When we have L := M, it replaces L with
|
||||||
|
// M after M has been overwritten. Arg.
|
||||||
|
/* |
||||||
|
* else if (rhs instanceof LeafExpr) { if |
||||||
|
* (propExpr(expr.block(), lhs, rhs)) { // If all uses of the
|
||||||
|
* local variable in the lhs were // replaced with the LeafExpr
|
||||||
|
* in the rhs, then the store // (L := X) is useless. Replace it
|
||||||
|
* with (eval X) so it // can be removed later. changed = true; //
|
||||||
|
* Replace eval (L := X) with eval X // Dead code elimination
|
||||||
|
* will remove it. if (expr.parent() instanceof ExprStmt) |
||||||
|
* iter.remove(); else expr.replaceWith((Expr) rhs.clone()); } } |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiStmt(PhiStmt stmt) { |
||||||
|
Expr lhs = stmt.target(); |
||||||
|
|
||||||
|
if (!(lhs instanceof LocalExpr)) { |
||||||
|
// If we're not assigning into a local variable, fergit
|
||||||
|
// it
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Look at all of the operands of the PhiStmt. If all of the
|
||||||
|
// operands are either the same local variable or the same
|
||||||
|
// constant, then propagate an operand (doesn't matter which
|
||||||
|
// one because they're all the same value) to all uses of the
|
||||||
|
// target of the PhiStmt.
|
||||||
|
Iterator e = stmt.operands().iterator(); |
||||||
|
|
||||||
|
if (!e.hasNext()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
Expr rhs = (Expr) e.next(); |
||||||
|
|
||||||
|
if (!(rhs instanceof LeafExpr)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Expr operand = (Expr) e.next(); |
||||||
|
|
||||||
|
if (rhs instanceof LocalExpr) { |
||||||
|
if (operand instanceof LocalExpr) { |
||||||
|
if (rhs.def() != operand.def()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} else { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
} else if (rhs instanceof ConstantExpr) { |
||||||
|
if (!rhs.equalsExpr(operand)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (propExpr(stmt.block(), (LocalExpr) lhs, rhs)) { |
||||||
|
// If all uses of the PhiStmt's target were replaced,
|
||||||
|
// remove
|
||||||
|
// it from the expression tree.
|
||||||
|
changed = true; |
||||||
|
iter.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Propagates the expression in rhs to all uses of the lhs. Returns true, if |
||||||
|
* all of the uses of the lhs were replaced. |
||||||
|
*/ |
||||||
|
boolean propExpr(Block block, LocalExpr lhs, Expr rhs) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("prop " + rhs + " to uses of " + lhs); |
||||||
|
System.out.println(" uses of lhs = " + lhs.uses()); |
||||||
|
} |
||||||
|
|
||||||
|
if (rhs instanceof LocalExpr) { |
||||||
|
// We can't prop a local to a PhiStmt operand, so don't bother
|
||||||
|
// doing the propagation at all.
|
||||||
|
Iterator e = lhs.uses().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
LocalExpr use = (LocalExpr) e.next(); |
||||||
|
|
||||||
|
if (use.parent() instanceof PhiStmt) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Replaces all uses of the lhs with the rhs. Both are local
|
||||||
|
// variables.
|
||||||
|
e = lhs.uses().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
LocalExpr use = (LocalExpr) e.next(); |
||||||
|
use.replaceWith((Expr) rhs.clone()); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
|
||||||
|
} else { |
||||||
|
boolean replacedAll = true; |
||||||
|
|
||||||
|
Iterator e = lhs.uses().iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
LocalExpr use = (LocalExpr) e.next(); |
||||||
|
|
||||||
|
if (use.parent() instanceof PhiCatchStmt) { |
||||||
|
replacedAll = false; |
||||||
|
} else { |
||||||
|
use.replaceWith((Expr) rhs.clone()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return replacedAll; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Copy propagation: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return "-----Before Copy Propagation-----"; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return "------After Copy Propagation-----"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms are permitted
|
||||||
|
# provided that this entire copyright notice is duplicated in all such
|
||||||
|
# copies, and that any documentation, announcements, and other
|
||||||
|
# materials related to such distribution and use acknowledge that the
|
||||||
|
# software was developed at Purdue University, West Lafayette, IN by
|
||||||
|
# Antony Hosking, David Whitlock, and Nathaniel Nystrom. No charge
|
||||||
|
# may be made for copies, derivations, or distributions of this
|
||||||
|
# material without the express written consent of the copyright
|
||||||
|
# holder. Neither the name of the University nor the name of the
|
||||||
|
# author may be used to endorse or promote products derived from this
|
||||||
|
# material without specific prior written permission. THIS SOFTWARE
|
||||||
|
# IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
# Java is a trademark of Sun Microsystems, Inc.
|
||||||
|
|
||||||
|
CLASS = \
|
||||||
|
CompactArrayInitializer.class\
|
||||||
|
DeadCodeElimination.class\
|
||||||
|
ExprPropagation.class\
|
||||||
|
NodeComparator.class\
|
||||||
|
Peephole.class\
|
||||||
|
SSAPRE.class\
|
||||||
|
SideEffectChecker.class\
|
||||||
|
StackPRE.class\
|
||||||
|
ValueFolder.class\
|
||||||
|
ValueFolding.class\
|
||||||
|
ValueNumbering.class
|
||||||
|
#PersistentCheckElimination.class\
|
||||||
|
|
||||||
|
include ../class.mk |
@ -0,0 +1,594 @@ |
|||||||
|
/* |
||||||
|
* Class: NodeComparator |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.tree.AddressStoreStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ArithExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayLengthExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallMethodExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallStaticExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CastExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CatchExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ExprStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.FieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.GotoStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.IfCmpStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.IfZeroStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.InitStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.InstanceOfExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.JsrStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.LabelStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MonitorStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.NegExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiJoinStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.RCExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.RetStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ReturnAddressExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ReturnExprStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ReturnStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SCStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.SRStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ShiftExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackManipStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StaticFieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.SwitchStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.ThrowStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.UCExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ZeroCheckExpr; |
||||||
|
|
||||||
|
/** |
||||||
|
* NodeComparator is a class used to differentiate nodes in an expression tree. |
||||||
|
*/ |
||||||
|
public class NodeComparator { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines whether or not two <tt>Node</tt>s are equal. |
||||||
|
*/ |
||||||
|
public static boolean equals(final Node v, final Node w) { |
||||||
|
class Bool { |
||||||
|
boolean value = false; |
||||||
|
} |
||||||
|
; |
||||||
|
|
||||||
|
final Bool eq = new Bool(); |
||||||
|
|
||||||
|
v.visit(new TreeVisitor() { |
||||||
|
public void visitExprStmt(ExprStmt stmt) { |
||||||
|
if (w instanceof ExprStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfCmpStmt(IfCmpStmt stmt) { |
||||||
|
if (w instanceof IfCmpStmt) { |
||||||
|
IfCmpStmt s = (IfCmpStmt) w; |
||||||
|
eq.value = stmt.trueTarget() == s.trueTarget() |
||||||
|
&& stmt.falseTarget() == s.falseTarget() |
||||||
|
&& stmt.comparison() == s.comparison(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfZeroStmt(IfZeroStmt stmt) { |
||||||
|
if (w instanceof IfZeroStmt) { |
||||||
|
IfZeroStmt s = (IfZeroStmt) w; |
||||||
|
eq.value = stmt.trueTarget() == s.trueTarget() |
||||||
|
&& stmt.falseTarget() == s.falseTarget() |
||||||
|
&& stmt.comparison() == s.comparison(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt stmt) { |
||||||
|
if (w instanceof SCStmt) { |
||||||
|
SCStmt s = (SCStmt) w; |
||||||
|
eq.value = stmt.array() == s.array() |
||||||
|
&& stmt.index() == s.index(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSRStmt(SRStmt stmt) { |
||||||
|
if (w instanceof SRStmt) { |
||||||
|
SRStmt s = (SRStmt) w; |
||||||
|
eq.value = stmt.array() == s.array() |
||||||
|
&& stmt.start() == s.start() |
||||||
|
&& stmt.end() == s.end(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
if (w instanceof InitStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
if (w instanceof GotoStmt) { |
||||||
|
GotoStmt s = (GotoStmt) w; |
||||||
|
eq.value = stmt.target() == s.target(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLabelStmt(LabelStmt stmt) { |
||||||
|
if (w instanceof LabelStmt) { |
||||||
|
LabelStmt s = (LabelStmt) w; |
||||||
|
eq.value = stmt.label().equals(s.label()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitMonitorStmt(MonitorStmt stmt) { |
||||||
|
if (w instanceof MonitorStmt) { |
||||||
|
MonitorStmt s = (MonitorStmt) w; |
||||||
|
eq.value = stmt.kind() == s.kind(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiJoinStmt(PhiJoinStmt stmt) { |
||||||
|
if (w instanceof PhiJoinStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiCatchStmt(PhiCatchStmt stmt) { |
||||||
|
if (w instanceof PhiCatchStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
// Catches are not equivalent.
|
||||||
|
eq.value = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
if (w instanceof StackManipStmt) { |
||||||
|
StackManipStmt s = (StackManipStmt) w; |
||||||
|
eq.value = stmt.kind() == s.kind(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
if (w instanceof RetStmt) { |
||||||
|
RetStmt s = (RetStmt) w; |
||||||
|
eq.value = stmt.sub() == s.sub(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnExprStmt(ReturnExprStmt stmt) { |
||||||
|
if (w instanceof ReturnExprStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnStmt(ReturnStmt stmt) { |
||||||
|
if (w instanceof ReturnStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitAddressStoreStmt(AddressStoreStmt stmt) { |
||||||
|
if (w instanceof AddressStoreStmt) { |
||||||
|
AddressStoreStmt s = (AddressStoreStmt) w; |
||||||
|
eq.value = stmt.sub() == s.sub(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
if (w instanceof StoreExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
if (w instanceof JsrStmt) { |
||||||
|
JsrStmt s = (JsrStmt) w; |
||||||
|
eq.value = stmt.sub() == s.sub(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
if (w instanceof SwitchStmt) { |
||||||
|
eq.value = stmt == w; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitThrowStmt(ThrowStmt stmt) { |
||||||
|
if (w instanceof ThrowStmt) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArithExpr(ArithExpr expr) { |
||||||
|
if (w instanceof ArithExpr) { |
||||||
|
ArithExpr e = (ArithExpr) w; |
||||||
|
eq.value = e.operation() == expr.operation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
if (w instanceof ArrayLengthExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
if (w instanceof ArrayRefExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
// Calls are never equal.
|
||||||
|
eq.value = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
// Calls are never equal.
|
||||||
|
eq.value = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
if (w instanceof CastExpr) { |
||||||
|
CastExpr e = (CastExpr) w; |
||||||
|
eq.value = e.castType().equals(expr.castType()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitConstantExpr(ConstantExpr expr) { |
||||||
|
if (w instanceof ConstantExpr) { |
||||||
|
ConstantExpr e = (ConstantExpr) w; |
||||||
|
if (e.value() == null) { |
||||||
|
eq.value = expr.value() == null; |
||||||
|
} else { |
||||||
|
eq.value = e.value().equals(expr.value()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
if (w instanceof FieldExpr) { |
||||||
|
FieldExpr e = (FieldExpr) w; |
||||||
|
eq.value = e.field().equals(expr.field()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInstanceOfExpr(InstanceOfExpr expr) { |
||||||
|
if (w instanceof InstanceOfExpr) { |
||||||
|
InstanceOfExpr e = (InstanceOfExpr) w; |
||||||
|
eq.value = e.checkType().equals(expr.checkType()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLocalExpr(LocalExpr expr) { |
||||||
|
if (w instanceof LocalExpr) { |
||||||
|
LocalExpr e = (LocalExpr) w; |
||||||
|
eq.value = e.def() == expr.def(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNegExpr(NegExpr expr) { |
||||||
|
if (w instanceof NegExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
eq.value = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
eq.value = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
eq.value = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitZeroCheckExpr(ZeroCheckExpr expr) { |
||||||
|
if (w instanceof ZeroCheckExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRCExpr(RCExpr expr) { |
||||||
|
if (w instanceof RCExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitUCExpr(UCExpr expr) { |
||||||
|
if (w instanceof UCExpr) { |
||||||
|
UCExpr e = (UCExpr) w; |
||||||
|
eq.value = e.kind() == expr.kind(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnAddressExpr(ReturnAddressExpr expr) { |
||||||
|
if (w instanceof ReturnAddressExpr) { |
||||||
|
eq.value = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitShiftExpr(ShiftExpr expr) { |
||||||
|
if (w instanceof ShiftExpr) { |
||||||
|
ShiftExpr e = (ShiftExpr) w; |
||||||
|
eq.value = e.dir() == expr.dir(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackExpr(StackExpr expr) { |
||||||
|
if (w instanceof StackExpr) { |
||||||
|
StackExpr e = (StackExpr) w; |
||||||
|
eq.value = e.def() == expr.def(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr expr) { |
||||||
|
if (w instanceof StaticFieldExpr) { |
||||||
|
StaticFieldExpr e = (StaticFieldExpr) w; |
||||||
|
eq.value = e.field().equals(expr.field()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
throw new RuntimeException("No method for " + node); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return eq.value; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Computes a hash code for a given <tt>Node</tt> based upon its type. The |
||||||
|
* hash code of nodes that are composed of other nodes are based upon their |
||||||
|
* composits. |
||||||
|
*/ |
||||||
|
public static int hashCode(final Node node) { |
||||||
|
class Int { |
||||||
|
int value = 0; |
||||||
|
} |
||||||
|
; |
||||||
|
|
||||||
|
final Int hash = new Int(); |
||||||
|
|
||||||
|
node.visit(new TreeVisitor() { |
||||||
|
public void visitExprStmt(ExprStmt stmt) { |
||||||
|
hash.value = 1; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfCmpStmt(IfCmpStmt stmt) { |
||||||
|
hash.value = stmt.comparison() + stmt.trueTarget().hashCode() |
||||||
|
+ stmt.falseTarget().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfZeroStmt(IfZeroStmt stmt) { |
||||||
|
hash.value = stmt.comparison() + stmt.trueTarget().hashCode() |
||||||
|
+ stmt.falseTarget().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
hash.value = 2; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
hash.value = stmt.target().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLabelStmt(LabelStmt stmt) { |
||||||
|
hash.value = stmt.label().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitMonitorStmt(MonitorStmt stmt) { |
||||||
|
hash.value = stmt.kind(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiJoinStmt(PhiJoinStmt stmt) { |
||||||
|
hash.value = 3; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiCatchStmt(PhiCatchStmt stmt) { |
||||||
|
hash.value = 4; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
// Catches are not equivalent.
|
||||||
|
hash.value = expr.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
hash.value = stmt.kind(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
hash.value = 5; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnExprStmt(ReturnExprStmt stmt) { |
||||||
|
hash.value = 6; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnStmt(ReturnStmt stmt) { |
||||||
|
hash.value = 7; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitAddressStoreStmt(AddressStoreStmt stmt) { |
||||||
|
hash.value = 8; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
hash.value = 9; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
hash.value = 10; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
hash.value = 11; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitThrowStmt(ThrowStmt stmt) { |
||||||
|
hash.value = 12; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArithExpr(ArithExpr expr) { |
||||||
|
hash.value = expr.operation(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
hash.value = 13; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
hash.value = 14; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
// Calls are never equal.
|
||||||
|
hash.value = expr.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
// Calls are never equal.
|
||||||
|
hash.value = expr.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
hash.value = expr.castType().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitConstantExpr(ConstantExpr expr) { |
||||||
|
if (expr.value() == null) { |
||||||
|
hash.value = 0; |
||||||
|
} else { |
||||||
|
hash.value = expr.value().hashCode(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
hash.value = expr.field().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInstanceOfExpr(InstanceOfExpr expr) { |
||||||
|
hash.value = expr.checkType().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLocalExpr(LocalExpr expr) { |
||||||
|
if (expr.def() != null) { |
||||||
|
hash.value = expr.def().hashCode(); |
||||||
|
} else { |
||||||
|
hash.value = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNegExpr(NegExpr expr) { |
||||||
|
hash.value = 16; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
hash.value = expr.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
hash.value = expr.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
hash.value = expr.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitZeroCheckExpr(ZeroCheckExpr expr) { |
||||||
|
hash.value = 15; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRCExpr(RCExpr expr) { |
||||||
|
hash.value = 17; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitUCExpr(UCExpr expr) { |
||||||
|
hash.value = 18 + expr.kind(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnAddressExpr(ReturnAddressExpr expr) { |
||||||
|
hash.value = 21; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt stmt) { |
||||||
|
hash.value = 23; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitSRStmt(SRStmt stmt) { |
||||||
|
hash.value = 22; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitShiftExpr(ShiftExpr expr) { |
||||||
|
hash.value = expr.dir(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackExpr(StackExpr expr) { |
||||||
|
if (expr.def() != null) { |
||||||
|
hash.value = expr.def().hashCode(); |
||||||
|
} else { |
||||||
|
hash.value = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr expr) { |
||||||
|
hash.value = expr.field().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
throw new RuntimeException("No method for " + node); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return hash.value; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,978 @@ |
|||||||
|
/* |
||||||
|
* Class: Peephole |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs some peephole optimizations such as loads and stores and removes |
||||||
|
* unreachable instructions. |
||||||
|
*/ |
||||||
|
|
||||||
|
public class Peephole implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
this.transform(state.methodGen(), true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Perform peephole optimizations on the bytecodes in a method. Peephole |
||||||
|
* optimizations look at two consecutive instructions and try to perform |
||||||
|
* some simple optimization. For instance, a push followed by a pop is |
||||||
|
* uninteresting, so both of those instructions can be removed. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* After the peephole optimizations are performed a final phase removes |
||||||
|
* instructions that are not reachable. These instructions reside in basic |
||||||
|
* blocks whose starting label is never jumped to. |
||||||
|
*/ |
||||||
|
|
||||||
|
// Peephole can work on any bytecode sequence it does not have to be a
|
||||||
|
// result of calls
|
||||||
|
// to CodeGenerator. However, if Peephole will need to have labels denoting
|
||||||
|
// the start
|
||||||
|
// of basic blocks, if the code is not the result of output from
|
||||||
|
// CodeGenerator then labels
|
||||||
|
// will not be intact set "labels" to false if this is the case and they can
|
||||||
|
// be placed using
|
||||||
|
// FlowGraph.buildBLOATInstructionList(MethodGen) --Arrin
|
||||||
|
public void transform(MethodGen method, boolean labels) { |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Peephole optimizing " + method); |
||||||
|
} |
||||||
|
|
||||||
|
// Map between labels and the instruction that they label
|
||||||
|
Map targets = new LinkedHashMap(); |
||||||
|
|
||||||
|
LinkedList jumps = new LinkedList(); // Jump instructions
|
||||||
|
|
||||||
|
Instruction next = null; |
||||||
|
|
||||||
|
InstructionList code = method.getInstructionList(); |
||||||
|
// Do we need to build the labels are they already intact?
|
||||||
|
if (!labels) |
||||||
|
FlowGraph.buildBLOATInstructionList(method); |
||||||
|
|
||||||
|
InstructionHandle ih = null; |
||||||
|
// Go backwards so we can eliminate redundant loads and stores
|
||||||
|
// in one pass. During the pass collect the locations of labels.
|
||||||
|
boolean canFilter = true; |
||||||
|
CODE: for (ih = code.getEnd(); ih != code.getStart(); ih = ih.getPrev()) { |
||||||
|
|
||||||
|
if (FlowGraph.label(ih)) { |
||||||
|
targets.put(ih, ih.getInstruction()); |
||||||
|
} |
||||||
|
|
||||||
|
// All items are Instructions now
|
||||||
|
Instruction inst = ih.getInstruction(); |
||||||
|
|
||||||
|
Filter peep = null; |
||||||
|
|
||||||
|
// Have we seen a label that starts a block? (i.e. is a target)
|
||||||
|
boolean seenLabel = false; |
||||||
|
|
||||||
|
if (inst instanceof GotoInstruction) { |
||||||
|
// Look at the instructions following the goto. If an
|
||||||
|
// instruction follows and no label (that starts a block)
|
||||||
|
// has been seen, the instruction is dead and can be
|
||||||
|
// removed. If the target of the goto follows the goto
|
||||||
|
// instruction, the goto is useless and is removed.
|
||||||
|
|
||||||
|
InstructionHandle target = ((GotoInstruction) inst).getTarget(); |
||||||
|
|
||||||
|
for (InstructionHandle j = ih.getNext(); j != null; j = j |
||||||
|
.getNext()) { |
||||||
|
|
||||||
|
// Replace
|
||||||
|
// goto L
|
||||||
|
// L: inst
|
||||||
|
// with
|
||||||
|
// L: inst
|
||||||
|
//
|
||||||
|
if (FlowGraph.label(j)) { |
||||||
|
// if (((Label) t).startsBlock()) {
|
||||||
|
// All labels start a block now
|
||||||
|
seenLabel = true; |
||||||
|
|
||||||
|
if (target.equals(j)) { |
||||||
|
InstructionHandle toDelete = ih; |
||||||
|
ih = ih.getNext(); |
||||||
|
try { |
||||||
|
code.delete(toDelete); |
||||||
|
next = null; |
||||||
|
} catch (TargetLostException tle) { |
||||||
|
InstructionHandle[] losttargets = tle |
||||||
|
.getTargets(); |
||||||
|
for (int i = 0; i < losttargets.length; i++) { |
||||||
|
InstructionTargeter[] targeters = losttargets[i] |
||||||
|
.getTargeters(); |
||||||
|
|
||||||
|
for (int k = 0; k < targeters.length; k++) |
||||||
|
targeters[k].updateTarget( |
||||||
|
losttargets[i], j); |
||||||
|
} |
||||||
|
// Redirect Lost targeters
|
||||||
|
} |
||||||
|
continue CODE; |
||||||
|
} |
||||||
|
if (Peephole.DEBUG) |
||||||
|
System.out.println("Not a target instruction : " |
||||||
|
+ j.getInstruction()); |
||||||
|
// Now we want to look at the instruction
|
||||||
|
// continue;
|
||||||
|
} |
||||||
|
|
||||||
|
// Replace
|
||||||
|
// goto L
|
||||||
|
// this is unreachable
|
||||||
|
// M: inst (M is a different label from L!)
|
||||||
|
// with
|
||||||
|
// goto L
|
||||||
|
// M: inst
|
||||||
|
//
|
||||||
|
// if (!FlowGraph.label(j)) {
|
||||||
|
if (seenLabel) { |
||||||
|
break; |
||||||
|
} |
||||||
|
InstructionHandle j2 = j; |
||||||
|
j = j.getPrev(); |
||||||
|
try { |
||||||
|
code.delete(j2); // Delete an unreachable instruction
|
||||||
|
} catch (TargetLostException tle) { |
||||||
|
System.out.println("Got a lost Target!!!!!!!"); |
||||||
|
// fail quitely
|
||||||
|
} |
||||||
|
|
||||||
|
// }
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (inst instanceof GotoInstruction || inst instanceof Select |
||||||
|
|| inst instanceof IfInstruction) { |
||||||
|
jumps.add(ih); |
||||||
|
} |
||||||
|
|
||||||
|
// Performs some peephole optimizations using the filter
|
||||||
|
// method that returns an instance of the Filter class. The
|
||||||
|
// filter method looks at two consecutive instructions and
|
||||||
|
// determines whether or not something about them can be
|
||||||
|
// changed. For instance, if a push is followed by a pop,
|
||||||
|
// both instructions are useless and can be eliminated. The
|
||||||
|
// contents of the Filter object represents the effects of the
|
||||||
|
// peephole optimization.
|
||||||
|
if (next != null && canFilter) { |
||||||
|
peep = filter(inst, next, method); |
||||||
|
} |
||||||
|
|
||||||
|
if (peep != null) { |
||||||
|
if (Peephole.DEBUG) { |
||||||
|
if (peep.replace.length == 0) { |
||||||
|
System.out.println("eliminate " + ih.getInstruction() |
||||||
|
+ "-" + ih.getNext().getInstruction()); |
||||||
|
|
||||||
|
} else { |
||||||
|
System.out.println("replace " + ih.getInstruction() |
||||||
|
+ "-" + ih.getNext().getInstruction()); |
||||||
|
System.out.println(" with"); |
||||||
|
for (int j = 0; j < peep.replace.length; j++) { |
||||||
|
System.out.println(" " + peep.replace[j]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
InstructionHandle oldIh = ih; |
||||||
|
ih = ih.getPrev(); |
||||||
|
InstructionHandle redirectTo = ih.getNext().getNext(); |
||||||
|
// if no Instruction is added redirect to after the deleted
|
||||||
|
// instructions
|
||||||
|
if (ih == null) {// we are at the start of the
|
||||||
|
// InstructionList
|
||||||
|
// Add instructions resulting from peephole optimizations
|
||||||
|
for (int j = peep.replace.length - 1; j >= 0; j--) { |
||||||
|
if (peep.replace[j] instanceof BranchInstruction) |
||||||
|
redirectTo = code |
||||||
|
.insert((BranchInstruction) peep.replace[j]); |
||||||
|
else |
||||||
|
// UGH BCEL treats Branch instructions differently
|
||||||
|
redirectTo = code.insert(peep.replace[j]); |
||||||
|
// break;
|
||||||
|
} |
||||||
|
} else { |
||||||
|
for (int j = peep.replace.length - 1; j >= 0; j--) { |
||||||
|
if (peep.replace[j] instanceof BranchInstruction) |
||||||
|
redirectTo = code.append(ih, |
||||||
|
(BranchInstruction) peep.replace[j]); |
||||||
|
else |
||||||
|
// UGH BCEL treats Branch instructions differently
|
||||||
|
redirectTo = code.append(ih, peep.replace[j]); |
||||||
|
} |
||||||
|
} |
||||||
|
try { |
||||||
|
// Remove old instructions
|
||||||
|
code.delete(oldIh.getNext()); |
||||||
|
code.delete(oldIh); |
||||||
|
} catch (TargetLostException tle) { |
||||||
|
FlowGraph.setLabel(redirectTo); // reinstate as a label.
|
||||||
|
InstructionHandle[] losttargets = tle.getTargets(); |
||||||
|
for (int i = 0; i < losttargets.length; i++) { |
||||||
|
InstructionTargeter[] targeters = losttargets[i] |
||||||
|
.getTargeters(); |
||||||
|
|
||||||
|
for (int j = 0; j < targeters.length; j++) |
||||||
|
targeters[j].updateTarget(losttargets[i], |
||||||
|
redirectTo); |
||||||
|
} |
||||||
|
// Redirect Lost targeters
|
||||||
|
} |
||||||
|
|
||||||
|
ih = ih.getNext();// This should be one of the added
|
||||||
|
// instructions if one was added.
|
||||||
|
if (ih != null && !FlowGraph.label(ih)) { |
||||||
|
next = ih.getInstruction(); |
||||||
|
|
||||||
|
} else { |
||||||
|
// No more instructions, or next thing is a label
|
||||||
|
next = null; |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
if (ih != null && !FlowGraph.label(ih)) { |
||||||
|
next = ih.getInstruction(); |
||||||
|
} else { |
||||||
|
next = null; |
||||||
|
} |
||||||
|
// Filter didn't find any peephole optimizations, skip to
|
||||||
|
// next pair of instructions.
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Peephole optimizing removing GOTOs"); |
||||||
|
} |
||||||
|
|
||||||
|
// Replace the target of jumps to gotos with the goto target.
|
||||||
|
// Replace gotos to unconditional jumps with the unconditional jump.
|
||||||
|
while (!jumps.isEmpty()) { |
||||||
|
InstructionHandle iHandle = (InstructionHandle) jumps.removeFirst(); |
||||||
|
InstructionHandle target; |
||||||
|
|
||||||
|
if ((iHandle.getInstruction() instanceof GotoInstruction) |
||||||
|
|| (iHandle.getInstruction() instanceof IfInstruction)) { |
||||||
|
BranchInstruction inst = (BranchInstruction) iHandle |
||||||
|
.getInstruction(); |
||||||
|
target = inst.getTarget(); |
||||||
|
if (target != null) { |
||||||
|
Instruction targetInst = target.getInstruction(); |
||||||
|
if (targetInst instanceof GotoInstruction |
||||||
|
&& !(((GotoInstruction) targetInst).getTarget() |
||||||
|
.equals(inst.getTarget()))) { |
||||||
|
// IF THIS WASN'T TRUE WOULDN'T IT MEAN WE HAVE A GOTO
|
||||||
|
// DIRECTED TO JUMP TO ITSELF?
|
||||||
|
if (Peephole.DEBUG) { |
||||||
|
System.out.println("replace " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
inst.setTarget(((GotoInstruction) targetInst) |
||||||
|
.getTarget()); |
||||||
|
|
||||||
|
if (Peephole.DEBUG) { |
||||||
|
System.out.println(" with " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
jumps.add(iHandle); |
||||||
|
|
||||||
|
} else if ((inst instanceof GotoInstruction) |
||||||
|
&& (targetInst instanceof Select || |
||||||
|
// targetInst instanceof ReturnInstruction ||
|
||||||
|
targetInst instanceof ATHROW)) { |
||||||
|
|
||||||
|
if (Peephole.DEBUG) { |
||||||
|
System.out.println("replace " + inst); |
||||||
|
} |
||||||
|
|
||||||
|
iHandle.setInstruction((BranchInstruction) targetInst |
||||||
|
.copy()); |
||||||
|
// THIS MIGHT BE BAD copy() IS A SHALLOW COPY!!
|
||||||
|
|
||||||
|
if (Peephole.DEBUG) { |
||||||
|
System.out.println(" with " + targetInst); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// Remove unreachable code.
|
||||||
|
removeUnreachable(method, code); |
||||||
|
|
||||||
|
Iterator iterhandles = method.getInstructionList().iterator(); |
||||||
|
while (iterhandles.hasNext()) { |
||||||
|
ih = (InstructionHandle) iterhandles.next(); |
||||||
|
ih.removeAttribute("Label"); |
||||||
|
} |
||||||
|
|
||||||
|
method.removeNOPs(); |
||||||
|
method.getInstructionList().setPositions(); |
||||||
|
method.setMaxStack(); |
||||||
|
method.setMaxLocals(); |
||||||
|
method.update(); |
||||||
|
|
||||||
|
if (Peephole.DEBUG) { |
||||||
|
System.out.println("END PEEPHOLE--------------------------------"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Iterate over the code in the method and determine which labels begin |
||||||
|
* blocks that are reachable. The code in blocks that are not reachable is |
||||||
|
* removed. |
||||||
|
*/ |
||||||
|
// TODO: Currently, ALL ret targets are marked reachable from a
|
||||||
|
// single ret. Correct this by looking at the local variables.
|
||||||
|
private void removeUnreachable(MethodGen method, InstructionList code) { |
||||||
|
// Maps Labels to their instruction position
|
||||||
|
Map labelPos = new LinkedHashMap(); |
||||||
|
|
||||||
|
// Collect all the ret targets.
|
||||||
|
Iterator iter = code.iterator(); |
||||||
|
int i = 0; |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
InstructionHandle ce = (InstructionHandle) iter.next(); |
||||||
|
|
||||||
|
if (FlowGraph.label(ce)) { |
||||||
|
labelPos.put(ce, new Integer(i)); |
||||||
|
} |
||||||
|
|
||||||
|
i++; |
||||||
|
} |
||||||
|
|
||||||
|
// Visit the blocks depth-first.
|
||||||
|
|
||||||
|
// Stack of Labels that begin blocks that have been visited
|
||||||
|
Set visited = new LinkedHashSet(); |
||||||
|
|
||||||
|
// Stack of Labels that begin blocks that have not been visited
|
||||||
|
Stack stack = new Stack(); |
||||||
|
|
||||||
|
InstructionHandle label; // Current label
|
||||||
|
|
||||||
|
if (code.getLength() > 0) { |
||||||
|
// Start with the label of the first block
|
||||||
|
label = (InstructionHandle) code.getStart(); |
||||||
|
visited.add(label); |
||||||
|
stack.push(label); |
||||||
|
} |
||||||
|
|
||||||
|
CodeExceptionGen[] excptns = method.getExceptionHandlers(); |
||||||
|
|
||||||
|
for (i = 0; i < excptns.length; i++) { |
||||||
|
// All exception handlers are considered to be live
|
||||||
|
visited.add(excptns[i].getHandlerPC()); |
||||||
|
stack.push(excptns[i].getHandlerPC()); |
||||||
|
} |
||||||
|
|
||||||
|
while (!stack.isEmpty()) { |
||||||
|
label = (InstructionHandle) stack.pop(); |
||||||
|
|
||||||
|
Integer labelIndex = (Integer) labelPos.get(label); |
||||||
|
Assert.isTrue(labelIndex != null, "Index of label_" |
||||||
|
+ label.getPosition() + " not found"); |
||||||
|
|
||||||
|
InstructionHandle blockIter = label; |
||||||
|
|
||||||
|
while (blockIter != null && blockIter.getNext() != null) { |
||||||
|
// Iterate over the code in the block. If we encounter
|
||||||
|
// instructions that change execution (i.e. go to another
|
||||||
|
// block), add the Label of the target of the jump to the
|
||||||
|
// stack if it is not already present.
|
||||||
|
|
||||||
|
blockIter = blockIter.getNext(); |
||||||
|
Instruction inst = blockIter.getInstruction(); |
||||||
|
|
||||||
|
if (!FlowGraph.label(blockIter)) { |
||||||
|
if (inst instanceof ReturnInstruction |
||||||
|
|| inst instanceof ATHROW) { |
||||||
|
// We've reached the end of the block, but we don't know
|
||||||
|
// which block will be executed next.
|
||||||
|
break; |
||||||
|
|
||||||
|
} else if (inst instanceof IfInstruction |
||||||
|
|| inst instanceof JsrInstruction) { |
||||||
|
// We've reached the end of the block, add the Label of
|
||||||
|
// the next block to be executed to the list. It's a
|
||||||
|
// conditional jump, so don't break. The rest of the
|
||||||
|
// code in the block is not necessarily dead.
|
||||||
|
|
||||||
|
label = ((BranchInstruction) inst).getTarget(); |
||||||
|
|
||||||
|
if (!visited.contains(label)) { |
||||||
|
visited.add(label); |
||||||
|
stack.push(label); |
||||||
|
} |
||||||
|
|
||||||
|
// Fall through.
|
||||||
|
|
||||||
|
} else if (inst instanceof GotoInstruction) { |
||||||
|
// Add next block to work list.
|
||||||
|
|
||||||
|
label = ((GotoInstruction) inst).getTarget(); |
||||||
|
|
||||||
|
if (!visited.contains(label)) { |
||||||
|
visited.add(label); |
||||||
|
stack.push(label); |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
} else if (inst instanceof RET) { |
||||||
|
// The ret targets were handled by the jsr.
|
||||||
|
break; |
||||||
|
|
||||||
|
} else if (inst instanceof Select) { |
||||||
|
// A switch. Add all possible targets of the switch to
|
||||||
|
// the worklist.
|
||||||
|
|
||||||
|
Select sw = (Select) inst; |
||||||
|
|
||||||
|
label = sw.getTarget(); |
||||||
|
if (!visited.contains(label)) { |
||||||
|
visited.add(label); |
||||||
|
stack.push(label); |
||||||
|
} |
||||||
|
|
||||||
|
InstructionHandle[] targets = sw.getTargets(); |
||||||
|
|
||||||
|
for (int j = 0; j < targets.length; j++) { |
||||||
|
label = targets[j]; |
||||||
|
|
||||||
|
if (!visited.contains(label)) { |
||||||
|
visited.add(label); |
||||||
|
stack.push(label); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
} |
||||||
|
} else if (FlowGraph.label(blockIter)) { |
||||||
|
label = blockIter; |
||||||
|
visited.add(label); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Done finding unreachable instructions"); |
||||||
|
} |
||||||
|
|
||||||
|
boolean reachable = false; |
||||||
|
|
||||||
|
iter = code.iterator(); |
||||||
|
|
||||||
|
// Remove unreachable instructions
|
||||||
|
while (iter.hasNext()) { |
||||||
|
InstructionHandle ce = (InstructionHandle) iter.next(); |
||||||
|
|
||||||
|
if (FlowGraph.label(ce)) { |
||||||
|
reachable = visited.contains(ce); |
||||||
|
// Don't remove unreachable labels, only instructions.
|
||||||
|
|
||||||
|
} |
||||||
|
if (!reachable) { |
||||||
|
if (Peephole.DEBUG) { |
||||||
|
System.out.println("Removing unreachable " + ce); |
||||||
|
} |
||||||
|
iter.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Filter represents a set of instructions that result from a peephole |
||||||
|
* optimizations. For instance, when uninteresting instructions are removed, |
||||||
|
* a Filter object with an empty "replace" array will be returned by the |
||||||
|
* below filter method. |
||||||
|
*/ |
||||||
|
static class Filter { |
||||||
|
Instruction[] replace; |
||||||
|
|
||||||
|
boolean[] labels; |
||||||
|
|
||||||
|
Filter() { |
||||||
|
this.replace = new Instruction[0]; |
||||||
|
} |
||||||
|
|
||||||
|
Filter(Instruction replace) { |
||||||
|
this.replace = new Instruction[] { replace }; |
||||||
|
} |
||||||
|
|
||||||
|
Filter(Instruction replace1, Instruction replace2) { |
||||||
|
this.replace = new Instruction[] { replace1, replace2 }; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Filter a pair of instructions. That is, do a peephole optimization on two |
||||||
|
* consecutive instructions. For instance, if a push is followed by a pop, |
||||||
|
* both instructions can be eliminated. The <tt>Filter</tt> object that is |
||||||
|
* returned specifies what instruction(s), if any, should replace the two |
||||||
|
* instructions that are the parameters to this method. |
||||||
|
* |
||||||
|
* @param first |
||||||
|
* The first instruction. |
||||||
|
* @param second |
||||||
|
* The second instruction. |
||||||
|
* @return A list of instructions to replace the two instructions with, or |
||||||
|
* null, if the instructions should be left as is. |
||||||
|
*/ |
||||||
|
private Filter filter(Instruction first, Instruction second, |
||||||
|
MethodGen method) { |
||||||
|
// switch (second.opcodeClass()) {
|
||||||
|
|
||||||
|
// swap means nothing if it's after a dup.
|
||||||
|
// (goodbye means nothing when it's all for show
|
||||||
|
// so stop pretending you've somewhere else to go.)
|
||||||
|
|
||||||
|
// case opcx_swap:
|
||||||
|
if (second instanceof SWAP) { |
||||||
|
// Elminate swap-swap
|
||||||
|
if (first instanceof SWAP) |
||||||
|
return new Filter(); |
||||||
|
// swap means nothing if it's after a dup.
|
||||||
|
// (goodbye means nothing when it's all for show
|
||||||
|
// so stop pretending you've somewhere else to go.)
|
||||||
|
if (first instanceof DUP) { |
||||||
|
return new Filter(first); |
||||||
|
} |
||||||
|
} else if (second instanceof POP) {// Eliminate push-pop.
|
||||||
|
// Eliminate push-pop.
|
||||||
|
|
||||||
|
// switch (first.opcodeClass()) {
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC f = (LDC) first; |
||||||
|
// Make sure things being popped off is not wide (we're
|
||||||
|
// dealing with a pop not a pop2).
|
||||||
|
Assert.isTrue(!(f.getType(method.getConstantPool()) |
||||||
|
.equals(Type.LONG)) |
||||||
|
&& !(f.getType(method.getConstantPool()) |
||||||
|
.equals(Type.DOUBLE)), |
||||||
|
"Cannot pop a 2-word operand"); |
||||||
|
return new Filter(); |
||||||
|
} else if ((first instanceof ILOAD) || (first instanceof FLOAD) |
||||||
|
|| (first instanceof ALOAD) || (first instanceof DUP)) { |
||||||
|
// Eliminate the load and the pop.
|
||||||
|
return new Filter(); |
||||||
|
} else if (first instanceof DUP_X1) { |
||||||
|
// Replace dup_x1-pop with swap
|
||||||
|
// (As if this is really likely to happen ;) <-- Nate made a
|
||||||
|
// joke!
|
||||||
|
System.out.println("HERE0 inserting SWAP"); |
||||||
|
return new Filter(new SWAP()); |
||||||
|
} |
||||||
|
} else if (second instanceof POP2) { |
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC f = (LDC) first; |
||||||
|
Assert.isTrue((f.getType(method.getConstantPool()) |
||||||
|
.equals(Type.LONG)) |
||||||
|
|| (f.getType(method.getConstantPool()) |
||||||
|
.equals(Type.DOUBLE)), |
||||||
|
"Cannot pop2 a 1-word operand"); |
||||||
|
return new Filter(); |
||||||
|
} else if ((first instanceof LLOAD) || (first instanceof DLOAD) |
||||||
|
|| (first instanceof DUP2)) { |
||||||
|
// Eliminate push and pop
|
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} else if (second instanceof ISTORE) { |
||||||
|
StoreInstruction secnd = (StoreInstruction) second; |
||||||
|
// Eliminate load-store to same location.
|
||||||
|
if (first instanceof ILOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof FSTORE) { |
||||||
|
StoreInstruction secnd = (StoreInstruction) second; |
||||||
|
if (first instanceof FLOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof ASTORE) { |
||||||
|
StoreInstruction secnd = (StoreInstruction) second; |
||||||
|
if (first instanceof ALOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof LSTORE) { |
||||||
|
StoreInstruction secnd = (StoreInstruction) second; |
||||||
|
if (first instanceof LLOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof DSTORE) { |
||||||
|
StoreInstruction secnd = (StoreInstruction) second; |
||||||
|
if (first instanceof DLOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof ReturnInstruction) { |
||||||
|
// THIS APPLIES FOR RETURN TOO RIGHT?
|
||||||
|
// Replace store-return with return. Remember that upon return
|
||||||
|
// all local variables revert to their pre-call values, so any
|
||||||
|
// stores are destroyed.
|
||||||
|
if (first instanceof StoreInstruction) { |
||||||
|
return new Filter(second); |
||||||
|
} |
||||||
|
} else if (second instanceof IADD) { |
||||||
|
// Replace ineg-iadd with isub
|
||||||
|
if (first instanceof INEG) { |
||||||
|
return new Filter(new ISUB()); |
||||||
|
} |
||||||
|
} else if (second instanceof ISUB) { |
||||||
|
// Replace ineg-isub with iadd
|
||||||
|
if (first instanceof INEG) { |
||||||
|
return new Filter(new IADD()); |
||||||
|
} |
||||||
|
} else if (second instanceof LADD) { |
||||||
|
// Replace lneg-ladd with lsub
|
||||||
|
if (first instanceof LNEG) { |
||||||
|
return new Filter(new LSUB()); |
||||||
|
} |
||||||
|
} else if (second instanceof LSUB) { |
||||||
|
// Replace lneg-lsub with ladd
|
||||||
|
if (first instanceof LNEG) { |
||||||
|
return new Filter(new LADD()); |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ICMPEQ) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-if_icmpeq with ifeq
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new IFEQ(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ICMPNE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-if_icmpne with ifne
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new IFNE(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ICMPLT) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-if_icmplt with iflt
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new IFLT(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ICMPGE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-if_icmpge with ifge
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new IFGE(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ICMPGT) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-if_icmpgt with ifgt
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new IFGT(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ICMPLE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-if_icmple with ifle
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new IFLE(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ACMPEQ) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc null-if_acmpeq with ifnull
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
if (frst.getValue(method.getConstantPool()) == null) { |
||||||
|
return new Filter(new IFNULL(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IF_ACMPNE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc null-if_acmpne with ifnonnull
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
if (frst.getValue(method.getConstantPool()) == null) { |
||||||
|
return new Filter(new IFNONNULL(secnd.getTarget())); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IFEQ) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc 0-ifeq with goto and eliminate ldc !0-ifeq
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() == 0) { |
||||||
|
return new Filter(new GOTO(secnd.getTarget())); |
||||||
|
} else { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IFNE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc !0-ifne with goto and eliminate ldc 0-ifne
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() != 0) { |
||||||
|
return new Filter(new GOTO(secnd.getTarget())); |
||||||
|
} else { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IFLT) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc <0-iflt with goto and eliminate ldc >=0-iflt
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() < 0) { |
||||||
|
return new Filter(new GOTO(secnd.getTarget())); |
||||||
|
} else { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IFGE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc >=0-ifge with goto and eliminate ldc <0-ifge
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() >= 0) { |
||||||
|
return new Filter(new GOTO(secnd.getTarget())); |
||||||
|
} else { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IFGT) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc >0-ifgt with goto and eliminate ldc <=0-ifgt
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() > 0) { |
||||||
|
return new Filter(new GOTO(secnd.getTarget())); |
||||||
|
} else { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof IFLE) { |
||||||
|
BranchInstruction secnd = (BranchInstruction) second; |
||||||
|
// Replace ldc <=0-ifle with goto and eliminate ldc >0-ifle
|
||||||
|
if (first instanceof LDC) { |
||||||
|
LDC frst = (LDC) first; |
||||||
|
Object op = frst.getValue(method.getConstantPool()); |
||||||
|
if (op instanceof Integer) { |
||||||
|
if (((Integer) op).intValue() <= 0) { |
||||||
|
return new Filter(new GOTO(secnd.getTarget())); |
||||||
|
} else { |
||||||
|
return new Filter(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (second instanceof StoreInstruction) { |
||||||
|
StoreInstruction secnd = (StoreInstruction) second; |
||||||
|
// Replace store-store to same location with pop-store.
|
||||||
|
if (first instanceof StoreInstruction) { |
||||||
|
StoreInstruction frst = (StoreInstruction) first; |
||||||
|
if ((frst instanceof LSTORE) || (frst instanceof DSTORE)) { |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new POP2(), first); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new POP(), first); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// Replace store-load with dup-store.
|
||||||
|
// Replace load-load with load-dup.
|
||||||
|
if (second instanceof ILOAD) { |
||||||
|
LoadInstruction secnd = (LoadInstruction) second; |
||||||
|
if (first instanceof ISTORE) { |
||||||
|
StoreInstruction frst = (StoreInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new DUP(), first); |
||||||
|
} |
||||||
|
} |
||||||
|
if (first instanceof ILOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(first, new DUP()); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof FLOAD) { |
||||||
|
LoadInstruction secnd = (LoadInstruction) second; |
||||||
|
if (first instanceof FSTORE) { |
||||||
|
StoreInstruction frst = (StoreInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new DUP(), first); |
||||||
|
} |
||||||
|
} |
||||||
|
if (first instanceof FLOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(first, new DUP()); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof ALOAD) { |
||||||
|
LoadInstruction secnd = (LoadInstruction) second; |
||||||
|
if (first instanceof ASTORE) { |
||||||
|
StoreInstruction frst = (StoreInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new DUP(), first); |
||||||
|
} |
||||||
|
} |
||||||
|
if (first instanceof ALOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(first, new DUP()); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof LLOAD) { |
||||||
|
LoadInstruction secnd = (LoadInstruction) second; |
||||||
|
if (first instanceof LSTORE) { |
||||||
|
StoreInstruction frst = (StoreInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new DUP2(), first); |
||||||
|
} |
||||||
|
} |
||||||
|
if (first instanceof LLOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(first, new DUP2()); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (second instanceof DLOAD) { |
||||||
|
LoadInstruction secnd = (LoadInstruction) second; |
||||||
|
if (first instanceof DSTORE) { |
||||||
|
StoreInstruction frst = (StoreInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(new DUP2(), first); |
||||||
|
} |
||||||
|
} |
||||||
|
if (first instanceof DLOAD) { |
||||||
|
LoadInstruction frst = (LoadInstruction) first; |
||||||
|
if (frst.getIndex() == secnd.getIndex()) { |
||||||
|
return new Filter(first, new DUP2()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,359 @@ |
|||||||
|
/* |
||||||
|
* Class: SideEffectChecker |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import org.apache.bcel.classfile.*; |
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.EditorContext; |
||||||
|
import edu.purdue.cs.bloat.editor.MemberRef; |
||||||
|
import edu.purdue.cs.bloat.tree.ArithExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayLengthExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ArrayRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallMethodExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CallStaticExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CastExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.CatchExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.FieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.LocalExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MonitorStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.NewArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.NewMultiArrayExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.RCExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StackManipStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.StaticFieldExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.StoreExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.tree.UCExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.ZeroCheckExpr; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>SideEffectChecker</tt> traverses a tree and determines if a node has |
||||||
|
* any side effects such as changing the stack, calling a function, or |
||||||
|
* performing a residency check. The side effects are represented by an integer |
||||||
|
* whose bits represent a certain kind of side effect. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* <Tt>SideEffectChecker</tt> is a <tt>TreeVisitor</tt>. The way it works |
||||||
|
* is that after a <tt>SideEffectChecker</tt> is reset, an expression tree |
||||||
|
* <tt>Node</tt> is visited to determine whether or not it has side effects. |
||||||
|
* Neat. |
||||||
|
*/ |
||||||
|
public class SideEffectChecker extends TreeVisitor { |
||||||
|
private int sideEffects = 0; |
||||||
|
|
||||||
|
public static final int STACK = (1 << 0); |
||||||
|
|
||||||
|
public static final int THROW = (1 << 1); |
||||||
|
|
||||||
|
public static final int CALL = (1 << 2); |
||||||
|
|
||||||
|
public static final int SYNC = (1 << 3); |
||||||
|
|
||||||
|
public static final int ALLOC = (1 << 4); // Allocates memory
|
||||||
|
|
||||||
|
public static final int RC = (1 << 5); |
||||||
|
|
||||||
|
public static final int UC = (1 << 6); |
||||||
|
|
||||||
|
public static final int STORE = (1 << 7); |
||||||
|
|
||||||
|
public static final int ALIAS = (1 << 8); |
||||||
|
|
||||||
|
public static final int VOLATILE = (1 << 9); |
||||||
|
|
||||||
|
private EditorContext context; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. The <tt>Context</tt> is needed to determine whether or not |
||||||
|
* a field is VOLATILE, etc. |
||||||
|
*/ |
||||||
|
public SideEffectChecker(EditorContext context) { |
||||||
|
this.context = context; |
||||||
|
} |
||||||
|
|
||||||
|
public int sideEffects() { |
||||||
|
return sideEffects; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasSideEffects() { |
||||||
|
return sideEffects != 0; |
||||||
|
} |
||||||
|
|
||||||
|
public void reset() { |
||||||
|
sideEffects = 0; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
sideEffects |= STORE; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLocalExpr(LocalExpr expr) { |
||||||
|
if (expr.isDef()) { |
||||||
|
sideEffects |= STORE; |
||||||
|
} |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitZeroCheckExpr(ZeroCheckExpr expr) { |
||||||
|
sideEffects |= THROW; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRCExpr(RCExpr expr) { |
||||||
|
sideEffects |= RC; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitUCExpr(UCExpr expr) { |
||||||
|
sideEffects |= UC; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
// Memory allocation
|
||||||
|
// NegativeArraySizeException
|
||||||
|
sideEffects |= THROW | ALLOC; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
// Memory allocation
|
||||||
|
// NegativeArraySizeException
|
||||||
|
sideEffects |= THROW | ALLOC; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
// Stack change
|
||||||
|
sideEffects |= STACK; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
// Memory allocation
|
||||||
|
sideEffects |= ALLOC; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackExpr(StackExpr expr) { |
||||||
|
// Stack change
|
||||||
|
sideEffects |= STACK; |
||||||
|
|
||||||
|
if (expr.isDef()) { |
||||||
|
sideEffects |= STORE; |
||||||
|
} |
||||||
|
|
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
// ClassCastException
|
||||||
|
if (expr.castType() instanceof ReferenceType) { |
||||||
|
sideEffects |= THROW; |
||||||
|
} |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArithExpr(ArithExpr expr) { |
||||||
|
// DivideByZeroException -- handled by ZeroCheckExpr
|
||||||
|
/* |
||||||
|
* if (expr.operation() == ArithExpr.DIV || expr.operation() == |
||||||
|
* ArithExpr.REM) { |
||||||
|
* |
||||||
|
* if (expr.type().isIntegral() || expr.type().equals(Type.LONG)) { |
||||||
|
* sideEffects |= THROW; } } |
||||||
|
*/ |
||||||
|
|
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
// NullPointerException
|
||||||
|
sideEffects |= THROW; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
// NullPointerException, ArrayIndexOutOfBoundsException,
|
||||||
|
// ArrayStoreException
|
||||||
|
sideEffects |= THROW; |
||||||
|
|
||||||
|
if (expr.isDef()) { |
||||||
|
sideEffects |= STORE; |
||||||
|
} |
||||||
|
|
||||||
|
sideEffects |= ALIAS; |
||||||
|
|
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
// NullPointerException -- handled by ZeroCheckExpr
|
||||||
|
/* |
||||||
|
* sideEffects |= THROW; |
||||||
|
*/ |
||||||
|
|
||||||
|
if (expr.isDef()) { |
||||||
|
sideEffects |= STORE; |
||||||
|
} |
||||||
|
|
||||||
|
MemberRef field = expr.field(); |
||||||
|
try { |
||||||
|
try { |
||||||
|
ReferenceType type = field.declaringClass(); |
||||||
|
if (type instanceof ArrayType) {// TODO
|
||||||
|
Type elementType = ((ArrayType) type).getElementType(); |
||||||
|
if (elementType instanceof BasicType) { |
||||||
|
return; // Already loaded
|
||||||
|
} |
||||||
|
type = (ObjectType) elementType; |
||||||
|
} |
||||||
|
JavaClass jc = context.loadClass(((ObjectType) type) |
||||||
|
.getClassName()); |
||||||
|
Field[] fields = jc.getFields(); |
||||||
|
Field e = null; |
||||||
|
for (int i = 0; i < fields.length; i++) { |
||||||
|
if (fields[i].getName().equals(field.name()) |
||||||
|
&& fields[i].getType().equals(field.type())) { |
||||||
|
e = fields[i]; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (e == null) |
||||||
|
throw new NoSuchFieldException("field :" + field |
||||||
|
+ "not found"); |
||||||
|
|
||||||
|
if (!e.isFinal()) { |
||||||
|
sideEffects |= ALIAS; |
||||||
|
} |
||||||
|
|
||||||
|
if (e.isVolatile()) { |
||||||
|
sideEffects |= VOLATILE; |
||||||
|
} |
||||||
|
// WE NEVER STARTED EDITING IT SO WE DON'T NEED TO RELEASE IT
|
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
} catch (NoSuchFieldException e) { |
||||||
|
// A field wasn't found. Silently assume it's not final and
|
||||||
|
// is volatile.
|
||||||
|
sideEffects |= ALIAS; |
||||||
|
sideEffects |= VOLATILE; |
||||||
|
} |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
System.out.println(cnfe.getMessage()); |
||||||
|
} |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr expr) { |
||||||
|
if (expr.isDef()) { |
||||||
|
sideEffects |= STORE; |
||||||
|
} |
||||||
|
|
||||||
|
MemberRef field = expr.field(); |
||||||
|
try { |
||||||
|
try { |
||||||
|
ReferenceType type = field.declaringClass(); |
||||||
|
if (type instanceof ArrayType) {// TODO
|
||||||
|
Type elementType = ((ArrayType) type).getElementType(); |
||||||
|
if (elementType instanceof BasicType) { |
||||||
|
return; // Already loaded
|
||||||
|
} |
||||||
|
type = (ObjectType) elementType; |
||||||
|
} |
||||||
|
JavaClass jc = context.loadClass(((ObjectType) type) |
||||||
|
.getClassName()); |
||||||
|
|
||||||
|
Field e = null; |
||||||
|
Field[] fields = jc.getFields(); |
||||||
|
for (int i = 0; i < fields.length; i++) { |
||||||
|
if (fields[i].getName().equals(field.name()) |
||||||
|
&& fields[i].getType().equals(field.type())) { |
||||||
|
e = fields[i]; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (e == null) |
||||||
|
throw new NoSuchFieldException("field :" + field |
||||||
|
+ "not found"); |
||||||
|
|
||||||
|
if (e.isVolatile()) { |
||||||
|
sideEffects |= VOLATILE; |
||||||
|
} |
||||||
|
// WE NEVER STARTED EDITING IT SO WE DON'T NEED TO RELEASE IT
|
||||||
|
// context.release(e.fieldInfo());
|
||||||
|
} catch (NoSuchFieldException e) { |
||||||
|
// A field wasn't found. Silently assume it's volatile.
|
||||||
|
sideEffects |= VOLATILE; |
||||||
|
} |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
System.out.println(cnfe.getMessage()); |
||||||
|
} |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
// Call
|
||||||
|
sideEffects |= THROW | CALL; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
// Call
|
||||||
|
sideEffects |= THROW | CALL; |
||||||
|
expr.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitMonitorStmt(MonitorStmt stmt) { |
||||||
|
// Synchronization
|
||||||
|
sideEffects |= THROW | SYNC; |
||||||
|
stmt.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
// Stack change
|
||||||
|
sideEffects |= STACK; |
||||||
|
stmt.visitChildren(this); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,327 @@ |
|||||||
|
/* |
||||||
|
* Class: StackOpt |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.codegen.CodeGenerator; |
||||||
|
import edu.purdue.cs.bloat.editor.InstructionAdapter; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
|
||||||
|
public class StackOpt extends InstructionAdapter implements Optimization { |
||||||
|
|
||||||
|
int stackHeight; |
||||||
|
|
||||||
|
int minStackHeight; |
||||||
|
|
||||||
|
static final boolean DEBUG = false; |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
// generate code without doing liveness or register allocation
|
||||||
|
CodeGenerator codegen = new CodeGenerator(state); |
||||||
|
codegen.replacePhis().generateCode(); |
||||||
|
|
||||||
|
// do stack optimization on the bytecode
|
||||||
|
state.commitChanges(); |
||||||
|
|
||||||
|
transform(state.methodGen()); |
||||||
|
|
||||||
|
state.rebuildFlowGraph(); |
||||||
|
} |
||||||
|
|
||||||
|
// StackOpt needs use and definition and label information to perform
|
||||||
|
// transformations.
|
||||||
|
// Consequently CodeGenerator must have been run to produce the code
|
||||||
|
// supplied to StackOpt.transform.
|
||||||
|
// Because of this I assume that labels and use and definition
|
||||||
|
// information are in place.
|
||||||
|
// This is currently implemented using attributes in InstructionHandles,
|
||||||
|
// the keys being "Label" and
|
||||||
|
// "Def". --Arrin
|
||||||
|
private void transform(MethodGen method) { |
||||||
|
for (InstructionHandle i = method.getInstructionList().getEnd(); i != null; // && i
|
||||||
|
// !=
|
||||||
|
// method.getInstructionList().getStart();
|
||||||
|
i = i.getPrev()) { |
||||||
|
|
||||||
|
Instruction inst = i.getInstruction(); |
||||||
|
boolean isWide; |
||||||
|
|
||||||
|
if (inst instanceof LoadInstruction) { |
||||||
|
isWide = (((LoadInstruction) inst).getType( |
||||||
|
method.getConstantPool()).getSize() == 2); |
||||||
|
} else if (isArrayLoadInstruction(inst)) { |
||||||
|
isWide = (((ArrayInstruction) inst).getType( |
||||||
|
method.getConstantPool()).getSize() == 2); |
||||||
|
} else { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) |
||||||
|
System.out.println("Considering: " + i); |
||||||
|
|
||||||
|
stackHeight = 0; |
||||||
|
|
||||||
|
boolean seenLabel = FlowGraph.label(i); // If 'i' is a label we
|
||||||
|
// don't do anything.
|
||||||
|
for (InstructionHandle j = i.getPrev();; j = j.getPrev()) { |
||||||
|
|
||||||
|
// stop at the begining of the code or a basic block.
|
||||||
|
// As Labels are also instructions
|
||||||
|
if (j == null || seenLabel) |
||||||
|
break; |
||||||
|
|
||||||
|
if (stackHeight == -1 |
||||||
|
&& ((hasSameDef(i, j) && isLoadInstruction(j)) || dupRun( |
||||||
|
j, i))) { |
||||||
|
if (forwardCountCheck(method, j, i, -1)) { |
||||||
|
// found a type 0 relation with a load
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("load type 0: " + j + " " + i); |
||||||
|
} |
||||||
|
if (isWide) { |
||||||
|
method.getInstructionList().append(j, new DUP2()); |
||||||
|
} else { |
||||||
|
method.getInstructionList().append(j, new DUP()); |
||||||
|
// add dup
|
||||||
|
} |
||||||
|
i.setInstruction(new NOP()); |
||||||
|
// TODO: Why is deleting this a problem?
|
||||||
|
// I would have deleted it but it seems to cause all
|
||||||
|
// sorts of evil
|
||||||
|
} |
||||||
|
break; // done, even if final check failed.
|
||||||
|
} else if (stackHeight == 0 && hasSameDef(i, j)) { |
||||||
|
if (isStoreInstruction(j)) { |
||||||
|
if (forwardCountCheck(method, j, i, 0)) { |
||||||
|
// found a type 0 with a store
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("store type 0: " + j + " " |
||||||
|
+ i); |
||||||
|
} |
||||||
|
if (isWide) { |
||||||
|
method.getInstructionList().append(j, |
||||||
|
j.getInstruction()); |
||||||
|
j.setInstruction(new DUP2()); |
||||||
|
} else { |
||||||
|
method.getInstructionList().append(j, |
||||||
|
j.getInstruction()); |
||||||
|
j.setInstruction(new DUP()); |
||||||
|
|
||||||
|
} |
||||||
|
i.setInstruction(new NOP()); |
||||||
|
// I would have deleted it but it seems to cause
|
||||||
|
// all sorts of evil
|
||||||
|
|
||||||
|
} |
||||||
|
break; |
||||||
|
} else if (isLoadInstruction(j) && !isWide) { |
||||||
|
// can't do type 1s with wides.
|
||||||
|
if (forwardCountCheck(method, j, i, -1)) { |
||||||
|
// found a type 1 with a load
|
||||||
|
if (DEBUG) |
||||||
|
System.out.println("load type 1: " + j + " " |
||||||
|
+ i); |
||||||
|
method.getInstructionList().append(j, new DUP()); |
||||||
|
System.out.println("HERE1 inserting SWAP"); |
||||||
|
i.setInstruction(new SWAP()); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} else if (stackHeight == 1 && hasSameDef(i, j)) { |
||||||
|
if (isStoreInstruction(j) && !isWide) { // can't do type 1
|
||||||
|
// with wides
|
||||||
|
|
||||||
|
if (forwardCountCheck(method, j, i, 0)) { |
||||||
|
// type 1 for stores
|
||||||
|
if (DEBUG) |
||||||
|
System.out.println("store type 1: " + j + " " |
||||||
|
+ i); |
||||||
|
method.getInstructionList().append(j, |
||||||
|
j.getInstruction()); |
||||||
|
j.setInstruction(new DUP()); |
||||||
|
System.out.println("HERE2 inserting SWAP"); |
||||||
|
i.setInstruction(new SWAP()); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
heightChange(method, j.getInstruction()); |
||||||
|
|
||||||
|
if (FlowGraph.label(j)) { |
||||||
|
seenLabel = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
method.removeNOPs(); |
||||||
|
method.getInstructionList().setPositions(); |
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("Method:"); |
||||||
|
System.out.println(method); |
||||||
|
for (InstructionHandle ih = method.getInstructionList().getStart(); ih != null; ih = ih |
||||||
|
.getNext()) { |
||||||
|
if (FlowGraph.label(ih)) |
||||||
|
System.out.print("(L)"); |
||||||
|
else |
||||||
|
System.out.print(" "); |
||||||
|
System.out.print(" " + ih.getPosition() + ": " |
||||||
|
+ ih.getInstruction()); |
||||||
|
if (ih.getAttribute("Def") != null) |
||||||
|
System.out.print("(" + ih.getAttribute("Def") + ")"); |
||||||
|
System.out.println(""); |
||||||
|
} |
||||||
|
// System.out.println(method.getMethod().getCode());
|
||||||
|
System.out.println(); |
||||||
|
System.out.println("LocalVariables: "); |
||||||
|
LocalVariableGen[] locals = method.getLocalVariables(); |
||||||
|
for (int i = 0; i < locals.length; i++) { |
||||||
|
System.out.println(" " + locals[i]); |
||||||
|
} |
||||||
|
System.out.println("LocalVariable size: " + method.getMaxLocals()); |
||||||
|
CodeExceptionGen[] excptns = method.getExceptionHandlers(); |
||||||
|
if (excptns != null) { |
||||||
|
System.out.println("ExceptionHandlers: "); |
||||||
|
for (int j = 0; j < excptns.length; j++) |
||||||
|
System.out.println(" " + excptns[j]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
method.setMaxStack(); |
||||||
|
method.setMaxLocals(); |
||||||
|
method.update(); |
||||||
|
} |
||||||
|
|
||||||
|
boolean forwardCountCheck(MethodGen m, InstructionHandle j, |
||||||
|
InstructionHandle i, int bound) { |
||||||
|
|
||||||
|
stackHeight = 0; |
||||||
|
minStackHeight = 0; |
||||||
|
|
||||||
|
for (InstructionHandle k = j.getNext(); k != i; k = k.getNext()) { |
||||||
|
heightChange(m, k.getInstruction()); |
||||||
|
if (minStackHeight < bound) |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
boolean dupRun(InstructionHandle j, InstructionHandle i) { |
||||||
|
InstructionHandle k = j; |
||||||
|
Instruction inst = k.getInstruction(); |
||||||
|
|
||||||
|
if (!(inst instanceof DUP)) |
||||||
|
return false; |
||||||
|
|
||||||
|
do { |
||||||
|
k = k.getPrev(); |
||||||
|
inst = k.getInstruction(); |
||||||
|
|
||||||
|
if (isLoadInstruction(inst) && hasSameDef(i, k)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} while (!FlowGraph.label(k) && k.getInstruction() instanceof DUP); |
||||||
|
|
||||||
|
return (isLoadInstruction(inst)) && hasSameDef(i, k); |
||||||
|
} |
||||||
|
|
||||||
|
void heightChange(MethodGen method, Instruction inst) { |
||||||
|
stackHeight = stackHeight - inst.consumeStack(method.getConstantPool()); |
||||||
|
|
||||||
|
if (stackHeight < minStackHeight) |
||||||
|
minStackHeight = stackHeight; |
||||||
|
|
||||||
|
stackHeight = stackHeight + inst.produceStack(method.getConstantPool()); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean hasSameDef(InstructionHandle i, InstructionHandle j) { |
||||||
|
Node iDef = (Node) i.getAttribute("Def"); |
||||||
|
Node jDef = (Node) j.getAttribute("Def"); |
||||||
|
return ((iDef != null) && (jDef != null) && iDef == jDef); |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " New stack optimization: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isLoadInstruction(InstructionHandle handle) { |
||||||
|
return isLoadInstruction(handle.getInstruction()); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isLoadInstruction(Instruction inst) { |
||||||
|
return inst instanceof LoadInstruction || isArrayLoadInstruction(inst); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isArrayLoadInstruction(Instruction inst) { |
||||||
|
return inst instanceof IALOAD || inst instanceof FALOAD |
||||||
|
|| inst instanceof AALOAD || inst instanceof BALOAD |
||||||
|
|| inst instanceof CALOAD || inst instanceof LALOAD |
||||||
|
|| inst instanceof DALOAD || inst instanceof SALOAD; |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isStoreInstruction(InstructionHandle handle) { |
||||||
|
return isStoreInstruction(handle.getInstruction()); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isStoreInstruction(Instruction inst) { |
||||||
|
return inst instanceof StoreInstruction |
||||||
|
|| isArrayStoreInstruction(inst); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isArrayStoreInstruction(Instruction inst) { |
||||||
|
return inst instanceof IASTORE || inst instanceof FASTORE |
||||||
|
|| inst instanceof AASTORE || inst instanceof BASTORE |
||||||
|
|| inst instanceof CASTORE || inst instanceof LASTORE |
||||||
|
|| inst instanceof DASTORE || inst instanceof SASTORE; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* Class: StackOptimization |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Block; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
|
||||||
|
/** |
||||||
|
* This is the old stack optimizer. The actual optimization stuff is in |
||||||
|
* tree/StackOptimizationData.java, this class just provides a convenient plugin |
||||||
|
* interface to it. |
||||||
|
* |
||||||
|
* This is completely unrelated to StackOpt. |
||||||
|
*/ |
||||||
|
public class StackOptimization implements Optimization { |
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Old stack optimization: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
List blocks = state.controlFlowGraph().preOrder(); |
||||||
|
|
||||||
|
for (Iterator i = blocks.iterator(); i.hasNext();) |
||||||
|
((Block) i.next()).stackOptimizer().optimize(); |
||||||
|
|
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,306 @@ |
|||||||
|
/* |
||||||
|
* Class: ValueFolding |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.editor.EditorContext; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.ssa.ComponentVisitor; |
||||||
|
import edu.purdue.cs.bloat.ssa.SSAGraph; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Expr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiCatchStmt; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>ValueFolding</tt> uses a <tt>ValueFolder</tt> to determine which |
||||||
|
* nodes in an expression tree can be removed or replaced by common expression |
||||||
|
* elimination and constant propagation. |
||||||
|
* |
||||||
|
* @see ValueFolder |
||||||
|
*/ |
||||||
|
public class ValueFolding implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
SideEffectChecker sideEffects; |
||||||
|
|
||||||
|
ValueFolder folder; |
||||||
|
|
||||||
|
boolean changed; |
||||||
|
|
||||||
|
public static boolean DUMP = false; |
||||||
|
|
||||||
|
public static boolean SAVEDUMP = false; |
||||||
|
|
||||||
|
PrintWriter vn; |
||||||
|
|
||||||
|
PrintWriter dump; |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs value folding (common expression elimination and constant |
||||||
|
* folding) on a control flow graph. |
||||||
|
*/ |
||||||
|
int next = 1; |
||||||
|
|
||||||
|
public void transform(MethodState state) { |
||||||
|
FlowGraph cfg = state.controlFlowGraph(); |
||||||
|
|
||||||
|
if (DUMP) { |
||||||
|
vn = new PrintWriter(System.out, true); |
||||||
|
dump = new PrintWriter(System.out, true); |
||||||
|
} |
||||||
|
|
||||||
|
// MAY NOT BE THE BEST THING TO DO
|
||||||
|
// Repository context = cfg.method().declaringClass().context();
|
||||||
|
// Repository context = org.apache.bcel.Repository.getRepository();
|
||||||
|
// EditorContext context = new
|
||||||
|
// PersistentBloatContext(org.apache.bcel.Repository.getRepository());
|
||||||
|
|
||||||
|
// Get the context from the MethodState object. In theory, this may
|
||||||
|
// cause
|
||||||
|
// problems if PersistentBloatContext.closure starts meaning something,
|
||||||
|
// so you may have to return to the previous definition. But this way is
|
||||||
|
// much nicer.
|
||||||
|
EditorContext context = state.context(); |
||||||
|
|
||||||
|
sideEffects = new SideEffectChecker(context); |
||||||
|
|
||||||
|
folder = new ValueFolder(true, context); |
||||||
|
|
||||||
|
SSAGraph ssaGraph = new SSAGraph(cfg); |
||||||
|
|
||||||
|
ssaGraph.visitComponents(new ComponentVisitor() { |
||||||
|
public void visitComponent(List scc) { |
||||||
|
// Maps Nodes in the SCC to their folded value
|
||||||
|
LinkedHashMap map = new LinkedHashMap(scc.size() * 2 + 1); |
||||||
|
|
||||||
|
boolean changed = true; |
||||||
|
|
||||||
|
while (changed) { |
||||||
|
changed = false; |
||||||
|
|
||||||
|
Iterator iter = scc.iterator(); |
||||||
|
|
||||||
|
int x = 0; |
||||||
|
while (iter.hasNext()) { |
||||||
|
Node node = (Node) iter.next(); |
||||||
|
|
||||||
|
if (DUMP) { |
||||||
|
x++; |
||||||
|
dump.println("Folding SCC Node " + node + " (" + x |
||||||
|
+ " of " + scc.size() + ")"); |
||||||
|
} |
||||||
|
|
||||||
|
if (fold(map, node)) { |
||||||
|
changed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (DUMP) |
||||||
|
dump.println(""); |
||||||
|
|
||||||
|
if (scc.size() == 1) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
cfg.removeUnreachable(); |
||||||
|
|
||||||
|
folder = null; |
||||||
|
sideEffects = null; |
||||||
|
|
||||||
|
// Okay, we've successfully value folded, remove debugging files
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds a mapping between the nodes in a CFG's SCCs and the expressions |
||||||
|
* they are equivalent to. |
||||||
|
* |
||||||
|
* @param map |
||||||
|
* A mapping between the SCCs of the CFG's SSA Graph |
||||||
|
* (definitions) and the expressions they are folded to |
||||||
|
* @param sscNode |
||||||
|
* A Node in the SCC of the SSA Graph |
||||||
|
* |
||||||
|
* @return True, if the value in the mapping was changed. |
||||||
|
*/ |
||||||
|
boolean fold(Map map, Node sccNode) { |
||||||
|
Node node = (Node) map.get(sccNode); |
||||||
|
|
||||||
|
if (DUMP) |
||||||
|
dump |
||||||
|
.println(" SCC Node " + sccNode + " is mapped to node " |
||||||
|
+ node); |
||||||
|
|
||||||
|
// The SCC node has not been folded yet, fold it to itself
|
||||||
|
if (node == null) { |
||||||
|
node = sccNode; |
||||||
|
} |
||||||
|
|
||||||
|
if (!node.hasParent()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("folding --- " + node + " in " + node.parent()); |
||||||
|
} |
||||||
|
|
||||||
|
if (DUMP) { |
||||||
|
dump.println(" Folding " + node + " (" + "VN=" |
||||||
|
+ node.valueNumber() + ") in " + node.parent()); |
||||||
|
} |
||||||
|
|
||||||
|
int v = node.valueNumber(); |
||||||
|
|
||||||
|
if (v == -1) { |
||||||
|
// Node has not been assigned a value number, can't do anything
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
folder.values.ensureSize(v + 1); |
||||||
|
ConstantExpr oldValue = (ConstantExpr) folder.values.get(v); |
||||||
|
ConstantExpr value = null; |
||||||
|
|
||||||
|
if (DUMP) |
||||||
|
dump.println(" Node " + node + " is mapped to constant " |
||||||
|
+ oldValue); |
||||||
|
|
||||||
|
if (node instanceof ConstantExpr) { |
||||||
|
// If the node that we're dealing with is already a
|
||||||
|
// ConstantExpr, change it to the mapped value if it is
|
||||||
|
// different.
|
||||||
|
value = (ConstantExpr) node; |
||||||
|
|
||||||
|
if (oldValue == null || !oldValue.equalsExpr(value)) { |
||||||
|
// The node was not previously mapped to a constant, or it was
|
||||||
|
// mapped to a different constant. Update the mapping to
|
||||||
|
// relfect the new constant.
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("changed " + oldValue + " to " + value); |
||||||
|
} |
||||||
|
|
||||||
|
if (DUMP) { |
||||||
|
dump.println(" Changed " + oldValue + " to " + value); |
||||||
|
} |
||||||
|
|
||||||
|
folder.values.set(v, value); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// Mapping was already correct, don't do anything.
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (node instanceof Expr && oldValue != null) { |
||||||
|
// The node is a non-constant Expr that was mapped to a constant
|
||||||
|
|
||||||
|
if (node.parent() instanceof PhiCatchStmt) { |
||||||
|
// Don't fold values inside PhiCatchStmts
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
sideEffects.reset(); |
||||||
|
node.visit(sideEffects); |
||||||
|
|
||||||
|
if (!sideEffects.hasSideEffects()) { |
||||||
|
// If the expression does not have side effects, then make a
|
||||||
|
// clone of the value to which it was mapped and map the clone
|
||||||
|
// to the original sccNode (which may or may not be node).
|
||||||
|
// Technically, the mapping did not change.
|
||||||
|
|
||||||
|
value = (ConstantExpr) oldValue.clone(); |
||||||
|
node.replaceWith(value); |
||||||
|
map.put(sccNode, value); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (value == null) { |
||||||
|
// The node is mapped to nothing, Use the ValueFolder to
|
||||||
|
// determine a expression that node can be folded to.
|
||||||
|
|
||||||
|
folder.node = null; |
||||||
|
node.visit(folder); |
||||||
|
|
||||||
|
if (DEBUG) { |
||||||
|
System.out.println("folded " + node + " to " + folder.node); |
||||||
|
} |
||||||
|
|
||||||
|
if (DUMP) { |
||||||
|
dump.println(" Using ValueFolder to determine new value"); |
||||||
|
dump.println(" Folded " + node + " to " + folder.node); |
||||||
|
} |
||||||
|
|
||||||
|
if (folder.node != null) { |
||||||
|
// Assert.isTrue(folder.node.hasParent(),
|
||||||
|
// "No parent for " + folder.node);
|
||||||
|
map.put(sccNode, folder.node); |
||||||
|
} |
||||||
|
|
||||||
|
if (folder.node instanceof ConstantExpr) { |
||||||
|
// If the node was folded into a ConstantExpr, then fold it in
|
||||||
|
// the ValueFolder.
|
||||||
|
value = (ConstantExpr) folder.node; |
||||||
|
folder.values.set(v, value); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Value Folding: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return "--------Before Value Folding---------"; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return "---------After Value Folding---------"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,536 @@ |
|||||||
|
/* |
||||||
|
* Class: ValueNumbering |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.trans; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import java.io.*; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.optimize.MethodState; |
||||||
|
import edu.purdue.cs.bloat.optimize.Optimization; |
||||||
|
import edu.purdue.cs.bloat.ssa.ComponentVisitor; |
||||||
|
import edu.purdue.cs.bloat.ssa.SSAGraph; |
||||||
|
import edu.purdue.cs.bloat.tree.ConstantExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.MemRefExpr; |
||||||
|
import edu.purdue.cs.bloat.tree.Node; |
||||||
|
import edu.purdue.cs.bloat.tree.PhiStmt; |
||||||
|
import edu.purdue.cs.bloat.tree.Tree; |
||||||
|
import edu.purdue.cs.bloat.tree.TreeVisitor; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs value numbering analysis on the nodes in a control flow graph. Nodes |
||||||
|
* with identical value numbers are folded into one another so that common |
||||||
|
* (redundent) expressions are eliminated. Note that ValueNumbering works on the |
||||||
|
* SSAGraph for the CFG and not the CFG itself. |
||||||
|
* |
||||||
|
* @see SSAGraph |
||||||
|
*/ |
||||||
|
// L.T. Simpson 1996. Value-driven redundancy elimination. PhD
|
||||||
|
// Thesis. Rice University. Look it up. Chapter 4 contains the
|
||||||
|
// stuff on SCC-based value numbering.
|
||||||
|
public class ValueNumbering implements Optimization { |
||||||
|
public static boolean DEBUG = false; |
||||||
|
|
||||||
|
SSAGraph ssaGraph; |
||||||
|
|
||||||
|
LinkedHashMap tuples; // Maps a Node to its Tuple
|
||||||
|
|
||||||
|
ValueFolder folder; |
||||||
|
|
||||||
|
int next; // The next value number to assign
|
||||||
|
|
||||||
|
public String debugDirName = "debug"; |
||||||
|
|
||||||
|
public File debugDir; |
||||||
|
|
||||||
|
public boolean DUMP = false; |
||||||
|
|
||||||
|
private PrintWriter dump = new PrintWriter(System.out); |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs value numbering on a control flow graph. |
||||||
|
* |
||||||
|
* @see ComponentVisitor |
||||||
|
* @see SSAGraph |
||||||
|
* @see ValueFolder |
||||||
|
*/ |
||||||
|
public void transform(MethodState state) { |
||||||
|
FlowGraph cfg = state.controlFlowGraph(); |
||||||
|
|
||||||
|
// Specify directory into which all debugging files should be
|
||||||
|
// placed
|
||||||
|
|
||||||
|
if (DUMP || ValueFolding.DUMP) { |
||||||
|
String className = cfg.method().getClassName(); |
||||||
|
String methodName = cfg.method().getName(); |
||||||
|
|
||||||
|
String dirName = debugDirName + File.separator + className |
||||||
|
+ File.separator + methodName; |
||||||
|
|
||||||
|
debugDir = new File(dirName); |
||||||
|
for (int nextDir = 1; debugDir.exists(); nextDir++) { |
||||||
|
// Multiple directories
|
||||||
|
debugDir = new File(dirName + "_" + nextDir); |
||||||
|
} |
||||||
|
|
||||||
|
if (!debugDir.exists()) |
||||||
|
debugDir.mkdirs(); |
||||||
|
|
||||||
|
// General dumping file
|
||||||
|
try { |
||||||
|
File dumpFile = new File(debugDir, "vn_dump"); |
||||||
|
dump = new PrintWriter(new FileWriter(dumpFile), true); |
||||||
|
} catch (IOException ex) { |
||||||
|
System.err.println(ex.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ssaGraph = new SSAGraph(cfg); |
||||||
|
tuples = new LinkedHashMap(); |
||||||
|
|
||||||
|
// Use state.context() to get the EditorContext. It breaks, go back to
|
||||||
|
// the
|
||||||
|
// "new PersistentBloatContext(...) version.
|
||||||
|
folder = new ValueFolder(false, state.context()); |
||||||
|
// new
|
||||||
|
// PersistentBloatContext(org.apache.bcel.Repository.getRepository()));
|
||||||
|
// cfg.method().declaringClass().context());
|
||||||
|
// AGAIN THIS MIGHT NOT BE THE BEST
|
||||||
|
next = 0; |
||||||
|
|
||||||
|
final LinkedHashMap valid = new LinkedHashMap(); |
||||||
|
final LinkedHashMap optimistic = new LinkedHashMap(); |
||||||
|
|
||||||
|
ssaGraph.visitComponents(new ComponentVisitor() { |
||||||
|
public void visitComponent(List scc) { |
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println("\nNumbering SCC = " + scc); |
||||||
|
} |
||||||
|
|
||||||
|
Iterator e = scc.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Node node = (Node) e.next(); |
||||||
|
node.setValueNumber(-1); |
||||||
|
} |
||||||
|
|
||||||
|
if (scc.size() > 1) { |
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println("Optimistic-----------------------"); |
||||||
|
} |
||||||
|
|
||||||
|
boolean changed = true; |
||||||
|
|
||||||
|
while (changed) { |
||||||
|
changed = false; |
||||||
|
|
||||||
|
Iterator iter = scc.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node node = (Node) iter.next(); |
||||||
|
|
||||||
|
if (valnum(node, optimistic)) { |
||||||
|
changed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println("Valid--------------------------------"); |
||||||
|
} |
||||||
|
|
||||||
|
// The valid table contains the correct value numbers. Run
|
||||||
|
// through the each node in the SCC and call valnum.
|
||||||
|
// Presumably, the nodes are in reverse postorder.
|
||||||
|
Iterator iter = scc.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node node = (Node) iter.next(); |
||||||
|
valnum(node, valid); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println("Final value numbers--------------------------"); |
||||||
|
printValueNumbers(cfg, new PrintWriter(dump)); |
||||||
|
} |
||||||
|
|
||||||
|
if (DUMP) { |
||||||
|
System.out.println(" Dumping to: " + debugDir); |
||||||
|
|
||||||
|
try { |
||||||
|
File valueNumbers = new File(debugDir, "scc.txt"); |
||||||
|
ssaGraph |
||||||
|
.printSCCs(new PrintWriter(new FileWriter(valueNumbers))); |
||||||
|
} catch (IOException ex) { |
||||||
|
System.err.println("IOException: " + ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ssaGraph = null; |
||||||
|
tuples = null; |
||||||
|
|
||||||
|
folder.cleanup(); |
||||||
|
folder = null; |
||||||
|
|
||||||
|
// Make sure each node has a value number
|
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitTree(Tree tree) { |
||||||
|
tree.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
node.visitChildren(this); |
||||||
|
Assert.isTrue(node.valueNumber() != -1, "No value number for " |
||||||
|
+ node); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private void printValueNumbers(FlowGraph cfg, final PrintWriter pw) { |
||||||
|
cfg.visit(new TreeVisitor() { |
||||||
|
public void visitTree(Tree tree) { |
||||||
|
tree.visitChildren(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
node.visitChildren(this); |
||||||
|
|
||||||
|
pw.println("VN[" + node + " " + System.identityHashCode(node) + |
||||||
|
// " == " + ssaGraph.equivalent(node) + " " +
|
||||||
|
// System.identityHashCode(ssaGraph.equivalent(node)) +
|
||||||
|
"] = " + node.valueNumber()); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Simplifies a node by examining its type. A ValueFolder may be used to |
||||||
|
* perform simplification. |
||||||
|
* |
||||||
|
* @return The folded (simplified) value of the node (which may be the same |
||||||
|
* as the node itself) |
||||||
|
*/ |
||||||
|
private Node simplify(Node node) { |
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println("folding " + node + " in " + node.parent()); |
||||||
|
} |
||||||
|
|
||||||
|
int v = node.valueNumber(); |
||||||
|
|
||||||
|
// A value number of -1 (i.e. value number has not yet been
|
||||||
|
// assigned) cannot be simplified.
|
||||||
|
if (v == -1) { |
||||||
|
return node; |
||||||
|
} |
||||||
|
|
||||||
|
// A constant expression can't be simplified, set the value of
|
||||||
|
// value number v to be node
|
||||||
|
if (node instanceof ConstantExpr) { |
||||||
|
folder.values.ensureSize(v + 1); |
||||||
|
folder.values.set(v, node); |
||||||
|
return node; |
||||||
|
} |
||||||
|
|
||||||
|
// Check for the value number in the folder.
|
||||||
|
if (v < folder.values.size()) { |
||||||
|
ConstantExpr value = (ConstantExpr) folder.values.get(v); |
||||||
|
|
||||||
|
if (value != null) { |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Else, use a ValueFolder to fold the node
|
||||||
|
folder.node = null; |
||||||
|
node.visit(folder); |
||||||
|
|
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println("folded " + node + " to " + folder.node); |
||||||
|
} |
||||||
|
|
||||||
|
if (folder.node == null) { |
||||||
|
// Nothing changed
|
||||||
|
return node; |
||||||
|
} |
||||||
|
|
||||||
|
// If we folded the node into a constant expression, add it to
|
||||||
|
// the values list
|
||||||
|
if (folder.node instanceof ConstantExpr) { |
||||||
|
folder.values.ensureSize(v + 1); |
||||||
|
folder.values.set(v, folder.node); |
||||||
|
} |
||||||
|
|
||||||
|
return folder.node; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Processes a Node in an SCC. |
||||||
|
*/ |
||||||
|
private boolean valnum(Node node, LinkedHashMap table) { |
||||||
|
boolean changed = false; // Did the table change?
|
||||||
|
|
||||||
|
Tuple tuple = (Tuple) tuples.get(node); |
||||||
|
|
||||||
|
if (tuple == null) { |
||||||
|
// Make a new Tuple for the node being processed
|
||||||
|
Node s = simplify(node); |
||||||
|
|
||||||
|
tuple = new Tuple(s); |
||||||
|
tuples.put(node, tuple); |
||||||
|
|
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println(" New tuple " + tuple); |
||||||
|
} |
||||||
|
|
||||||
|
} else if (DUMP) { |
||||||
|
dump.println(" " + node + " mapped to tuple " + tuple); |
||||||
|
} |
||||||
|
|
||||||
|
Node w = (Node) table.get(tuple); |
||||||
|
|
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println(" Looking up " + tuple); |
||||||
|
dump.println(" " + tuple + " mapped to node " + w |
||||||
|
+ (w != null ? " (VN = " + w.valueNumber() + ")" : "")); |
||||||
|
} |
||||||
|
|
||||||
|
int value = -1; |
||||||
|
|
||||||
|
if (w != null && w.valueNumber() != -1) { |
||||||
|
value = w.valueNumber(); |
||||||
|
|
||||||
|
} else { |
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println(" New value number " + next); |
||||||
|
} |
||||||
|
|
||||||
|
value = next++; |
||||||
|
} |
||||||
|
|
||||||
|
Assert.isTrue(value != -1); |
||||||
|
|
||||||
|
// Now make sure all equivalent nodes have the same value number.
|
||||||
|
Iterator iter = ssaGraph.equivalent(node).iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node v = (Node) iter.next(); |
||||||
|
|
||||||
|
Tuple t = (Tuple) tuples.get(v); |
||||||
|
|
||||||
|
if (t == null) { |
||||||
|
// Will get done later.
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (v.valueNumber() != value) { |
||||||
|
v.setValueNumber(value); |
||||||
|
table.put(t, v); |
||||||
|
|
||||||
|
if (DEBUG || DUMP) { |
||||||
|
dump.println(" Assigning value number " |
||||||
|
+ v.valueNumber() + " to " + v); |
||||||
|
dump.println(" Mapping tuple " + t + " to node " + v); |
||||||
|
} |
||||||
|
|
||||||
|
changed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return changed; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Tuple contains a Node and an associated hash value. The Node is the |
||||||
|
* simplified version of another node. The main purpose of the Tuple class
|
||||||
|
* is to compare two Nodes to determine if they are the same with respect to |
||||||
|
* their value numbers. |
||||||
|
*/ |
||||||
|
class Tuple { |
||||||
|
Node node; |
||||||
|
|
||||||
|
int hash; |
||||||
|
|
||||||
|
public Tuple(Node node) { |
||||||
|
this.node = node; |
||||||
|
List children = ssaGraph.children(node); |
||||||
|
this.hash = NodeComparator.hashCode(node) + children.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
List children = ssaGraph.children(node); |
||||||
|
|
||||||
|
String s = "<" + node + ", hash=" + hash; |
||||||
|
|
||||||
|
Iterator iter = children.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node child = (Node) iter.next(); |
||||||
|
s += ", " + child + "{" + child.valueNumber() + "}"; |
||||||
|
} |
||||||
|
|
||||||
|
s += ">"; |
||||||
|
|
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (this == obj) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (obj instanceof Tuple) { |
||||||
|
Tuple t = (Tuple) obj; |
||||||
|
|
||||||
|
if (node == t.node) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// All mem refs are unequal.
|
||||||
|
if (node instanceof MemRefExpr || t.node instanceof MemRefExpr) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (!NodeComparator.equals(node, t.node)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
List children1 = ssaGraph.children(node); |
||||||
|
List children2 = ssaGraph.children(t.node); |
||||||
|
|
||||||
|
if (children1.size() != children2.size()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (node instanceof PhiStmt) { |
||||||
|
// The order of the children does not matter
|
||||||
|
int[] used = new int[next]; |
||||||
|
int free = 0; // The number of un-numbered children
|
||||||
|
|
||||||
|
Iterator iter = children1.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node child = (Node) iter.next(); |
||||||
|
int v = child.valueNumber(); |
||||||
|
|
||||||
|
if (v != -1) { |
||||||
|
used[v]++; |
||||||
|
|
||||||
|
} else { |
||||||
|
free++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
iter = children2.iterator(); |
||||||
|
|
||||||
|
while (iter.hasNext()) { |
||||||
|
Node child = (Node) iter.next(); |
||||||
|
int v = child.valueNumber(); |
||||||
|
|
||||||
|
if (v != -1) { |
||||||
|
if (used[v] != 0) { |
||||||
|
used[v]--; |
||||||
|
|
||||||
|
} else { |
||||||
|
free--; |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
free--; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (free < 0) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
|
||||||
|
} else { |
||||||
|
// The children of the nodes in the SSAGraph must have
|
||||||
|
// the
|
||||||
|
// same value numbers and be in the same order.
|
||||||
|
Iterator iter1 = children1.iterator(); |
||||||
|
Iterator iter2 = children2.iterator(); |
||||||
|
|
||||||
|
while (iter1.hasNext() && iter2.hasNext()) { |
||||||
|
Node child1 = (Node) iter1.next(); |
||||||
|
Node child2 = (Node) iter2.next(); |
||||||
|
|
||||||
|
int v1 = child1.valueNumber(); |
||||||
|
int v2 = child2.valueNumber(); |
||||||
|
|
||||||
|
if (v1 != -1 && v2 != -1 && v1 != v2) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (iter1.hasNext() || iter2.hasNext()) { |
||||||
|
// Size mismatch.
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String traceMessage(String dateString) { |
||||||
|
return " Value Numbering: " + dateString; |
||||||
|
} |
||||||
|
|
||||||
|
public String preDebugMessage() { |
||||||
|
return "--------Doing value numbering--------"; |
||||||
|
} |
||||||
|
|
||||||
|
public String postDebugMessage() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
<html> |
||||||
|
<body> |
||||||
|
|
||||||
|
<p>Performs transformations (optimizations) on a control flow graph. |
||||||
|
There are several optimizations performed by classes in this package. |
||||||
|
Older Java compilers produced poor code for initializing arrays. |
||||||
|
BLOAT can replace this poor code with more efficient code by loading |
||||||
|
the array from the constant pool. Dead code elimination removes code |
||||||
|
from a method that does not contribute to the final output of the |
||||||
|
program.</p> |
||||||
|
|
||||||
|
<p>Value numbering associates a number with each expression such that |
||||||
|
if two expressions have the same number, they have the same value. A |
||||||
|
value folder is then used to eliminate redundent nodes from and to |
||||||
|
propagate constants through the control flow graph.</p> |
||||||
|
|
||||||
|
<p>Constant propagation removes unnecessary assignments by replacing |
||||||
|
variables that are assigned constant values with those values. Copy |
||||||
|
propagation removes unnecessary assignments to varibles to other |
||||||
|
variables.</p> |
||||||
|
|
||||||
|
<p>BLOAT was designed to optimize classes that were to be run inside a |
||||||
|
persistent system that required special opcodes to perform operation |
||||||
|
such as checking an object cache for a certain resident object. The |
||||||
|
analysis that BLOAT does can eliminate some of these checks.</p> |
||||||
|
|
||||||
|
<p>SSA-based partial redundency elimination (PRE) of expressions and |
||||||
|
access paths can also be performed on a control flow graph. If a |
||||||
|
calculation is redundent along one control flow path leading to a |
||||||
|
merge point, PRE computes it once along <b>all</b> paths, assigns the |
||||||
|
result to a variable, and replaces further occurrences of the |
||||||
|
calculation with that variable. This way, the expression is only |
||||||
|
computed once along any given control flow path.</p> |
||||||
|
|
||||||
|
<p>Finally, peephole optimizations are performed on Java bytecode. |
||||||
|
For instance, a push instruction followed by a pop instruction is |
||||||
|
useless and can be removed. Additionally, unreachable code is removed |
||||||
|
from the method.</p> |
||||||
|
|
||||||
|
<p>This package also contains several auxiliary classes that perform |
||||||
|
operations like determining whether or not an expression has side |
||||||
|
effects and comparing two nodes.</p> |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,82 @@ |
|||||||
|
/* |
||||||
|
* Class: AddressStoreStmt |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.Subroutine; |
||||||
|
|
||||||
|
/** |
||||||
|
* Associated with an AddressStoreStmt is a Subroutine whose address (offset in |
||||||
|
* the instruction sequence) is to be stored. Addresses may be loaded (using |
||||||
|
* <i>astore</i>), but cannot be reloaded. Therefore, AddressStoreStmt is |
||||||
|
* needed to differentiate between a regular (object reference) <i>astore</i> |
||||||
|
* which is modeled by a LocalExpr. |
||||||
|
* |
||||||
|
* @see Tree#visit_astore |
||||||
|
* @see Subroutine |
||||||
|
* @see LocalExpr |
||||||
|
*/ |
||||||
|
public class AddressStoreStmt extends Stmt { |
||||||
|
final Subroutine sub; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param sub |
||||||
|
* |
||||||
|
*/ |
||||||
|
public AddressStoreStmt(Subroutine sub) { |
||||||
|
this.sub = sub; |
||||||
|
} |
||||||
|
|
||||||
|
public Subroutine sub() { |
||||||
|
return sub; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitAddressStoreStmt(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new AddressStoreStmt(sub)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,146 @@ |
|||||||
|
/* |
||||||
|
* Class: ArithExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* ArithExpr represents a binary arithmetic expression. It consists of two |
||||||
|
* operands and an operator. |
||||||
|
*/ |
||||||
|
public class ArithExpr extends Expr { |
||||||
|
final char operation; // Arithmetic operator
|
||||||
|
|
||||||
|
Expr left; // Expression on left-hand side of operation
|
||||||
|
|
||||||
|
Expr right; // Expression on right-hand side of operation
|
||||||
|
|
||||||
|
// Operators...
|
||||||
|
public static final char ADD = '+'; |
||||||
|
|
||||||
|
public static final char SUB = '-'; |
||||||
|
|
||||||
|
public static final char DIV = '/'; |
||||||
|
|
||||||
|
public static final char MUL = '*'; |
||||||
|
|
||||||
|
public static final char REM = '%'; |
||||||
|
|
||||||
|
public static final char AND = '&'; |
||||||
|
|
||||||
|
public static final char IOR = '|'; |
||||||
|
|
||||||
|
public static final char XOR = '^'; |
||||||
|
|
||||||
|
public static final char CMP = '?'; |
||||||
|
|
||||||
|
public static final char CMPL = '<'; |
||||||
|
|
||||||
|
public static final char CMPG = '>'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param operation |
||||||
|
* Arithmetic operation that this expression performs. |
||||||
|
* @param left |
||||||
|
* Left-hand argument to operation. |
||||||
|
* @param right |
||||||
|
* Right-hand argument to operation. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public ArithExpr(char operation, Expr left, Expr right, Type type) { |
||||||
|
super(type); |
||||||
|
this.operation = operation; |
||||||
|
this.left = left; |
||||||
|
this.right = right; |
||||||
|
|
||||||
|
left.setParent(this); |
||||||
|
right.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int operation() { |
||||||
|
return operation; |
||||||
|
} |
||||||
|
|
||||||
|
public Expr left() { |
||||||
|
return left; |
||||||
|
} |
||||||
|
|
||||||
|
public Expr right() { |
||||||
|
return right; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
right.visit(visitor); |
||||||
|
left.visit(visitor); |
||||||
|
} else { |
||||||
|
left.visit(visitor); |
||||||
|
right.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitArithExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
return 1 + operation ^ left.exprHashCode() ^ right.exprHashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Compare this arithmetic expression to another Expression. |
||||||
|
* |
||||||
|
* @return True, if both expressions have the same contents. |
||||||
|
*/ |
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return other != null && other instanceof ArithExpr |
||||||
|
&& ((ArithExpr) other).operation == operation |
||||||
|
&& ((ArithExpr) other).left.equalsExpr(left) |
||||||
|
&& ((ArithExpr) other).right.equalsExpr(right); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new ArithExpr(operation, (Expr) left.clone(), |
||||||
|
(Expr) right.clone(), type)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
/* |
||||||
|
* Class: ArrayLengthExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>ArrayLengthExpr</tt> represents the <i>arraylength</i> opcode which |
||||||
|
* gets length of an array. |
||||||
|
*/ |
||||||
|
public class ArrayLengthExpr extends Expr { |
||||||
|
Expr array; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param array |
||||||
|
* Array whose length is sought. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public ArrayLengthExpr(Expr array, Type type) { |
||||||
|
super(type); |
||||||
|
this.array = array; |
||||||
|
array.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Expr array() { |
||||||
|
return array; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
array.visit(visitor); |
||||||
|
} else { |
||||||
|
array.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitArrayLengthExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
return 3 + array.exprHashCode() ^ (int) Assert.simple(type).hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return other != null && other instanceof ArrayLengthExpr |
||||||
|
&& ((ArrayLengthExpr) other).array.equalsExpr(array); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new ArrayLengthExpr((Expr) array.clone(), type)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
/* |
||||||
|
* Class: ArrayRefExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* ArrayRefExpr represents an expression that references an element in an array. |
||||||
|
*/ |
||||||
|
public class ArrayRefExpr extends MemRefExpr { |
||||||
|
Expr array; |
||||||
|
|
||||||
|
Expr index; |
||||||
|
|
||||||
|
final Type elementType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param array |
||||||
|
* The array whose element we are indexing. |
||||||
|
* @param index |
||||||
|
* The index into the array. |
||||||
|
* @param elementType |
||||||
|
* The type of elements in array. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public ArrayRefExpr(Expr array, Expr index, Type elementType, Type type) { |
||||||
|
super(type); |
||||||
|
this.array = array; |
||||||
|
this.index = index; |
||||||
|
this.elementType = elementType; |
||||||
|
|
||||||
|
array.setParent(this); |
||||||
|
index.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Expr array() { |
||||||
|
return array; |
||||||
|
} |
||||||
|
|
||||||
|
public Expr index() { |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
public Type elementType() { |
||||||
|
return elementType; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
index.visit(visitor); |
||||||
|
array.visit(visitor); |
||||||
|
} else { |
||||||
|
array.visit(visitor); |
||||||
|
index.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitArrayRefExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
return 4 + array.exprHashCode() ^ index.exprHashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return other != null && other instanceof ArrayRefExpr |
||||||
|
&& ((ArrayRefExpr) other).array.equalsExpr(array) |
||||||
|
&& ((ArrayRefExpr) other).index.equalsExpr(index); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new ArrayRefExpr((Expr) array.clone(), (Expr) index |
||||||
|
.clone(), elementType, type)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,454 @@ |
|||||||
|
/* |
||||||
|
* Class: AscendVisitor |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* AscendVisitor is the superclass of Type0Visitor and Type1Visitor, |
||||||
|
* conveniently containing the common code. It makes an upward traversal of the |
||||||
|
* tree as if it were a binary tree (nodes with more than two children, such as |
||||||
|
* a method call, are considered in a form similar to curried form). |
||||||
|
* |
||||||
|
* @author Thomas VanDrunen |
||||||
|
*/ |
||||||
|
|
||||||
|
public abstract class AscendVisitor extends TreeVisitor { |
||||||
|
|
||||||
|
HashMap defInfoMap; /* the same as the fields of Stack Optimizer */ |
||||||
|
|
||||||
|
HashMap useInfoMap; /* of the same name */ |
||||||
|
|
||||||
|
LocalExpr start; /* where we start the search from */ |
||||||
|
|
||||||
|
Node previous; |
||||||
|
|
||||||
|
Vector visited; |
||||||
|
|
||||||
|
public AscendVisitor(HashMap defInfoMap, HashMap useInfoMap) { |
||||||
|
this.defInfoMap = defInfoMap; |
||||||
|
this.useInfoMap = useInfoMap; |
||||||
|
|
||||||
|
visited = new Vector(); |
||||||
|
} |
||||||
|
|
||||||
|
abstract public void check(Node node); |
||||||
|
|
||||||
|
public void visitTree(Tree tree) { |
||||||
|
|
||||||
|
ListIterator iter = tree.stmts().listIterator( |
||||||
|
tree.stmts().lastIndexOf(previous)); |
||||||
|
|
||||||
|
if (iter.hasPrevious()) { |
||||||
|
Stmt p = (Stmt) iter.previous(); |
||||||
|
check(p); |
||||||
|
} |
||||||
|
/* |
||||||
|
* Object prev = iter.previous(); if (prev instanceof LocalExpr) |
||||||
|
* check(prev); |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
public void visitExprStmt(ExprStmt stmt) { |
||||||
|
|
||||||
|
previous = stmt; |
||||||
|
stmt.parent().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfCmpStmt(IfCmpStmt stmt) { |
||||||
|
|
||||||
|
if (stmt.right() == previous) |
||||||
|
check(stmt.left()); |
||||||
|
else if (stmt.left() == previous) { |
||||||
|
previous = stmt; |
||||||
|
stmt.parent().visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfZeroStmt(IfZeroStmt stmt) { |
||||||
|
|
||||||
|
previous = stmt; |
||||||
|
stmt.parent.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
|
||||||
|
LocalExpr[] targets = stmt.targets(); |
||||||
|
for (int i = 0; i < targets.length; i++) |
||||||
|
if (targets[i] == previous) |
||||||
|
if (i > 0) |
||||||
|
check(targets[i - 1]); |
||||||
|
else |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitLabelStmt(LabelStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitMonitorStmt(MonitorStmt stmt) { |
||||||
|
|
||||||
|
previous = stmt; |
||||||
|
stmt.parent().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiStmt(PhiStmt stmt) { |
||||||
|
|
||||||
|
if (stmt instanceof PhiCatchStmt) |
||||||
|
visitPhiCatchStmt((PhiCatchStmt) stmt); |
||||||
|
else if (stmt instanceof PhiJoinStmt) |
||||||
|
visitPhiJoinStmt((PhiJoinStmt) stmt); |
||||||
|
/* |
||||||
|
* else if (stmt instanceof PhiReturnStmt) |
||||||
|
* visitPhiReturnStmt((PhiReturnStmt) stmt); |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitDefExpr(DefExpr expr) { |
||||||
|
if (expr instanceof MemExpr) |
||||||
|
visitMemExpr((MemExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiCatchStmt(PhiCatchStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiJoinStmt(PhiJoinStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnExprStmt(ReturnExprStmt stmt) { |
||||||
|
|
||||||
|
previous = stmt; |
||||||
|
stmt.parent.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnStmt(ReturnStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitAddressStoreStmt(AddressStoreStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
|
||||||
|
if (expr.target() instanceof LocalExpr |
||||||
|
|| expr.target() instanceof StaticFieldExpr) { |
||||||
|
if (previous == expr.expr()) { // can't be target, because then
|
||||||
|
// it would be a definition, for which
|
||||||
|
// Type0Visitor is not called
|
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
else if (expr.target() instanceof ArrayRefExpr) { |
||||||
|
if (previous == expr.expr()) |
||||||
|
check(((ArrayRefExpr) expr.target()).index()); |
||||||
|
else if (previous == expr.target()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
else if (expr.target() instanceof FieldExpr) { |
||||||
|
if (previous == expr.expr()) |
||||||
|
check(expr.target()); |
||||||
|
else if (previous == expr.target()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
|
||||||
|
if (previous == stmt.index()) { |
||||||
|
previous = stmt; |
||||||
|
stmt.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitThrowStmt(ThrowStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitStmt(Stmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitSRStmt(SRStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitArithExpr(ArithExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.left()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} else if (previous == expr.right()) |
||||||
|
check(expr.left()); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitMemExpr(MemExpr expr) { |
||||||
|
|
||||||
|
if (expr instanceof MemRefExpr) |
||||||
|
visitMemRefExpr((MemRefExpr) expr); |
||||||
|
else if (expr instanceof VarExpr) |
||||||
|
visitVarExpr((VarExpr) expr); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitMemRefExpr(MemRefExpr expr) { |
||||||
|
if (expr instanceof FieldExpr) |
||||||
|
visitFieldExpr((FieldExpr) expr); |
||||||
|
else if (expr instanceof StaticFieldExpr) |
||||||
|
visitStaticFieldExpr((StaticFieldExpr) expr); |
||||||
|
else if (expr instanceof ArrayRefExpr) |
||||||
|
visitArrayRefExpr((ArrayRefExpr) expr); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.array()) { // the array reference is like the
|
||||||
|
previous = expr; // left child
|
||||||
|
expr.parent().visit(this); |
||||||
|
} else if (previous == expr.index()) // the index is like the
|
||||||
|
check(expr.array()); // right child
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallExpr(CallExpr expr) { |
||||||
|
if (expr instanceof CallMethodExpr) |
||||||
|
visitCallMethodExpr((CallMethodExpr) expr); |
||||||
|
if (expr instanceof CallStaticExpr) |
||||||
|
visitCallStaticExpr((CallStaticExpr) expr); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.receiver()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
else { |
||||||
|
Expr[] params = expr.params(); |
||||||
|
for (int i = 0; i < params.length; i++) |
||||||
|
if (params[i] == previous) |
||||||
|
if (i > 0) |
||||||
|
check(params[i - 1]); |
||||||
|
else |
||||||
|
check(expr.receiver()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
|
||||||
|
Expr[] params = expr.params(); |
||||||
|
for (int i = 0; i < params.length; i++) |
||||||
|
if (params[i] == previous) { |
||||||
|
if (i > 0) |
||||||
|
check(params[i - 1]); |
||||||
|
else { |
||||||
|
previous = expr; |
||||||
|
expr.parent().visit(this); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
|
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitConstantExpr(ConstantExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.object()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInstanceOfExpr(InstanceOfExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.expr()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitLocalExpr(LocalExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitNegExpr(NegExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.expr()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.size()) { |
||||||
|
previous = expr; |
||||||
|
expr.parent.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
|
||||||
|
Expr[] dims = expr.dimensions; |
||||||
|
for (int i = 0; i < dims.length; i++) |
||||||
|
if (dims[i] == previous) |
||||||
|
if (i > 0) |
||||||
|
check(dims[i - 1]); |
||||||
|
else { |
||||||
|
previous = expr; |
||||||
|
expr.parent().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCheckExpr(CheckExpr expr) { |
||||||
|
if (expr instanceof ZeroCheckExpr) |
||||||
|
visitZeroCheckExpr((ZeroCheckExpr) expr); |
||||||
|
else if (expr instanceof RCExpr) |
||||||
|
visitRCExpr((RCExpr) expr); |
||||||
|
else if (expr instanceof UCExpr) |
||||||
|
visitUCExpr((UCExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitZeroCheckExpr(ZeroCheckExpr expr) { |
||||||
|
/* |
||||||
|
* if (previous == expr.expr()) { previous = expr; |
||||||
|
* expr.parent.visit(this); } |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
public void visitRCExpr(RCExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitUCExpr(UCExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnAddressExpr(ReturnAddressExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitShiftExpr(ShiftExpr expr) { |
||||||
|
|
||||||
|
if (previous == expr.expr()) { // the expression to be shifted is like
|
||||||
|
previous = expr; // the left child
|
||||||
|
expr.parent().visit(this); |
||||||
|
} else if (previous == expr.bits()) // the bits shifted is like
|
||||||
|
check(expr.expr()); // the right child
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackExpr(StackExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
if (expr instanceof LocalExpr) |
||||||
|
visitLocalExpr((LocalExpr) expr); |
||||||
|
if (expr instanceof StackExpr) |
||||||
|
visitStackExpr((StackExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitNode(Node node) { |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
/* |
||||||
|
* Class: Assign |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
/** |
||||||
|
* Classes that implement Assign involve an assignment (definition). |
||||||
|
* |
||||||
|
* @see InitStmt |
||||||
|
* @see PhiStmt |
||||||
|
* @see StackManipStmt |
||||||
|
* @see StoreExpr |
||||||
|
*/ |
||||||
|
public interface Assign { |
||||||
|
/** |
||||||
|
* Returns the expressions that may be modified (defined) by this expression |
||||||
|
* or statement. |
||||||
|
*/ |
||||||
|
public abstract DefExpr[] defs(); |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* Class: CallExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
|
||||||
|
/** |
||||||
|
* <tt>CallExpr</tt> is a superclass of expressions that represent the |
||||||
|
* invocation of a method. It consists of an array of <tt>Expr</tt> that |
||||||
|
* represent the arguments to a method and a <tt>MethodRef</tt> that |
||||||
|
* represents the method itself. |
||||||
|
* |
||||||
|
* @see CallMethodExpr |
||||||
|
* @see CallStaticExpr |
||||||
|
*/ |
||||||
|
public abstract class CallExpr extends Expr { |
||||||
|
final Expr[] params; // The parameters to the method
|
||||||
|
|
||||||
|
final MethodRef method; // The method to be invoked
|
||||||
|
|
||||||
|
public int voltaPos; // used for placing swaps and stuff
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param params |
||||||
|
* Parameters to the method. Note that these parameters do not |
||||||
|
* contain parameter 0, the "this" pointer. |
||||||
|
* @param method |
||||||
|
* The method that is to be invoked. |
||||||
|
* @param type |
||||||
|
* The type of this expression (i.e. the return type of the |
||||||
|
* method being called). |
||||||
|
*/ |
||||||
|
public CallExpr(Expr[] params, MethodRef method) { |
||||||
|
super(method.type()); |
||||||
|
this.params = params; |
||||||
|
this.method = method; |
||||||
|
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
params[i].setParent(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public MethodRef method() { |
||||||
|
return method; |
||||||
|
} |
||||||
|
|
||||||
|
public Expr[] params() { |
||||||
|
return params; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,141 @@ |
|||||||
|
/* |
||||||
|
* Class: CallMethodExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
|
||||||
|
/** |
||||||
|
* CallMethodExpr represents the invocation of an object's method. In addition |
||||||
|
* to knowing what method is being called and its parameters, it also knows what |
||||||
|
* "kind" of method call it is (<tt>VIRTUAL</tt>, <tt>NONVIRTUAL</tt>, or |
||||||
|
* <tt>INTERFACE</tt>) and the object that is the reciever of this method |
||||||
|
* call. |
||||||
|
* |
||||||
|
* @see CallStaticExpr |
||||||
|
*/ |
||||||
|
public class CallMethodExpr extends CallExpr { |
||||||
|
// Different kinds of methods to call...
|
||||||
|
public static final int VIRTUAL = 0; // invokevirtual
|
||||||
|
|
||||||
|
public static final int NONVIRTUAL = 1; // invokespecial
|
||||||
|
|
||||||
|
public static final int INTERFACE = 2; // invokeinterface
|
||||||
|
|
||||||
|
Expr receiver; |
||||||
|
|
||||||
|
final int kind; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param kind |
||||||
|
* The kind (VIRTUAL, NONVIRTUAL, or INTERFACE) of method that is |
||||||
|
* being called. |
||||||
|
* @param receiver |
||||||
|
* The expression (object) whose method is being called. |
||||||
|
* @param params |
||||||
|
* Parameters to the method. |
||||||
|
* @param method |
||||||
|
* The method being called. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public CallMethodExpr(int kind, Expr receiver, Expr[] params, |
||||||
|
MethodRef method) { |
||||||
|
super(params, method); |
||||||
|
this.receiver = receiver; |
||||||
|
this.kind = kind; |
||||||
|
|
||||||
|
receiver.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int kind() { |
||||||
|
return kind; |
||||||
|
} |
||||||
|
|
||||||
|
public Expr receiver() { |
||||||
|
return receiver; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
for (int i = params.length - 1; i >= 0; i--) { |
||||||
|
params[i].visit(visitor); |
||||||
|
} |
||||||
|
|
||||||
|
receiver.visit(visitor); |
||||||
|
} else { |
||||||
|
receiver.visit(visitor); |
||||||
|
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
params[i].visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitCallMethodExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
int v = 5 + kind ^ receiver.exprHashCode(); |
||||||
|
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
v ^= params[i].exprHashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
return v; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
Expr[] p = new Expr[params.length]; |
||||||
|
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
p[i] = (Expr) params[i].clone(); |
||||||
|
} |
||||||
|
|
||||||
|
return copyInto(new CallMethodExpr(kind, (Expr) receiver.clone(), p, |
||||||
|
method)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
/* |
||||||
|
* Class: CallStaticExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.editor.MethodRef; |
||||||
|
|
||||||
|
/** |
||||||
|
* CallStaticExpr represents the <tt>invokestatic</tt> opcode which invokes a |
||||||
|
* class (static) method. Static methods can always be inlined. |
||||||
|
* |
||||||
|
* @see CallMethodExpr |
||||||
|
*/ |
||||||
|
public class CallStaticExpr extends CallExpr { |
||||||
|
// invokestatic
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param params |
||||||
|
* Parameters to the method. |
||||||
|
* @param method |
||||||
|
* The (class) method to be invoked. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public CallStaticExpr(Expr[] params, MethodRef method) { |
||||||
|
super(params, method); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
for (int i = params.length - 1; i >= 0; i--) { |
||||||
|
params[i].visit(visitor); |
||||||
|
} |
||||||
|
} else { |
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
params[i].visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitCallStaticExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
int v = 6; |
||||||
|
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
v ^= params[i].exprHashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
return v; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
Expr[] p = new Expr[params.length]; |
||||||
|
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
p[i] = (Expr) params[i].clone(); |
||||||
|
} |
||||||
|
|
||||||
|
return copyInto(new CallStaticExpr(p, method)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
/* |
||||||
|
* Class: CastExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* CastExpr represents an expression that casts an object to a given type. |
||||||
|
*/ |
||||||
|
public class CastExpr extends Expr { |
||||||
|
Expr expr; // An expression (object) to cast
|
||||||
|
|
||||||
|
final Type castType; // The Type to cast expr to
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param expr |
||||||
|
* Expression (object) to be cast. |
||||||
|
* @param type |
||||||
|
* The type to which to cast expr and as well as the type of this |
||||||
|
* expression. |
||||||
|
*/ |
||||||
|
public CastExpr(Expr expr, Type type) { |
||||||
|
this(expr, type, type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param expr |
||||||
|
* Expression (object) to be cast. |
||||||
|
* @param castType |
||||||
|
* The type to which to cast expr. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public CastExpr(Expr expr, Type castType, Type type) { |
||||||
|
super(type); |
||||||
|
this.expr = expr; |
||||||
|
this.castType = castType; |
||||||
|
|
||||||
|
expr.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Expr expr() { |
||||||
|
return expr; |
||||||
|
} |
||||||
|
|
||||||
|
public Type castType() { |
||||||
|
return castType; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
expr.visit(visitor); |
||||||
|
} else { |
||||||
|
expr.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitCastExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
return 7 + expr.exprHashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return other != null && other instanceof CastExpr |
||||||
|
&& ((CastExpr) other).castType.equals(castType) |
||||||
|
&& ((CastExpr) other).expr.equalsExpr(expr); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new CastExpr((Expr) expr.clone(), castType, type)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
/* |
||||||
|
* Class: CatchExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.cfg.FlowGraph; |
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* CatchExpr represents an expression that catches an exception. A CatchExpr is |
||||||
|
* used when evaluating a method's try-catch blocks when a control flow graph is |
||||||
|
* constructed. |
||||||
|
* |
||||||
|
* @see TryCatch |
||||||
|
* @see FlowGraph#FlowGraph |
||||||
|
* @see MethodEditor |
||||||
|
*/ |
||||||
|
public class CatchExpr extends Expr { |
||||||
|
final Type catchType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param catchType |
||||||
|
* The type of the exception that is being caught. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public CatchExpr(Type catchType, Type type) { |
||||||
|
super(type); |
||||||
|
this.catchType = catchType; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitCatchExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Type catchType() { |
||||||
|
return catchType; |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
return 8 + (int) Assert.simple(type).hashCode() ^ catchType.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
if (other instanceof CatchExpr) { |
||||||
|
CatchExpr c = (CatchExpr) other; |
||||||
|
|
||||||
|
if (catchType != null) { |
||||||
|
return catchType.equals(c.catchType); |
||||||
|
} else { |
||||||
|
return c.catchType == null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new CatchExpr(catchType, type)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
/* |
||||||
|
* Class: CheckExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* CheckExpr is a superclass for classes representing a check on an expression. |
||||||
|
* For instance, a CheckExpr is inserted into the tree before the divisor of a |
||||||
|
* divide operation. The CheckExpr checks to make sure that the divisor is not |
||||||
|
* zero. |
||||||
|
* |
||||||
|
* @see RCExpr |
||||||
|
* @see UCExpr |
||||||
|
* @see ZeroCheckExpr |
||||||
|
*/ |
||||||
|
public abstract class CheckExpr extends Expr { |
||||||
|
Expr expr; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param expr |
||||||
|
* An expression that is to be checked. |
||||||
|
* @param type |
||||||
|
* The type of this expression. |
||||||
|
*/ |
||||||
|
public CheckExpr(Expr expr, Type type) { |
||||||
|
super(type); |
||||||
|
this.expr = expr; |
||||||
|
expr.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
if (visitor.reverse()) { |
||||||
|
expr.visit(visitor); |
||||||
|
} else { |
||||||
|
expr.visit(visitor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the expression being checked. |
||||||
|
*/ |
||||||
|
public Expr expr() { |
||||||
|
return expr; |
||||||
|
} |
||||||
|
|
||||||
|
public int exprHashCode() { |
||||||
|
return 9 + expr.exprHashCode() ^ (int) Assert.simple(type).hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
return other != null && other instanceof CheckExpr |
||||||
|
&& ((CheckExpr) other).expr.equalsExpr(expr); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Class: CondExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* CondExpr is a superclass for conditional expressions. That is, an expression |
||||||
|
* that yields a true or false value. |
||||||
|
* |
||||||
|
* @see InstanceOfExpr |
||||||
|
*/ |
||||||
|
public abstract class CondExpr extends Expr { |
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param type |
||||||
|
* The Type of this expression. |
||||||
|
*/ |
||||||
|
public CondExpr(Type type) { |
||||||
|
super(type); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
/* |
||||||
|
* Class: ConstantExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* ConstantExpr represents a constant expression. It is used when opcodes <i>ldc</i>, |
||||||
|
* <i>iinc</i>, and <i>getstatic</i> are visited. It value must be an Integer, |
||||||
|
* Long, Float, Double, or String. |
||||||
|
*/ |
||||||
|
public class ConstantExpr extends Expr implements LeafExpr { |
||||||
|
// ldc
|
||||||
|
|
||||||
|
final Object value; // The operand to the ldc instruction
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param value |
||||||
|
* The operand of the ldc instruction |
||||||
|
* @param type |
||||||
|
* The Type of the operand |
||||||
|
*/ |
||||||
|
public ConstantExpr(Object value, Type type) { |
||||||
|
super(type); |
||||||
|
this.value = value; |
||||||
|
/* |
||||||
|
* Assert.isTrue(((value == null)||(value instanceof Integer)||(value |
||||||
|
* instanceof Long)|| (value instanceof Float)||(value instanceof |
||||||
|
* Double)|| (value instanceof String)||(value instanceof Byte)|| (value |
||||||
|
* instanceof Short)||(value instanceof Boolean)), "Illegal ConstantExpr |
||||||
|
* value:" + value); |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return The operand of the ldc instruction |
||||||
|
*/ |
||||||
|
public Object value() { |
||||||
|
return value; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitConstantExpr(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return A hash code for this expression. |
||||||
|
*/ |
||||||
|
public int exprHashCode() { |
||||||
|
if (value != null) { |
||||||
|
return 10 + value.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
return 10; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Compare this ConstantExpr to another Expr. |
||||||
|
* |
||||||
|
* @param other |
||||||
|
* An Expr to compare this to. |
||||||
|
* |
||||||
|
* @return True, if this and other are the same (that is, have the same |
||||||
|
* contents). |
||||||
|
*/ |
||||||
|
public boolean equalsExpr(Expr other) { |
||||||
|
if (!(other instanceof ConstantExpr)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (value == null) { |
||||||
|
return ((ConstantExpr) other).value == null; |
||||||
|
} |
||||||
|
|
||||||
|
if (((ConstantExpr) other).value == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return ((ConstantExpr) other).value.equals(value); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new ConstantExpr(value, type)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,136 @@ |
|||||||
|
/* |
||||||
|
* Class: DefExpr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* An expression in which a definition occurs. Each instance has a unique |
||||||
|
* version number associated with it. |
||||||
|
*/ |
||||||
|
public abstract class DefExpr extends Expr { |
||||||
|
Set uses; // Expressions in which the definition is used
|
||||||
|
|
||||||
|
int version; // Which number DefExpr is this?
|
||||||
|
|
||||||
|
static int next = 0; // Total number of DefExprs
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param type |
||||||
|
* The Type (descriptor) of this expression |
||||||
|
*/ |
||||||
|
public DefExpr(Type type) { |
||||||
|
super(type); |
||||||
|
uses = new LinkedHashSet(); |
||||||
|
version = next++; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Clean up this expression. Notify all the expressions that use this |
||||||
|
* definition that it is no longer their defining expression. |
||||||
|
*/ |
||||||
|
public void cleanupOnly() { |
||||||
|
super.cleanupOnly(); |
||||||
|
|
||||||
|
List a = new ArrayList(uses); |
||||||
|
|
||||||
|
uses.clear(); |
||||||
|
|
||||||
|
Iterator e = a.iterator(); |
||||||
|
|
||||||
|
while (e.hasNext()) { |
||||||
|
Expr use = (Expr) e.next(); |
||||||
|
use.setDef(null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns Number DefExpr this is. This is also the SSA version number of |
||||||
|
* the expression that this <tt>DefExpr</tt> defines. |
||||||
|
*/ |
||||||
|
public int version() { |
||||||
|
return version; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines whether or not this <tt>DefExpr</tt> defines a local |
||||||
|
* variable in its parent. |
||||||
|
* |
||||||
|
* @see Assign#defs |
||||||
|
*/ |
||||||
|
public boolean isDef() { |
||||||
|
if (parent instanceof Assign) { |
||||||
|
DefExpr[] defs = ((Assign) parent).defs(); |
||||||
|
|
||||||
|
if (defs != null) { |
||||||
|
for (int i = 0; i < defs.length; i++) { |
||||||
|
if (defs[i] == this) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the <tt>Expr</tt>s in which the variable defined by this are |
||||||
|
* used. |
||||||
|
*/ |
||||||
|
public Collection uses() { |
||||||
|
return new LinkedHashSet(uses); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasUse(Expr use) { |
||||||
|
return uses.contains(use); |
||||||
|
} |
||||||
|
|
||||||
|
protected void addUse(Expr use) { |
||||||
|
uses.add(use); |
||||||
|
} |
||||||
|
|
||||||
|
protected void removeUse(Expr use) { |
||||||
|
uses.remove(use); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Class: DefInformation |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
/** |
||||||
|
* DefInformation contains information about the definition of a local variable |
||||||
|
* |
||||||
|
* @author Thomas VanDrunen |
||||||
|
*/ |
||||||
|
public class DefInformation { |
||||||
|
|
||||||
|
int type1s; |
||||||
|
|
||||||
|
int uses; |
||||||
|
|
||||||
|
int usesFound; |
||||||
|
|
||||||
|
public DefInformation(int uses) { |
||||||
|
type1s = 0; |
||||||
|
this.uses = uses; |
||||||
|
usesFound = 0; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,452 @@ |
|||||||
|
/* |
||||||
|
* Class: DescendVisitor |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* DecsendVisitor is the superclass of a few private classes of Type0Visitor and |
||||||
|
* Type1Visitor. It descends the tree, keeping track of the number of right |
||||||
|
* links that have been taken. |
||||||
|
*/ |
||||||
|
public abstract class DescendVisitor extends TreeVisitor { |
||||||
|
|
||||||
|
HashMap useInfoMap; |
||||||
|
|
||||||
|
HashMap defInfoMap; |
||||||
|
|
||||||
|
boolean found; |
||||||
|
|
||||||
|
Node beginNode; // where this visitor starts its search from
|
||||||
|
|
||||||
|
LocalExpr start; // where the original search began
|
||||||
|
|
||||||
|
int exchangeFactor; |
||||||
|
|
||||||
|
public DescendVisitor(HashMap useInfoMap, HashMap defInfoMap) { |
||||||
|
this.useInfoMap = useInfoMap; |
||||||
|
this.defInfoMap = defInfoMap; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean search(Node beginNode, LocalExpr start) { |
||||||
|
this.beginNode = beginNode; |
||||||
|
this.start = start; |
||||||
|
exchangeFactor = 0; |
||||||
|
found = false; |
||||||
|
|
||||||
|
beginNode.visit(this); |
||||||
|
|
||||||
|
return found; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitExprStmt(ExprStmt stmt) { |
||||||
|
stmt.expr().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfStmt(IfStmt stmt) { |
||||||
|
|
||||||
|
if (stmt instanceof IfCmpStmt) |
||||||
|
visitIfCmpStmt((IfCmpStmt) stmt); |
||||||
|
else if (stmt instanceof IfZeroStmt) |
||||||
|
visitIfZeroStmt((IfZeroStmt) stmt); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfCmpStmt(IfCmpStmt stmt) { |
||||||
|
stmt.left().visit(this); // search the left branch
|
||||||
|
if (!found) { // if nothing has been found
|
||||||
|
exchangeFactor++; // increase the exchange factor,
|
||||||
|
if (stmt.left().type().getSize() == 2) |
||||||
|
exchangeFactor++; // twice to get
|
||||||
|
// around wides
|
||||||
|
if (exchangeFactor < 3) |
||||||
|
stmt.right().visit(this); // search the right branch.
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitIfZeroStmt(IfZeroStmt stmt) { |
||||||
|
|
||||||
|
stmt.expr().visit(this); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitInitStmt(InitStmt stmt) { |
||||||
|
|
||||||
|
// would have been checked by the Type0Visitor
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitGotoStmt(GotoStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitLabelStmt(LabelStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitMonitorStmt(MonitorStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiStmt(PhiStmt stmt) { |
||||||
|
if (stmt instanceof PhiCatchStmt) |
||||||
|
visitPhiCatchStmt((PhiCatchStmt) stmt); |
||||||
|
else if (stmt instanceof PhiJoinStmt) |
||||||
|
visitPhiJoinStmt((PhiJoinStmt) stmt); |
||||||
|
/* |
||||||
|
* else if (stmt instanceof PhiReturnStmt) |
||||||
|
* visitPhiReturnStmt((PhiReturnStmt) stmt); |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCatchExpr(CatchExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitDefExpr(DefExpr expr) { |
||||||
|
if (expr instanceof MemExpr) |
||||||
|
visitMemExpr((MemExpr) expr); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitStackManipStmt(StackManipStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiCatchStmt(PhiCatchStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitPhiJoinStmt(PhiJoinStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitRetStmt(RetStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnExprStmt(ReturnExprStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnStmt(ReturnStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitAddressStoreStmt(AddressStoreStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// StoreExprs are very difficult because they represent several
|
||||||
|
// types of expressions. What we do will depend on what the target
|
||||||
|
// of the store is: ArrayRefExpr, FieldExpr, StaticFieldExpr,
|
||||||
|
// or LocalExpr
|
||||||
|
|
||||||
|
public void visitStoreExpr(StoreExpr expr) { |
||||||
|
MemExpr target = expr.target(); |
||||||
|
|
||||||
|
if (target instanceof ArrayRefExpr) { |
||||||
|
// ArrayRefExpr: the store will be something like an astore
|
||||||
|
// which manipulates the stack like
|
||||||
|
// arrayref, index, val => ...
|
||||||
|
// so, think of the tree like
|
||||||
|
// (StoreExpr)
|
||||||
|
// / \
|
||||||
|
// Array Ref .
|
||||||
|
// / \
|
||||||
|
// index value
|
||||||
|
// This is unlike the structure of the tree BLOAT uses for
|
||||||
|
// intermediate representation, but it better relates to what's
|
||||||
|
// on the stack at what time
|
||||||
|
|
||||||
|
((ArrayRefExpr) target).array().visit(this); // visit the
|
||||||
|
// left child
|
||||||
|
if (!found) { // if match wasn't found
|
||||||
|
exchangeFactor++; // take the right branch
|
||||||
|
if (exchangeFactor < 3) { // (an array ref isn't wide)
|
||||||
|
// visit next left child
|
||||||
|
((ArrayRefExpr) target).index().visit(this); |
||||||
|
if (!found) { // if match wasn't found
|
||||||
|
exchangeFactor++; |
||||||
|
if (exchangeFactor < 3) // (an index isn't wide)
|
||||||
|
expr.expr().visit(this); // search the right
|
||||||
|
// branch
|
||||||
|
} // end seaching RR
|
||||||
|
} |
||||||
|
} // end searching R
|
||||||
|
} // end case where target is ArrayRefExpr
|
||||||
|
|
||||||
|
else if (target instanceof FieldExpr) { |
||||||
|
// FieldExpr: the store will be like a putfield
|
||||||
|
// which manipulates the stack like
|
||||||
|
// objref, val => ...
|
||||||
|
// so, think of the tree like
|
||||||
|
// (StoreExpr)
|
||||||
|
// / \
|
||||||
|
// Object Ref value
|
||||||
|
|
||||||
|
((FieldExpr) target).object().visit(this); // visit the left child
|
||||||
|
|
||||||
|
if (!found) { |
||||||
|
exchangeFactor++; // (an object ref isn't wide)
|
||||||
|
if (exchangeFactor < 3) { |
||||||
|
expr.expr().visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} // end case where target is FieldRef
|
||||||
|
|
||||||
|
else if (target instanceof StaticFieldExpr) { |
||||||
|
// StaticFieldExpr: the store will be like a putstatic
|
||||||
|
// which manipulates the stack like
|
||||||
|
// val => ...
|
||||||
|
// so, think of the tree like
|
||||||
|
// (StoreExpr)
|
||||||
|
// /
|
||||||
|
// value
|
||||||
|
|
||||||
|
expr.expr.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
else if (target instanceof LocalExpr) { |
||||||
|
// LocalExpr: the store will be like istore/astore/etc.
|
||||||
|
// which manipulates the stack like
|
||||||
|
// val => ...
|
||||||
|
// so, think of the tree like
|
||||||
|
// (StoreExpr)
|
||||||
|
// /
|
||||||
|
// value
|
||||||
|
|
||||||
|
expr.expr.visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitJsrStmt(JsrStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitSwitchStmt(SwitchStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitThrowStmt(ThrowStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitStmt(Stmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitSCStmt(SCStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitSRStmt(SRStmt stmt) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitArithExpr(ArithExpr expr) { // important one
|
||||||
|
expr.left().visit(this); // visit the left branch
|
||||||
|
|
||||||
|
if (!found) { // if a match isn't found yet
|
||||||
|
exchangeFactor++; // increase the exchange factor
|
||||||
|
if (expr.left().type().getSize() == 2) |
||||||
|
exchangeFactor++; |
||||||
|
// twice if wide
|
||||||
|
if (exchangeFactor < 3) { |
||||||
|
expr.right().visit(this); // visit right branch
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayLengthExpr(ArrayLengthExpr expr) { |
||||||
|
expr.array().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitMemExpr(MemExpr expr) { |
||||||
|
if (expr instanceof LocalExpr) |
||||||
|
visitLocalExpr((LocalExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitMemRefExpr(MemRefExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitArrayRefExpr(ArrayRefExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallExpr(CallExpr expr) { |
||||||
|
if (expr instanceof CallMethodExpr) |
||||||
|
visitCallMethodExpr((CallMethodExpr) expr); |
||||||
|
else if (expr instanceof CallStaticExpr) |
||||||
|
visitCallStaticExpr((CallStaticExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallMethodExpr(CallMethodExpr expr) { |
||||||
|
// Method invocations are to be thought of, in terms of
|
||||||
|
// binary expression trees, as
|
||||||
|
// (CallMethodExpr)
|
||||||
|
// / \
|
||||||
|
// receiver .
|
||||||
|
// / \
|
||||||
|
// arg1 .
|
||||||
|
// / \
|
||||||
|
// arg2 .
|
||||||
|
// / \
|
||||||
|
// arg3 ...
|
||||||
|
// This might be the opposite of what one would think in terms
|
||||||
|
// of currying (ie, one might think of currying in terms of
|
||||||
|
// left associativity), but this gives a better picture of what
|
||||||
|
// happens to the stack when invokestatic or invokevirtual is called:
|
||||||
|
// objectref, [arg1, [arg2 ...]] => ...
|
||||||
|
|
||||||
|
expr.receiver().visit(this); |
||||||
|
Expr[] params = expr.params(); |
||||||
|
if (!found && exchangeFactor < 2 && params.length > 0) { |
||||||
|
exchangeFactor++; // (reciever won't be wide)
|
||||||
|
params[0].visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitCallStaticExpr(CallStaticExpr expr) { |
||||||
|
|
||||||
|
Expr[] params = expr.params(); |
||||||
|
if (params.length > 0) |
||||||
|
params[0].visit(this); |
||||||
|
if (!found && exchangeFactor < 2 && params.length > 1) { |
||||||
|
exchangeFactor++; |
||||||
|
params[1].visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCastExpr(CastExpr expr) { |
||||||
|
expr.expr().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitConstantExpr(ConstantExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitFieldExpr(FieldExpr expr) { |
||||||
|
expr.object.visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitInstanceOfExpr(InstanceOfExpr expr) { |
||||||
|
expr.expr().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
/* needs to be different for Type0 and Type1 */ |
||||||
|
public abstract void visitLocalExpr(LocalExpr expr); |
||||||
|
|
||||||
|
public void visitNegExpr(NegExpr expr) { |
||||||
|
expr.expr().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewArrayExpr(NewArrayExpr expr) { |
||||||
|
expr.size().visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewExpr(NewExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitNewMultiArrayExpr(NewMultiArrayExpr expr) { |
||||||
|
// Think of the tree like
|
||||||
|
// (NewMultiArrayExpr)
|
||||||
|
// / \
|
||||||
|
// count1 .
|
||||||
|
// / \
|
||||||
|
// count2 etc.
|
||||||
|
// since multianewarray manipulates the stack like
|
||||||
|
// count1, [count1 ...] => ...
|
||||||
|
|
||||||
|
Expr[] dims = expr.dimensions(); |
||||||
|
if (dims.length > 0) |
||||||
|
dims[0].visit(this); |
||||||
|
if (!found && exchangeFactor < 2 && dims.length > 1) { |
||||||
|
exchangeFactor++; // (count1 won't be wide)
|
||||||
|
dims[1].visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitCheckExpr(CheckExpr expr) { |
||||||
|
if (expr instanceof ZeroCheckExpr) |
||||||
|
visitZeroCheckExpr((ZeroCheckExpr) expr); |
||||||
|
else if (expr instanceof RCExpr) |
||||||
|
visitRCExpr((RCExpr) expr); |
||||||
|
else if (expr instanceof UCExpr) |
||||||
|
visitUCExpr((UCExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitZeroCheckExpr(ZeroCheckExpr expr) { |
||||||
|
// perhaps add something here
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitRCExpr(RCExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitUCExpr(UCExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitReturnAddressExpr(ReturnAddressExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitShiftExpr(ShiftExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitVarExpr(VarExpr expr) { |
||||||
|
if (expr instanceof LocalExpr) |
||||||
|
visitLocalExpr((LocalExpr) expr); |
||||||
|
} |
||||||
|
|
||||||
|
public void visitStaticFieldExpr(StaticFieldExpr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitExpr(Expr expr) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
/* |
||||||
|
* Class: EliminationInformation |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author John N Zigman |
||||||
|
* @author Arrin Daley |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class EliminationInformation { |
||||||
|
|
||||||
|
public Vector Occurences; |
||||||
|
|
||||||
|
public int type1s; |
||||||
|
|
||||||
|
public int uniqueNumber; |
||||||
|
|
||||||
|
static int nextUN = 0; |
||||||
|
|
||||||
|
public EliminationInformation() { |
||||||
|
uniqueNumber = nextUN; |
||||||
|
nextUN++; |
||||||
|
Occurences = new Vector(); |
||||||
|
type1s = 0; |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return uniqueNumber + "+" + type1s + Occurences.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,246 @@ |
|||||||
|
/* |
||||||
|
* Class: Expr |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
import org.apache.bcel.generic.Type; |
||||||
|
|
||||||
|
import edu.purdue.cs.bloat.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Expr is the superclass for a number of other classes representing expressions |
||||||
|
* in byte code. Expressions are typed and may be nested. |
||||||
|
* |
||||||
|
* @see DefExpr |
||||||
|
*/ |
||||||
|
public abstract class Expr extends Node implements Cloneable { |
||||||
|
protected Type type; // The type (descriptor) of this expression
|
||||||
|
|
||||||
|
private DefExpr def; // The expression in which this expression
|
||||||
|
|
||||||
|
// is defined (if applicable)
|
||||||
|
private Object comparator; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. Initializes an expression with a given type. |
||||||
|
* |
||||||
|
* @param type |
||||||
|
* The initial Type (descriptor) of this expression. |
||||||
|
*/ |
||||||
|
public Expr(Type type) { |
||||||
|
this.def = null; |
||||||
|
this.comparator = new ExprComparator(); |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the type of this expression. Returns whether or not the type changed |
||||||
|
* as a result of calling this method. |
||||||
|
*/ |
||||||
|
public boolean setType(Type type) { |
||||||
|
|
||||||
|
if (!this.type.equals(type)) { |
||||||
|
// Assert.isTrue((type.equals(Type.OBJECT) ||
|
||||||
|
// type.equals(Type.INT) ||
|
||||||
|
// type.equals(Type.LONG) || type.equals(Type.FLOAT) ||
|
||||||
|
// type.equals(Type.DOUBLE) || type.equals(Type.STRING) ||
|
||||||
|
// type.equals(Type.BYTE) || type.equals(Type.SHORT) ||
|
||||||
|
// type.equals(Type.BOOLEAN)),
|
||||||
|
// "Illegal ConstantExpr type:" + type);
|
||||||
|
|
||||||
|
// if (Tree.DEBUG) {
|
||||||
|
// System.out.println(" setting typeof(" + this + ") = " +
|
||||||
|
// type);
|
||||||
|
// }
|
||||||
|
this.type = type; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns whether or not this expression is a defining occurrence. By |
||||||
|
* default, false is returned. |
||||||
|
*/ |
||||||
|
public boolean isDef() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the statement to which this expression belongs. It essentially |
||||||
|
* searches up the expression tree for this expression's first ancestor |
||||||
|
* which is a Stmt. |
||||||
|
*/ |
||||||
|
public Stmt stmt() { |
||||||
|
Node p = parent; |
||||||
|
|
||||||
|
while (!(p instanceof Stmt)) { |
||||||
|
Assert.isTrue(!(p instanceof Tree), "Invalid ancestor of " + this); |
||||||
|
Assert.isTrue(p != null, "Null ancestor of " + this); |
||||||
|
p = p.parent; |
||||||
|
} |
||||||
|
|
||||||
|
return (Stmt) p; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the Type of this expression. |
||||||
|
*/ |
||||||
|
public Type type() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Cleans up this expression only, not its children. |
||||||
|
*/ |
||||||
|
public void cleanupOnly() { |
||||||
|
setDef(null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the expression that defines this expression. |
||||||
|
* |
||||||
|
* @param def |
||||||
|
* Defining expression. |
||||||
|
*/ |
||||||
|
public void setDef(DefExpr def) { |
||||||
|
// if (Tree.DEBUG) {
|
||||||
|
// System.out.println(" setting def of " + this +
|
||||||
|
// " (" + System.identityHashCode(this) + ") to " + def);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (this.def == def) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// If this Expr already had a defining statement, remove this from the
|
||||||
|
// DefExpr use list.
|
||||||
|
if (this.def != null) { |
||||||
|
this.def.removeUse(this); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.isDef()) { |
||||||
|
Assert.isTrue(def == this || def == null); |
||||||
|
this.def = null; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
this.def = def; |
||||||
|
|
||||||
|
if (this.def != null) { |
||||||
|
this.def.addUse(this); // This Expr is a use of def
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the expression in which this Expr is defined. |
||||||
|
*/ |
||||||
|
public DefExpr def() { |
||||||
|
return def; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the hash code for this expresion. |
||||||
|
*/ |
||||||
|
public abstract int exprHashCode(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Compares this expression to another. |
||||||
|
* |
||||||
|
* @param other |
||||||
|
* Expr to which to compare this. |
||||||
|
*/ |
||||||
|
public abstract boolean equalsExpr(Expr other); |
||||||
|
|
||||||
|
public abstract Object clone(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Copies the contents of another expression in this one. |
||||||
|
* |
||||||
|
* @param expr |
||||||
|
* The expression from which to copy. |
||||||
|
*/ |
||||||
|
protected Expr copyInto(Expr expr) { |
||||||
|
expr = (Expr) super.copyInto(expr); |
||||||
|
|
||||||
|
DefExpr def = def(); |
||||||
|
|
||||||
|
if (isDef()) { |
||||||
|
expr.setDef(null); |
||||||
|
} else { |
||||||
|
expr.setDef(def); |
||||||
|
} |
||||||
|
|
||||||
|
return expr; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns an Object that can be used to compare other Expr to this. |
||||||
|
*/ |
||||||
|
public Object comparator() { |
||||||
|
return comparator; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* ExprComparator is used to provide a different notion of equality among |
||||||
|
* expressions than the default ==. In most cases, we want ==, but |
||||||
|
* occasionally we want the equalsExpr() functionality when inserting in |
||||||
|
* Hashtables, etc. |
||||||
|
*/ |
||||||
|
private class ExprComparator { |
||||||
|
Expr expr = Expr.this; |
||||||
|
|
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj instanceof ExprComparator) { |
||||||
|
Expr other = ((ExprComparator) obj).expr; |
||||||
|
return expr.equalsExpr(other) |
||||||
|
&& Assert.simple(expr.type).equals( |
||||||
|
Assert.simple(other.type)); |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return Expr.this.exprHashCode(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* Class: ExprStmt |
||||||
|
* Version: |
||||||
|
* Date: |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms are permitted |
||||||
|
* provided that this entire copyright notice is duplicated in all |
||||||
|
* such copies, and that any documentation, announcements, and other |
||||||
|
* materials related to such distribution and use acknowledge that the |
||||||
|
* software was developed at Purdue University, West Lafayette, IN by |
||||||
|
* @author Antony Hosking |
||||||
|
* @author David Whitlock |
||||||
|
* @author Nathaniel Nystrom |
||||||
|
* No charge may be made for copies, derivations, or distributions of |
||||||
|
* this material without the express written consent of the copyright |
||||||
|
* holder. Neither the name of the University nor the name of the |
||||||
|
* author may be used to endorse or promote products derived from this |
||||||
|
* material without specific prior written permission. THIS SOFTWARE |
||||||
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
||||||
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* |
||||||
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was |
||||||
|
* contributed by The Australian National University by |
||||||
|
* @author Arrin Daley |
||||||
|
* @author John N Zigman |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Java is a trademark of Sun Microsystems, Inc. |
||||||
|
*/ |
||||||
|
|
||||||
|
package edu.purdue.cs.bloat.tree; |
||||||
|
|
||||||
|
/** |
||||||
|
* ExprStmt is a statement consisting of an expression. |
||||||
|
* |
||||||
|
* @see Expr |
||||||
|
*/ |
||||||
|
public class ExprStmt extends Stmt { |
||||||
|
Expr expr; // Expression contained in this statement
|
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param expr |
||||||
|
* The expression contained in this statement. |
||||||
|
*/ |
||||||
|
public ExprStmt(Expr expr) { |
||||||
|
this.expr = expr; |
||||||
|
expr.setParent(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Expr expr() { |
||||||
|
return expr; |
||||||
|
} |
||||||
|
|
||||||
|
public void visitForceChildren(TreeVisitor visitor) { |
||||||
|
expr.visit(visitor); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(TreeVisitor visitor) { |
||||||
|
visitor.visitExprStmt(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Object clone() { |
||||||
|
return copyInto(new ExprStmt((Expr) expr.clone())); |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue