several variants of reaching defs analysis, including test class and a bit of test data. still needs better documentation
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@3815 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
05499a6d15
commit
fe13a2d35b
|
@ -0,0 +1,51 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2010 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 dataflow;
|
||||
|
||||
/**
|
||||
* test cases for dataflow analysis involving static fields.
|
||||
*/
|
||||
public class StaticDataflow {
|
||||
|
||||
static int f;
|
||||
|
||||
static int g;
|
||||
|
||||
public static void test1() {
|
||||
f = 3;
|
||||
f = 3;
|
||||
}
|
||||
|
||||
public static void test2() {
|
||||
f = 4;
|
||||
g = 3;
|
||||
if (f == 5) {
|
||||
g = 2;
|
||||
} else {
|
||||
g = 7;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
testInterproc();
|
||||
}
|
||||
|
||||
private static void testInterproc() {
|
||||
f = 3;
|
||||
m();
|
||||
g = 4;
|
||||
m();
|
||||
}
|
||||
|
||||
private static void m() {
|
||||
f = 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.examples.analysis.dataflow;
|
||||
|
||||
import com.ibm.wala.fixedpoint.impl.UnaryOperator;
|
||||
import com.ibm.wala.fixpoint.BitVectorVariable;
|
||||
|
||||
/**
|
||||
* Just kills everything
|
||||
*/
|
||||
public class BitVectorKillAll extends UnaryOperator<BitVectorVariable> {
|
||||
|
||||
private final static BitVectorKillAll SINGLETON = new BitVectorKillAll();
|
||||
|
||||
public static BitVectorKillAll instance() {
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
private BitVectorKillAll() {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.ibm.wala.fixedpoint.impl.UnaryOperator#evaluate(com.ibm.wala.fixpoint.IVariable, com.ibm.wala.fixpoint.IVariable)
|
||||
*/
|
||||
@Override
|
||||
public byte evaluate(BitVectorVariable lhs, BitVectorVariable rhs) {
|
||||
BitVectorVariable empty = new BitVectorVariable();
|
||||
if (!lhs.sameValue(empty)) {
|
||||
lhs.copyState(empty);
|
||||
return CHANGED;
|
||||
} else {
|
||||
return NOT_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.ibm.wala.fixedpoint.impl.AbstractOperator#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.ibm.wala.fixedpoint.impl.AbstractOperator#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 12423958;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.ibm.wala.fixedpoint.impl.AbstractOperator#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KillAll";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.examples.analysis.dataflow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.classLoader.IField;
|
||||
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorFramework;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorIdentity;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorKillGen;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorSolver;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorUnion;
|
||||
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
|
||||
import com.ibm.wala.fixedpoint.impl.UnaryOperator;
|
||||
import com.ibm.wala.fixpoint.BitVectorVariable;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.cfg.BasicBlockInContext;
|
||||
import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.ssa.SSAPutInstruction;
|
||||
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.ObjectArrayMapping;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
import com.ibm.wala.util.intset.BitVector;
|
||||
import com.ibm.wala.util.intset.OrdinalSetMapping;
|
||||
|
||||
/**
|
||||
* Computes interprocedural reaching definitions for static fields in a context-insensitive manner.
|
||||
*/
|
||||
public class ContextInsensitiveReachingDefs {
|
||||
|
||||
/**
|
||||
* the exploded control-flow graph on which to compute the analysis
|
||||
*/
|
||||
private final ExplodedInterproceduralCFG icfg;
|
||||
|
||||
/**
|
||||
* maps method and instruction index of putstatic to more compact numbering for bitvectors
|
||||
*/
|
||||
private final OrdinalSetMapping<Pair<CGNode, Integer>> putInstrNumbering;
|
||||
|
||||
private final IClassHierarchy cha;
|
||||
|
||||
/**
|
||||
* maps each static field to the numbers of the statements that define it
|
||||
*/
|
||||
private final Map<IField, BitVector> staticField2DefStatements = HashMapFactory.make();
|
||||
|
||||
public ContextInsensitiveReachingDefs(ExplodedInterproceduralCFG icfg, IClassHierarchy cha) {
|
||||
this.icfg = icfg;
|
||||
this.cha = cha;
|
||||
this.putInstrNumbering = numberPutStatics();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private OrdinalSetMapping<Pair<CGNode, Integer>> numberPutStatics() {
|
||||
ArrayList<Pair<CGNode, Integer>> putInstrs = new ArrayList<Pair<CGNode, Integer>>();
|
||||
for (CGNode node : icfg.getCallGraph()) {
|
||||
IR ir = node.getIR();
|
||||
if (ir == null) {
|
||||
continue;
|
||||
}
|
||||
SSAInstruction[] instructions = ir.getInstructions();
|
||||
for (int i = 0; i < instructions.length; i++) {
|
||||
SSAInstruction instruction = instructions[i];
|
||||
if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) {
|
||||
SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
|
||||
int instrNum = putInstrs.size();
|
||||
putInstrs.add(Pair.make(node, i));
|
||||
IField field = cha.resolveField(putInstr.getDeclaredField());
|
||||
assert field != null;
|
||||
BitVector bv = staticField2DefStatements.get(field);
|
||||
if (bv == null) {
|
||||
bv = new BitVector();
|
||||
staticField2DefStatements.put(field, bv);
|
||||
}
|
||||
bv.set(instrNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ObjectArrayMapping<Pair<CGNode, Integer>>(putInstrs.toArray(new Pair[putInstrs.size()]));
|
||||
}
|
||||
|
||||
private class TransferFunctions implements ITransferFunctionProvider<BasicBlockInContext<IExplodedBasicBlock>, BitVectorVariable> {
|
||||
|
||||
public AbstractMeetOperator<BitVectorVariable> getMeetOperator() {
|
||||
// meet is union
|
||||
return BitVectorUnion.instance();
|
||||
}
|
||||
|
||||
public UnaryOperator<BitVectorVariable> getNodeTransferFunction(BasicBlockInContext<IExplodedBasicBlock> node) {
|
||||
IExplodedBasicBlock ebb = node.getDelegate();
|
||||
SSAInstruction instruction = ebb.getInstruction();
|
||||
int instructionIndex = ebb.getFirstInstructionIndex();
|
||||
CGNode cgNode = node.getNode();
|
||||
if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) {
|
||||
// kill all defs of the same static field
|
||||
final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
|
||||
final IField field = cha.resolveField(putInstr.getDeclaredField());
|
||||
assert field != null;
|
||||
BitVector kill = staticField2DefStatements.get(field);
|
||||
BitVector gen = new BitVector();
|
||||
gen.set(putInstrNumbering.getMappedIndex(Pair.make(cgNode, instructionIndex)));
|
||||
return new BitVectorKillGen(kill, gen);
|
||||
} else {
|
||||
// nothing defined
|
||||
return BitVectorIdentity.instance();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEdgeTransferFunctions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasNodeTransferFunctions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(BasicBlockInContext<IExplodedBasicBlock> src,
|
||||
BasicBlockInContext<IExplodedBasicBlock> dst) {
|
||||
if (isCallToReturnEdge(src,dst)) {
|
||||
return BitVectorKillAll.instance();
|
||||
} else {
|
||||
return BitVectorIdentity.instance();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCallToReturnEdge(BasicBlockInContext<IExplodedBasicBlock> src, BasicBlockInContext<IExplodedBasicBlock> dst) {
|
||||
SSAInstruction srcInst = src.getDelegate().getInstruction();
|
||||
return srcInst instanceof SSAAbstractInvokeInstruction && src.getNode().equals(dst.getNode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public BitVectorSolver<BasicBlockInContext<IExplodedBasicBlock>> analyze() {
|
||||
BitVectorFramework<BasicBlockInContext<IExplodedBasicBlock>, Pair<CGNode, Integer>> framework = new BitVectorFramework<BasicBlockInContext<IExplodedBasicBlock>, Pair<CGNode, Integer>>(
|
||||
icfg, new TransferFunctions(), putInstrNumbering);
|
||||
BitVectorSolver<BasicBlockInContext<IExplodedBasicBlock>> solver = new BitVectorSolver<BasicBlockInContext<IExplodedBasicBlock>>(
|
||||
framework);
|
||||
try {
|
||||
solver.solve(null);
|
||||
} catch (CancelException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (BasicBlockInContext<IExplodedBasicBlock> ebb : icfg) {
|
||||
System.out.println(ebb);
|
||||
System.out.println(ebb.getDelegate().getInstruction());
|
||||
System.out.println(solver.getIn(ebb));
|
||||
System.out.println(solver.getOut(ebb));
|
||||
}
|
||||
return solver;
|
||||
}
|
||||
|
||||
public Pair<CGNode, Integer> getNodeAndInstrForNumber(int num) {
|
||||
return putInstrNumbering.getMappedObject(num);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.examples.analysis.dataflow;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.ibm.wala.classLoader.IField;
|
||||
import com.ibm.wala.dataflow.IFDS.ICFGSupergraph;
|
||||
import com.ibm.wala.dataflow.IFDS.IFlowFunction;
|
||||
import com.ibm.wala.dataflow.IFDS.IMergeFunction;
|
||||
import com.ibm.wala.dataflow.IFDS.IPartiallyBalancedFlowFunctions;
|
||||
import com.ibm.wala.dataflow.IFDS.ISupergraph;
|
||||
import com.ibm.wala.dataflow.IFDS.IUnaryFlowFunction;
|
||||
import com.ibm.wala.dataflow.IFDS.IdentityFlowFunction;
|
||||
import com.ibm.wala.dataflow.IFDS.KillEverything;
|
||||
import com.ibm.wala.dataflow.IFDS.PartiallyBalancedTabulationProblem;
|
||||
import com.ibm.wala.dataflow.IFDS.PartiallyBalancedTabulationSolver;
|
||||
import com.ibm.wala.dataflow.IFDS.PathEdge;
|
||||
import com.ibm.wala.dataflow.IFDS.TabulationDomain;
|
||||
import com.ibm.wala.dataflow.IFDS.TabulationResult;
|
||||
import com.ibm.wala.dataflow.IFDS.TabulationSolver;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ipa.cfg.BasicBlockInContext;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.ssa.SSAPutInstruction;
|
||||
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.MutableMapping;
|
||||
import com.ibm.wala.util.intset.MutableSparseIntSet;
|
||||
|
||||
/**
|
||||
* Computes interprocedural reaching definitions for static fields in a context-sensitive manner via {@link TabulationSolver
|
||||
* tabulation}.
|
||||
*/
|
||||
public class ContextSensitiveReachingDefs {
|
||||
|
||||
private final IClassHierarchy cha;
|
||||
|
||||
private final ISupergraph<BasicBlockInContext<IExplodedBasicBlock>, CGNode> supergraph;
|
||||
|
||||
private ReachingDefsDomain domain = new ReachingDefsDomain();
|
||||
|
||||
public ContextSensitiveReachingDefs(CallGraph cg, AnalysisCache cache) {
|
||||
this.cha = cg.getClassHierarchy();
|
||||
this.supergraph = ICFGSupergraph.make(cg, cache);
|
||||
}
|
||||
|
||||
private class ReachingDefsDomain extends MutableMapping<Pair<CGNode, Integer>> implements
|
||||
TabulationDomain<Pair<CGNode, Integer>, BasicBlockInContext<IExplodedBasicBlock>> {
|
||||
|
||||
public boolean hasPriorityOver(PathEdge<BasicBlockInContext<IExplodedBasicBlock>> p1,
|
||||
PathEdge<BasicBlockInContext<IExplodedBasicBlock>> p2) {
|
||||
// don't worry about worklist priorities
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ReachingDefsFlowFunctions implements IPartiallyBalancedFlowFunctions<BasicBlockInContext<IExplodedBasicBlock>> {
|
||||
|
||||
private final ReachingDefsDomain domain;
|
||||
|
||||
protected ReachingDefsFlowFunctions(ReachingDefsDomain domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public IFlowFunction getUnbalancedReturnFlowFunction(BasicBlockInContext<IExplodedBasicBlock> src,
|
||||
BasicBlockInContext<IExplodedBasicBlock> dest) {
|
||||
return IdentityFlowFunction.identity();
|
||||
}
|
||||
|
||||
public IUnaryFlowFunction getCallFlowFunction(BasicBlockInContext<IExplodedBasicBlock> src,
|
||||
BasicBlockInContext<IExplodedBasicBlock> dest, BasicBlockInContext<IExplodedBasicBlock> ret) {
|
||||
// just send the fact into the callee
|
||||
return IdentityFlowFunction.identity();
|
||||
}
|
||||
|
||||
public IUnaryFlowFunction getCallNoneToReturnFlowFunction(BasicBlockInContext<IExplodedBasicBlock> src,
|
||||
BasicBlockInContext<IExplodedBasicBlock> dest) {
|
||||
// if we're missing callees, just give up and kill everything
|
||||
return KillEverything.singleton();
|
||||
}
|
||||
|
||||
public IUnaryFlowFunction getCallToReturnFlowFunction(BasicBlockInContext<IExplodedBasicBlock> src,
|
||||
BasicBlockInContext<IExplodedBasicBlock> dest) {
|
||||
// kill everything; surviving facts should flow out of the callee
|
||||
return KillEverything.singleton();
|
||||
}
|
||||
|
||||
public IUnaryFlowFunction getNormalFlowFunction(final BasicBlockInContext<IExplodedBasicBlock> src,
|
||||
BasicBlockInContext<IExplodedBasicBlock> dest) {
|
||||
final IExplodedBasicBlock ebb = src.getDelegate();
|
||||
SSAInstruction instruction = ebb.getInstruction();
|
||||
if (instruction instanceof SSAPutInstruction) {
|
||||
final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
|
||||
if (putInstr.isStatic()) {
|
||||
return new IUnaryFlowFunction() {
|
||||
|
||||
public IntSet getTargets(int d1) {
|
||||
int factNum = domain.getMappedIndex(Pair.make(src.getNode(), ebb.getFirstInstructionIndex()));
|
||||
IField staticField = cha.resolveField(putInstr.getDeclaredField());
|
||||
assert staticField != null;
|
||||
assert factNum != -1;
|
||||
MutableSparseIntSet result = MutableSparseIntSet.makeEmpty();
|
||||
result.add(factNum);
|
||||
if (d1 != factNum) {
|
||||
Pair<CGNode, Integer> otherPutInstrAndNode = domain.getMappedObject(d1);
|
||||
// if it writes the same field, kill it
|
||||
SSAPutInstruction otherPutInstr = (SSAPutInstruction) otherPutInstrAndNode.fst.getIR().getInstructions()[otherPutInstrAndNode.snd];
|
||||
IField otherStaticField = cha.resolveField(otherPutInstr.getDeclaredField());
|
||||
if (!staticField.equals(otherStaticField)) {
|
||||
result.add(d1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Reaching Defs Normal Flow";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return IdentityFlowFunction.identity();
|
||||
}
|
||||
|
||||
public IFlowFunction getReturnFlowFunction(BasicBlockInContext<IExplodedBasicBlock> call,
|
||||
BasicBlockInContext<IExplodedBasicBlock> src, BasicBlockInContext<IExplodedBasicBlock> dest) {
|
||||
return IdentityFlowFunction.identity();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ReachingDefsProblem implements
|
||||
PartiallyBalancedTabulationProblem<BasicBlockInContext<IExplodedBasicBlock>, CGNode, Pair<CGNode, Integer>> {
|
||||
|
||||
private ReachingDefsFlowFunctions flowFunctions = new ReachingDefsFlowFunctions(domain);
|
||||
|
||||
private Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> initialSeeds = collectInitialSeeds();
|
||||
|
||||
/**
|
||||
* we use the entry block of the CGNode as the fake entry when propagating from callee to caller with unbalanced parens
|
||||
*/
|
||||
public BasicBlockInContext<IExplodedBasicBlock> getFakeEntry(BasicBlockInContext<IExplodedBasicBlock> node) {
|
||||
final CGNode cgNode = node.getNode();
|
||||
return getFakeEntry(cgNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* we use the entry block of the CGNode as the fake entry when propagating from callee to caller with unbalanced parens
|
||||
*/
|
||||
private BasicBlockInContext<IExplodedBasicBlock> getFakeEntry(final CGNode cgNode) {
|
||||
BasicBlockInContext<IExplodedBasicBlock>[] entriesForProcedure = supergraph.getEntriesForProcedure(cgNode);
|
||||
assert entriesForProcedure.length == 1;
|
||||
return entriesForProcedure[0];
|
||||
}
|
||||
|
||||
private Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> collectInitialSeeds() {
|
||||
Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> result = HashSetFactory.make();
|
||||
for (BasicBlockInContext<IExplodedBasicBlock> bb : supergraph) {
|
||||
IExplodedBasicBlock ebb = bb.getDelegate();
|
||||
SSAInstruction instruction = ebb.getInstruction();
|
||||
if (instruction instanceof SSAPutInstruction) {
|
||||
SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
|
||||
if (putInstr.isStatic()) {
|
||||
final CGNode cgNode = bb.getNode();
|
||||
Pair<CGNode, Integer> fact = Pair.make(cgNode, ebb.getFirstInstructionIndex());
|
||||
int factNum = domain.add(fact);
|
||||
BasicBlockInContext<IExplodedBasicBlock> fakeEntry = getFakeEntry(cgNode);
|
||||
result.add(PathEdge.createPathEdge(fakeEntry, factNum, bb, factNum));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public IPartiallyBalancedFlowFunctions<BasicBlockInContext<IExplodedBasicBlock>> getFunctionMap() {
|
||||
return flowFunctions;
|
||||
}
|
||||
|
||||
public TabulationDomain<Pair<CGNode, Integer>, BasicBlockInContext<IExplodedBasicBlock>> getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public IMergeFunction getMergeFunction() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ISupergraph<BasicBlockInContext<IExplodedBasicBlock>, CGNode> getSupergraph() {
|
||||
return supergraph;
|
||||
}
|
||||
|
||||
public Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> initialSeeds() {
|
||||
return initialSeeds;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public TabulationResult<BasicBlockInContext<IExplodedBasicBlock>, CGNode, Pair<CGNode, Integer>> analyze() throws CancelException {
|
||||
PartiallyBalancedTabulationSolver<BasicBlockInContext<IExplodedBasicBlock>, CGNode, Pair<CGNode, Integer>> solver = PartiallyBalancedTabulationSolver
|
||||
.createPartiallyBalancedTabulationSolver(new ReachingDefsProblem(), null);
|
||||
TabulationResult<BasicBlockInContext<IExplodedBasicBlock>, CGNode, Pair<CGNode, Integer>> result = solver.solve();
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public ISupergraph<BasicBlockInContext<IExplodedBasicBlock>, CGNode> getSupergraph() {
|
||||
return supergraph;
|
||||
}
|
||||
|
||||
public TabulationDomain<Pair<CGNode,Integer>, BasicBlockInContext<IExplodedBasicBlock>> getDomain() {
|
||||
return domain;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.examples.analysis.dataflow;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
|
||||
import com.ibm.wala.core.tests.util.TestConstants;
|
||||
import com.ibm.wala.core.tests.util.WalaTestCase;
|
||||
import com.ibm.wala.dataflow.IFDS.ISupergraph;
|
||||
import com.ibm.wala.dataflow.IFDS.TabulationResult;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorSolver;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
|
||||
import com.ibm.wala.ipa.callgraph.Entrypoint;
|
||||
import com.ibm.wala.ipa.callgraph.impl.Util;
|
||||
import com.ibm.wala.ipa.cfg.BasicBlockInContext;
|
||||
import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph;
|
||||
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
import com.ibm.wala.util.config.AnalysisScopeReader;
|
||||
import com.ibm.wala.util.intset.IntIterator;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.io.FileProvider;
|
||||
|
||||
/**
|
||||
* Tests of various flow analysis engines.
|
||||
*/
|
||||
public class DataflowTest extends WalaTestCase {
|
||||
|
||||
private static AnalysisScope scope;
|
||||
|
||||
private static IClassHierarchy cha;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
|
||||
scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
|
||||
FileProvider.getFile("J2SEClassHierarchyExclusions.txt"), DataflowTest.class.getClassLoader());
|
||||
|
||||
try {
|
||||
cha = ClassHierarchy.make(scope);
|
||||
} catch (ClassHierarchyException e) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see junit.framework.TestCase#tearDown()
|
||||
*/
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
scope = null;
|
||||
cha = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntraproc1() {
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
final MethodReference ref = MethodReference.findOrCreate(ClassLoaderReference.Application, "Ldataflow/StaticDataflow", "test1",
|
||||
"()V");
|
||||
IMethod method = cha.resolveMethod(ref);
|
||||
IR ir = cache.getIR(method);
|
||||
ExplodedControlFlowGraph ecfg = ExplodedControlFlowGraph.make(ir);
|
||||
IntraprocReachingDefs reachingDefs = new IntraprocReachingDefs(ecfg, cha);
|
||||
BitVectorSolver<IExplodedBasicBlock> solver = reachingDefs.analyze();
|
||||
for (IExplodedBasicBlock ebb : ecfg) {
|
||||
if (ebb.getNumber() == 4) {
|
||||
IntSet out = solver.getOut(ebb).getValue();
|
||||
Assert.assertEquals(1, out.size());
|
||||
Assert.assertTrue(out.contains(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntraproc2() {
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
final MethodReference ref = MethodReference.findOrCreate(ClassLoaderReference.Application, "Ldataflow/StaticDataflow", "test2",
|
||||
"()V");
|
||||
IMethod method = cha.resolveMethod(ref);
|
||||
IR ir = cache.getIR(method);
|
||||
ExplodedControlFlowGraph ecfg = ExplodedControlFlowGraph.make(ir);
|
||||
IntraprocReachingDefs reachingDefs = new IntraprocReachingDefs(ecfg, cha);
|
||||
BitVectorSolver<IExplodedBasicBlock> solver = reachingDefs.analyze();
|
||||
for (IExplodedBasicBlock ebb : ecfg) {
|
||||
if (ebb.getNumber() == 10) {
|
||||
IntSet out = solver.getOut(ebb).getValue();
|
||||
Assert.assertEquals(2, out.size());
|
||||
Assert.assertTrue(out.contains(0));
|
||||
Assert.assertTrue(out.contains(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextInsensitive() throws IllegalArgumentException, CallGraphBuilderCancelException {
|
||||
Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha,
|
||||
"Ldataflow/StaticDataflow");
|
||||
AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
|
||||
|
||||
CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope);
|
||||
CallGraph cg = builder.makeCallGraph(options, null);
|
||||
ExplodedInterproceduralCFG icfg = ExplodedInterproceduralCFG.make(cg);
|
||||
ContextInsensitiveReachingDefs reachingDefs = new ContextInsensitiveReachingDefs(icfg, cha);
|
||||
BitVectorSolver<BasicBlockInContext<IExplodedBasicBlock>> solver = reachingDefs.analyze();
|
||||
for (BasicBlockInContext<IExplodedBasicBlock> bb : icfg) {
|
||||
if (bb.getNode().toString().contains("testInterproc")) {
|
||||
IExplodedBasicBlock delegate = bb.getDelegate();
|
||||
if (delegate.getNumber() == 4) {
|
||||
IntSet solution = solver.getOut(bb).getValue();
|
||||
IntIterator intIterator = solution.intIterator();
|
||||
while (intIterator.hasNext()) {
|
||||
int next = intIterator.next();
|
||||
System.out.println(reachingDefs.getNodeAndInstrForNumber(next));
|
||||
}
|
||||
Assert.assertEquals(4, solution.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextSensitive() throws IllegalArgumentException, CancelException {
|
||||
Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha,
|
||||
"Ldataflow/StaticDataflow");
|
||||
AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
|
||||
|
||||
CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope);
|
||||
CallGraph cg = builder.makeCallGraph(options, null);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
ContextSensitiveReachingDefs reachingDefs = new ContextSensitiveReachingDefs(cg, cache);
|
||||
TabulationResult<BasicBlockInContext<IExplodedBasicBlock>, CGNode, Pair<CGNode, Integer>> result = reachingDefs.analyze();
|
||||
ISupergraph<BasicBlockInContext<IExplodedBasicBlock>, CGNode> supergraph = reachingDefs.getSupergraph();
|
||||
for (BasicBlockInContext<IExplodedBasicBlock> bb : supergraph) {
|
||||
if (bb.getNode().toString().contains("testInterproc")) {
|
||||
IExplodedBasicBlock delegate = bb.getDelegate();
|
||||
if (delegate.getNumber() == 4) {
|
||||
IntSet solution = result.getResult(bb);
|
||||
IntIterator intIterator = solution.intIterator();
|
||||
while (intIterator.hasNext()) {
|
||||
int next = intIterator.next();
|
||||
System.out.println(reachingDefs.getDomain().getMappedObject(next));
|
||||
}
|
||||
Assert.assertEquals(3, solution.size());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ExplodedInterproceduralCFG icfg = ExplodedInterproceduralCFG.make(cg);
|
||||
// ContextInsensitiveReachingDefs reachingDefs = new ContextInsensitiveReachingDefs(icfg , cha);
|
||||
// BitVectorSolver<BasicBlockInContext<IExplodedBasicBlock>> solver = reachingDefs.analyze();
|
||||
// for (BasicBlockInContext<IExplodedBasicBlock> bb : icfg) {
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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.examples.analysis.dataflow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.classLoader.IField;
|
||||
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorFramework;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorIdentity;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorKillGen;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorSolver;
|
||||
import com.ibm.wala.dataflow.graph.BitVectorUnion;
|
||||
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
|
||||
import com.ibm.wala.fixedpoint.impl.UnaryOperator;
|
||||
import com.ibm.wala.fixpoint.BitVectorVariable;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.ssa.SSAPutInstruction;
|
||||
import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph;
|
||||
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.ObjectArrayMapping;
|
||||
import com.ibm.wala.util.intset.BitVector;
|
||||
import com.ibm.wala.util.intset.OrdinalSetMapping;
|
||||
|
||||
/**
|
||||
* @author manu
|
||||
*
|
||||
*/
|
||||
public class IntraprocReachingDefs {
|
||||
|
||||
/**
|
||||
* the exploded control-flow graph on which to compute the analysis
|
||||
*/
|
||||
private final ExplodedControlFlowGraph ecfg;
|
||||
|
||||
/**
|
||||
* maps instruction index of putstatic to more compact numbering for bitvectors
|
||||
*/
|
||||
private final OrdinalSetMapping<Integer> putInstrNumbering;
|
||||
|
||||
private final IClassHierarchy cha;
|
||||
|
||||
/**
|
||||
* maps each static field to the numbers of the statements that define it
|
||||
*/
|
||||
private final Map<IField, BitVector> staticField2DefStatements = HashMapFactory.make();
|
||||
|
||||
public IntraprocReachingDefs(ExplodedControlFlowGraph ecfg, IClassHierarchy cha) {
|
||||
this.ecfg = ecfg;
|
||||
this.cha = cha;
|
||||
this.putInstrNumbering = numberPutStatics();
|
||||
}
|
||||
|
||||
private OrdinalSetMapping<Integer> numberPutStatics() {
|
||||
ArrayList<Integer> putInstrs = new ArrayList<Integer>();
|
||||
IR ir = ecfg.getIR();
|
||||
SSAInstruction[] instructions = ir.getInstructions();
|
||||
for (int i = 0; i < instructions.length; i++) {
|
||||
SSAInstruction instruction = instructions[i];
|
||||
if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) {
|
||||
SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
|
||||
int instrNum = putInstrs.size();
|
||||
putInstrs.add(i);
|
||||
IField field = cha.resolveField(putInstr.getDeclaredField());
|
||||
assert field != null;
|
||||
BitVector bv = staticField2DefStatements.get(field);
|
||||
if (bv == null) {
|
||||
bv = new BitVector();
|
||||
staticField2DefStatements.put(field, bv);
|
||||
}
|
||||
bv.set(instrNum);
|
||||
}
|
||||
}
|
||||
return new ObjectArrayMapping<Integer>(putInstrs.toArray(new Integer[putInstrs.size()]));
|
||||
}
|
||||
|
||||
private class TransferFunctions implements ITransferFunctionProvider<IExplodedBasicBlock, BitVectorVariable> {
|
||||
|
||||
public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(IExplodedBasicBlock src, IExplodedBasicBlock dst) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public AbstractMeetOperator<BitVectorVariable> getMeetOperator() {
|
||||
// meet is union
|
||||
return BitVectorUnion.instance();
|
||||
}
|
||||
|
||||
public UnaryOperator<BitVectorVariable> getNodeTransferFunction(IExplodedBasicBlock node) {
|
||||
SSAInstruction instruction = node.getInstruction();
|
||||
int instructionIndex = node.getFirstInstructionIndex();
|
||||
if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) {
|
||||
// kill all defs of the same static field
|
||||
final SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
|
||||
final IField field = cha.resolveField(putInstr.getDeclaredField());
|
||||
assert field != null;
|
||||
BitVector kill = staticField2DefStatements.get(field);
|
||||
BitVector gen = new BitVector();
|
||||
gen.set(putInstrNumbering.getMappedIndex(instructionIndex));
|
||||
return new BitVectorKillGen(kill, gen);
|
||||
} else {
|
||||
// nothing defined
|
||||
return BitVectorIdentity.instance();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEdgeTransferFunctions() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasNodeTransferFunctions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public BitVectorSolver<IExplodedBasicBlock> analyze() {
|
||||
BitVectorFramework<IExplodedBasicBlock, Integer> framework = new BitVectorFramework<IExplodedBasicBlock, Integer>(
|
||||
ecfg, new TransferFunctions(), putInstrNumbering);
|
||||
BitVectorSolver<IExplodedBasicBlock> solver = new BitVectorSolver<IExplodedBasicBlock>(framework);
|
||||
try {
|
||||
solver.solve(null);
|
||||
} catch (CancelException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (IExplodedBasicBlock ebb : ecfg) {
|
||||
System.out.println(ebb);
|
||||
System.out.println(ebb.getInstruction());
|
||||
System.out.println(solver.getIn(ebb));
|
||||
System.out.println(solver.getOut(ebb));
|
||||
}
|
||||
return solver;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue