Mirror of the BLOAT repository
https://www.cs.purdue.edu/homes/hosking/bloat/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
306 lines
9.7 KiB
306 lines
9.7 KiB
/*
|
|
* 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---------";
|
|
}
|
|
}
|
|
|