replace broken ExpandedControlFlowGraph with hopefully somewhat less broken ExplodedControlFlowGraph

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@1499 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
sjfink 2007-07-17 13:46:35 +00:00
parent 2c4fd1fc93
commit b9465e1bcc
5 changed files with 432 additions and 1490 deletions

View File

@ -40,8 +40,8 @@ import com.ibm.wala.ipa.slicer.Statement.Kind;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.analysis.ExpandedControlFlowGraph;
import com.ibm.wala.ssa.analysis.ExpandedControlFlowGraph.SingleInstructionBasicBlock;
import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph;
import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph.ExplodedBasicBlock;
import com.ibm.wala.util.collections.Filter;
import com.ibm.wala.util.collections.FilterIterator;
import com.ibm.wala.util.collections.HashMapFactory;
@ -104,12 +104,11 @@ public class HeapReachingDefs {
}
System.err.println("Reaching Defs " + node);
if (VERBOSE) {
// System.err.println("Reaching Defs " + node);
System.err.println(statements.size());
}
// create a control flow graph with one instruction per basic block.
ExpandedControlFlowGraph cfg = new ExpandedControlFlowGraph(ir);
ExplodedControlFlowGraph cfg = ExplodedControlFlowGraph.make(ir);
// create a mapping between statements and integers, used in bit vectors
// shortly
@ -137,11 +136,11 @@ public class HeapReachingDefs {
final Map<Statement, OrdinalSet<Statement>> delegate = HashMapFactory.make();
private final HeapExclusions exclusions;
private final CallGraph cg;
RDMap(BitVectorSolver<IBasicBlock> solver, OrdinalSetMapping<Statement> domain, CGNode node, ExtendedHeapModel h,
PointerAnalysis pa, Map<CGNode, OrdinalSet<PointerKey>> mod, ExpandedControlFlowGraph cfg,
PointerAnalysis pa, Map<CGNode, OrdinalSet<PointerKey>> mod, ExplodedControlFlowGraph cfg,
Map<Integer, NormalStatement> ssaInstructionIndex2Statement, HeapExclusions exclusions, CallGraph cg) {
if (VERBOSE) {
System.err.println("Init pointer Key mod ");
@ -160,7 +159,7 @@ public class HeapReachingDefs {
private void eagerPopulate(Map<PointerKey, MutableIntSet> pointerKeyMod, BitVectorSolver<IBasicBlock> solver,
OrdinalSetMapping<Statement> domain, CGNode node, ExtendedHeapModel h, PointerAnalysis pa,
Map<CGNode, OrdinalSet<PointerKey>> mod, ExpandedControlFlowGraph cfg,
Map<CGNode, OrdinalSet<PointerKey>> mod, ExplodedControlFlowGraph cfg,
Map<Integer, NormalStatement> ssaInstruction2Statement) {
for (Statement s : domain) {
delegate.put(s, computeResult(s, pointerKeyMod, solver, domain, node, h, pa, mod, cfg, ssaInstruction2Statement));
@ -169,11 +168,6 @@ public class HeapReachingDefs {
/**
* For each pointerKey, which statements may def it
*
* @param domain
* @param node
* @param h
* @param pa
*/
private Map<PointerKey, MutableIntSet> initPointerKeyMod(OrdinalSetMapping<Statement> domain, CGNode node, ExtendedHeapModel h,
PointerAnalysis pa) {
@ -285,7 +279,7 @@ public class HeapReachingDefs {
*/
private OrdinalSet<Statement> computeResult(Statement s, Map<PointerKey, MutableIntSet> pointerKeyMod,
BitVectorSolver<IBasicBlock> solver, OrdinalSetMapping<Statement> domain, CGNode node, ExtendedHeapModel h,
PointerAnalysis pa, Map<CGNode, OrdinalSet<PointerKey>> mod, ExpandedControlFlowGraph cfg,
PointerAnalysis pa, Map<CGNode, OrdinalSet<PointerKey>> mod, ExplodedControlFlowGraph cfg,
Map<Integer, NormalStatement> ssaInstructionIndex2Statement) {
switch (s.getKind()) {
case NORMAL:
@ -367,7 +361,7 @@ public class HeapReachingDefs {
*/
private static Map<Statement, OrdinalSet<Statement>> makeResult(BitVectorSolver<IBasicBlock> solver,
OrdinalSetMapping<Statement> domain, CGNode node, ExtendedHeapModel h, PointerAnalysis pa,
Map<CGNode, OrdinalSet<PointerKey>> mod, ExpandedControlFlowGraph cfg,
Map<CGNode, OrdinalSet<PointerKey>> mod, ExplodedControlFlowGraph cfg,
Map<Integer, NormalStatement> ssaInstructionIndex2Statement, HeapExclusions exclusions, CallGraph cg) {
return new RDMap(solver, domain, node, h, pa, mod, cfg, ssaInstructionIndex2Statement, exclusions, cg);
@ -447,7 +441,7 @@ public class HeapReachingDefs {
private final CGNode node;
private final ExpandedControlFlowGraph cfg;
private final ExplodedControlFlowGraph cfg;
private final OrdinalSetMapping<Statement> domain;
@ -466,7 +460,7 @@ public class HeapReachingDefs {
*/
private final IBinaryNaturalRelation heapReturnCaller = new BasicNaturalRelation();
public RD(CGNode node, ExpandedControlFlowGraph cfg, PointerAnalysis pa, OrdinalSetMapping<Statement> domain,
public RD(CGNode node, ExplodedControlFlowGraph cfg, PointerAnalysis pa, OrdinalSetMapping<Statement> domain,
Map<Integer, NormalStatement> ssaInstructionIndex2Statement, HeapExclusions exclusions) {
this.node = node;
this.cfg = cfg;
@ -491,7 +485,7 @@ public class HeapReachingDefs {
}
public UnaryOperator getEdgeTransferFunction(IBasicBlock src, IBasicBlock dst) {
SingleInstructionBasicBlock s = (SingleInstructionBasicBlock) src;
ExplodedBasicBlock s = (ExplodedBasicBlock) src;
if (s.getInstruction() != null && !(s.getInstruction() instanceof SSAInvokeInstruction)
&& !cfg.getNormalSuccessors(src).contains(dst)) {
// if the edge only happens due to exceptional control flow, then no
@ -538,7 +532,7 @@ public class HeapReachingDefs {
* @return int set representing the heap def statements that are gen'ed by
* the basic block. null if none.
*/
IntSet gen(SingleInstructionBasicBlock b) {
IntSet gen(ExplodedBasicBlock b) {
if (b.isEntryBlock()) {
return heapEntryStatements();
} else {
@ -588,7 +582,7 @@ public class HeapReachingDefs {
* @return int set representing the heap def statements that are killed by
* the basic block. null if none.
*/
BitVector kill(SingleInstructionBasicBlock b) {
BitVector kill(ExplodedBasicBlock b) {
SSAInstruction s = b.getInstruction();
if (s == null) {
return null;

View File

@ -28,8 +28,7 @@ import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Trace;
/**
*
* Eliminate dead assignnments (phis) from an SSA IR.
* Eliminate dead assignments (phis) from an SSA IR.
*
* @author sfink
*/
@ -84,8 +83,6 @@ public class DeadAssignmentElimination {
}
/**
* @author sfink
*
* A dataflow system which computes whether or not a value is dead
*/
private static class DeadValueSystem extends DefaultFixedPointSolver {

View File

@ -1,144 +0,0 @@
/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.ssa.analysis;
import java.io.FileWriter;
import java.util.Iterator;
import com.ibm.wala.ssa.SSACFG;
import com.ibm.wala.ssa.SSACFG.BasicBlock;
import com.ibm.wala.ssa.analysis.ExpandedControlFlowGraph.SingleInstructionBasicBlock;
/**
* @author Eran Yahav (yahave)
*
*/
public class ExpandedCFGDotWriter {
public static void write(String fileName, ExpandedControlFlowGraph cfg) throws IllegalArgumentException {
if (cfg == null) {
throw new IllegalArgumentException("cfg cannot be null");
}
StringBuffer result = new StringBuffer();
result.append(dotOutput(cfg));
try {
FileWriter fw = new FileWriter(fileName, false);
fw.write(result.toString());
fw.close();
} catch (Exception e) {
throw new RuntimeException("Error writing dot file");
}
}
public static void write(String fileName, SSACFG cfg) {
if (cfg == null) {
throw new IllegalArgumentException("cfg cannot be null");
}
StringBuffer result = new StringBuffer();
result.append(dotOutput(cfg));
try {
FileWriter fw = new FileWriter(fileName, false);
fw.write(result.toString());
fw.close();
} catch (Exception e) {
throw new RuntimeException("Error writing dot file");
}
}
private static StringBuffer dotOutput(ExpandedControlFlowGraph cfg) {
StringBuffer result = new StringBuffer("digraph \"ExpandedControlFlowGraph:\" {\n");
result.append("center=true;fontsize=12;node [fontsize=12];edge [fontsize=12]; \n");
// create nodes for basic-blocks
for (Iterator it = cfg.iterator(); it.hasNext();) {
SingleInstructionBasicBlock bb = (SingleInstructionBasicBlock) it.next();
result.append(dotOutput(bb));
if (bb.isEntryBlock()) {
result.append(" [color=green]\n");
} else if (bb.isExitBlock()) {
result.append(" [color=red]\n");
} else {
result.append("\n");
}
}
// create edges
for (Iterator it = cfg.iterator(); it.hasNext();) {
SingleInstructionBasicBlock bb = (SingleInstructionBasicBlock) it.next();
for (Iterator succIt = cfg.getSuccNodes(bb); succIt.hasNext();) {
SingleInstructionBasicBlock succ = (SingleInstructionBasicBlock) succIt.next();
result.append(dotOutput(bb));
result.append(" -> ");
result.append(dotOutput(succ));
result.append("\n");
}
}
// close digraph
result.append("}");
return result;
}
private static StringBuffer dotOutput(SSACFG cfg) {
StringBuffer result = new StringBuffer("digraph \"ControlFlowGraph:\" {\n");
result.append("center=true;fontsize=12;node [fontsize=12];edge [fontsize=12]; \n");
// create nodes for basic-blocks
for (Iterator it = cfg.iterator(); it.hasNext();) {
BasicBlock bb = (BasicBlock) it.next();
result.append(dotOutput(bb));
if (bb.isEntryBlock()) {
result.append(" [color=green]\n");
} else if (bb.isExitBlock()) {
result.append(" [color=red]\n");
} else {
result.append("\n");
}
}
// create edges
for (Iterator it = cfg.iterator(); it.hasNext();) {
BasicBlock bb = (BasicBlock) it.next();
for (Iterator succIt = cfg.getSuccNodes(bb); succIt.hasNext();) {
BasicBlock succ = (BasicBlock) succIt.next();
result.append(dotOutput(bb));
result.append(" -> ");
result.append(dotOutput(succ));
result.append("\n");
}
}
// close digraph
result.append("}");
return result;
}
private static StringBuffer dotOutput(BasicBlock bb) {
StringBuffer result = new StringBuffer();
result.append("\"");
result.append(bb.getNumber());
result.append("\"");
return result;
}
private static StringBuffer dotOutput(SingleInstructionBasicBlock bb) {
StringBuffer result = new StringBuffer();
result.append("\"");
result.append(bb.getNumber());
result.append("-");
result.append(bb.getInstruction());
result.append("\"");
return result;
}
}

View File

@ -0,0 +1,418 @@
/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.ssa.analysis;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.cfg.IBasicBlock;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.intset.BitVector;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.SimpleVector;
/**
* A view of a control flow graph where each basic block corresponds to exactly
* one SSA instruction index.
*
* Prototype: Not terribly efficient.
*/
public class ExplodedControlFlowGraph implements ControlFlowGraph {
private final IR ir;
private final SimpleVector<IBasicBlock> normalNodes = new SimpleVector<IBasicBlock>();
private final Collection<IBasicBlock> allNodes = HashSetFactory.make();
private final ExplodedBasicBlock entry;
private final ExplodedBasicBlock exit;
private ExplodedControlFlowGraph(IR ir) {
this.ir = ir;
this.entry = new ExplodedBasicBlock(-2, ir.getControlFlowGraph().entry());
this.exit = new ExplodedBasicBlock(-2, ir.getControlFlowGraph().exit());
createNodes();
}
private void createNodes() {
allNodes.add(entry);
allNodes.add(exit);
for (IBasicBlock b : ir.getControlFlowGraph()) {
for (int i = b.getFirstInstructionIndex(); i <= b.getLastInstructionIndex(); i++) {
ExplodedBasicBlock bb = new ExplodedBasicBlock(i, b);
normalNodes.set(i, bb);
allNodes.add(bb);
}
}
}
public static ExplodedControlFlowGraph make(IR ir) {
return new ExplodedControlFlowGraph(ir);
}
public IBasicBlock entry() {
return entry;
}
public IBasicBlock exit() {
return exit;
}
public IBasicBlock getBlockForInstruction(int index) {
return normalNodes.get(index);
}
public BitVector getCatchBlocks() {
Assertions.UNREACHABLE();
return null;
}
public Collection<IBasicBlock> getExceptionalPredecessors(IBasicBlock b) {
Assertions.UNREACHABLE();
return null;
}
public Collection<IBasicBlock> getExceptionalSuccessors(IBasicBlock b) {
assert b != null;
if (b.equals(exit)) {
return Collections.emptySet();
}
ExplodedBasicBlock eb = (ExplodedBasicBlock) b;
if (eb.isEntryBlock() || eb.instructionIndex == eb.original.getLastInstructionIndex()) {
List<IBasicBlock> result = new ArrayList<IBasicBlock>();
for (IBasicBlock s : ir.getControlFlowGraph().getExceptionalSuccessors(eb.original)) {
if (s.equals(ir.getControlFlowGraph().exit())) {
result.add(exit());
} else {
assert normalNodes.get(s.getFirstInstructionIndex()) != null;
result.add(normalNodes.get(s.getFirstInstructionIndex()));
}
}
return result;
} else {
return Collections.emptySet();
}
}
public IInstruction[] getInstructions() {
return ir.getInstructions();
}
public IMethod getMethod() {
Assertions.UNREACHABLE();
return null;
}
public Collection<IBasicBlock> getNormalPredecessors(IBasicBlock b) {
Assertions.UNREACHABLE();
return null;
}
public Collection<IBasicBlock> getNormalSuccessors(IBasicBlock b) {
assert b != null;
if (b.equals(exit)) {
return Collections.emptySet();
}
ExplodedBasicBlock eb = (ExplodedBasicBlock) b;
if (eb.isEntryBlock() || eb.instructionIndex == eb.original.getLastInstructionIndex()) {
List<IBasicBlock> result = new ArrayList<IBasicBlock>();
for (IBasicBlock s : ir.getControlFlowGraph().getNormalSuccessors(eb.original)) {
if (s.equals(ir.getControlFlowGraph().exit())) {
result.add(exit());
} else {
assert normalNodes.get(s.getFirstInstructionIndex()) != null;
result.add(normalNodes.get(s.getFirstInstructionIndex()));
}
}
return result;
} else {
assert normalNodes.get(eb.instructionIndex + 1) != null;
return Collections.singleton(normalNodes.get(eb.instructionIndex + 1));
}
}
public int getProgramCounter(int index) {
Assertions.UNREACHABLE();
return 0;
}
public void removeNodeAndEdges(IBasicBlock N) throws UnsupportedOperationException {
Assertions.UNREACHABLE();
}
public void addNode(IBasicBlock n) {
Assertions.UNREACHABLE();
}
public boolean containsNode(IBasicBlock N) {
Assertions.UNREACHABLE();
return false;
}
public int getNumberOfNodes() {
return allNodes.size();
}
public Iterator<IBasicBlock> iterator() {
return allNodes.iterator();
}
public void removeNode(IBasicBlock n) {
Assertions.UNREACHABLE();
}
public void addEdge(IBasicBlock src, IBasicBlock dst) {
Assertions.UNREACHABLE();
}
public int getPredNodeCount(IBasicBlock N) {
ExplodedBasicBlock b = (ExplodedBasicBlock) N;
if (b.isEntryBlock()) {
return 0;
}
if (b.equals(exit) || b.instructionIndex == b.original.getFirstInstructionIndex()) {
return ir.getControlFlowGraph().getPredNodeCount(b.original);
} else {
return 1;
}
}
public Iterator<? extends IBasicBlock> getPredNodes(IBasicBlock N) {
ExplodedBasicBlock b = (ExplodedBasicBlock) N;
if (b.isEntryBlock()) {
return EmptyIterator.instance();
}
if (b.equals(exit) || b.instructionIndex == b.original.getFirstInstructionIndex()) {
List<IBasicBlock> result = new ArrayList<IBasicBlock>();
for (Iterator<IBasicBlock> it = ir.getControlFlowGraph().getPredNodes(b.original); it.hasNext();) {
IBasicBlock s = it.next();
if (s.isEntryBlock()) {
result.add(entry);
} else {
assert normalNodes.get(s.getLastInstructionIndex()) != null;
result.add(normalNodes.get(s.getLastInstructionIndex()));
}
}
return result.iterator();
} else {
assert normalNodes.get(b.instructionIndex - 1) != null;
return NonNullSingletonIterator.make(normalNodes.get(b.instructionIndex - 1));
}
}
public int getSuccNodeCount(IBasicBlock N) {
Assertions.UNREACHABLE();
return 0;
}
public Iterator<? extends IBasicBlock> getSuccNodes(IBasicBlock N) {
assert N != null;
if (N.equals(exit)) {
return EmptyIterator.instance();
}
ExplodedBasicBlock b = (ExplodedBasicBlock) N;
if (b.isEntryBlock() || b.instructionIndex == b.original.getLastInstructionIndex()) {
List<IBasicBlock> result = new ArrayList<IBasicBlock>();
for (Iterator<IBasicBlock> it = ir.getControlFlowGraph().getSuccNodes(b.original); it.hasNext();) {
IBasicBlock s = it.next();
if (s.equals(ir.getControlFlowGraph().exit())) {
result.add(exit());
} else {
assert normalNodes.get(s.getFirstInstructionIndex()) != null;
result.add(normalNodes.get(s.getFirstInstructionIndex()));
}
}
return result.iterator();
} else {
assert normalNodes.get(b.instructionIndex + 1) != null;
return NonNullSingletonIterator.make(normalNodes.get(b.instructionIndex + 1));
}
}
public boolean hasEdge(IBasicBlock src, IBasicBlock dst) {
Assertions.UNREACHABLE();
return false;
}
public void removeAllIncidentEdges(IBasicBlock node) throws UnsupportedOperationException {
Assertions.UNREACHABLE();
}
public void removeEdge(IBasicBlock src, IBasicBlock dst) throws UnsupportedOperationException {
Assertions.UNREACHABLE();
}
public void removeIncomingEdges(IBasicBlock node) throws UnsupportedOperationException {
Assertions.UNREACHABLE();
}
public void removeOutgoingEdges(IBasicBlock node) throws UnsupportedOperationException {
Assertions.UNREACHABLE();
}
public int getMaxNumber() {
Assertions.UNREACHABLE();
return 0;
}
public IBasicBlock getNode(int number) {
if (number == 0) {
return entry();
} else if (number == getNumberOfNodes() -1) {
return exit();
} else {
return normalNodes.get(number);
}
}
public int getNumber(IBasicBlock N) {
Assertions.UNREACHABLE();
return 0;
}
public Iterator<IBasicBlock> iterateNodes(IntSet s) {
Assertions.UNREACHABLE();
return null;
}
public IntSet getPredNodeNumbers(IBasicBlock node) {
Assertions.UNREACHABLE();
return null;
}
public IntSet getSuccNodeNumbers(IBasicBlock node) {
Assertions.UNREACHABLE();
return null;
}
public class ExplodedBasicBlock implements IBasicBlock {
private final int instructionIndex;
private final IBasicBlock original;
public ExplodedBasicBlock(int instructionIndex, IBasicBlock original) {
this.instructionIndex = instructionIndex;
this.original = original;
assert original != null;
}
public int getFirstInstructionIndex() {
return instructionIndex;
}
public int getLastInstructionIndex() {
return instructionIndex;
}
public IMethod getMethod() {
Assertions.UNREACHABLE();
return null;
}
public int getNumber() {
if (isEntryBlock()) {
return 0;
} else if (isExitBlock()) {
return getNumberOfNodes() -1;
} else {
return instructionIndex;
}
}
public boolean isCatchBlock() {
Assertions.UNREACHABLE();
return false;
}
public boolean isEntryBlock() {
return original.isEntryBlock();
}
public boolean isExitBlock() {
return original.isExitBlock();
}
public int getGraphNodeId() {
Assertions.UNREACHABLE();
return 0;
}
public void setGraphNodeId(int number) {
Assertions.UNREACHABLE();
}
public Iterator<IInstruction> iterator() {
Assertions.UNREACHABLE();
return null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + instructionIndex;
result = prime * result + ((original == null) ? 0 : original.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ExplodedBasicBlock other = (ExplodedBasicBlock) obj;
if (instructionIndex != other.instructionIndex)
return false;
if (original == null) {
if (other.original != null)
return false;
} else if (!original.equals(other.original))
return false;
return true;
}
public SSAInstruction getInstruction() {
if (isEntryBlock() || isExitBlock()) {
return null;
} else {
return ir.getInstructions()[instructionIndex];
}
}
}
}