WALA/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/SDG.java

822 lines
28 KiB
Java

/*******************************************************************************
* Copyright (c) 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.ipa.slicer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.modref.ModRef;
import com.ibm.wala.ipa.slicer.Slicer.ControlDependenceOptions;
import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions;
import com.ibm.wala.ipa.slicer.Statement.Kind;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.Iterator2Collection;
import com.ibm.wala.util.collections.Iterator2Iterable;
import com.ibm.wala.util.collections.IteratorUtil;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.graph.AbstractNumberedGraph;
import com.ibm.wala.util.graph.NumberedEdgeManager;
import com.ibm.wala.util.graph.NumberedNodeManager;
import com.ibm.wala.util.graph.impl.SlowNumberedNodeManager;
import com.ibm.wala.util.intset.IntIterator;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.MutableSparseIntSet;
import com.ibm.wala.util.intset.OrdinalSet;
/**
* System dependence graph.
*
* An SDG comprises a set of PDGs, one for each method. We compute these lazily.
*
* Prototype implementation. Not efficient.
*/
public class SDG<T extends InstanceKey> extends AbstractNumberedGraph<Statement> implements ISDG {
/**
* Turn this flag on if you don't want eagerConstruction() to be called.
*/
private static final boolean DEBUG_LAZY = false;
/**
* node manager for graph API
*/
private final Nodes nodeMgr = new Nodes();
/**
* edge manager for graph API
*/
private final Edges edgeMgr = new Edges();
/**
* governing call graph
*/
private final CallGraph cg;
/**
* governing pointer analysis
*/
private final PointerAnalysis<T> pa;
/**
* keeps track of PDG for each call graph node
*/
private final Map<CGNode, PDG<T>> pdgMap = HashMapFactory.make();
/**
* governs data dependence edges in the graph
*/
private final DataDependenceOptions dOptions;
/**
* governs control dependence edges in the graph
*/
private final ControlDependenceOptions cOptions;
/**
* the set of heap locations which may be written (transitively) by each node. These are logically return values in the SDG.
*/
private final Map<CGNode, OrdinalSet<PointerKey>> mod;
/**
* the set of heap locations which may be read (transitively) by each node. These are logically parameters in the SDG.
*/
private final Map<CGNode, OrdinalSet<PointerKey>> ref;
/**
* CGNodes for which we have added all statements
*/
private final Collection<CGNode> statementsAdded = HashSetFactory.make();
/**
* If non-null, represents the heap locations to exclude from data dependence
*/
private final HeapExclusions heapExclude;
private final ModRef<T> modRef;
/**
* Have we eagerly populated all nodes of this SDG?
*/
private boolean eagerComputed = false;
public SDG(final CallGraph cg, PointerAnalysis<T> pa, DataDependenceOptions dOptions, ControlDependenceOptions cOptions) {
this(cg, pa, new ModRef<T>(), dOptions, cOptions, null);
}
public SDG(final CallGraph cg, PointerAnalysis<T> pa, ModRef<T> modRef, DataDependenceOptions dOptions,
ControlDependenceOptions cOptions) {
this(cg, pa, modRef, dOptions, cOptions, null);
}
public SDG(CallGraph cg, PointerAnalysis<T> pa, ModRef<T> modRef, DataDependenceOptions dOptions, ControlDependenceOptions cOptions,
HeapExclusions heapExclude) throws IllegalArgumentException {
super();
if (dOptions == null) {
throw new IllegalArgumentException("dOptions must not be null");
}
this.modRef = modRef;
this.cg = cg;
this.pa = pa;
this.mod = dOptions.isIgnoreHeap() ? null : modRef.computeMod(cg, pa, heapExclude);
this.ref = dOptions.isIgnoreHeap() ? null : modRef.computeRef(cg, pa, heapExclude);
this.dOptions = dOptions;
this.cOptions = cOptions;
this.heapExclude = heapExclude;
}
/**
* Use this with care. This forces eager construction of the SDG, and SDGs can be big.
*
* @see com.ibm.wala.util.graph.AbstractGraph#toString()
*/
@Override
public String toString() {
eagerConstruction();
return super.toString();
}
/**
* force eager construction of the entire SDG
*/
private void eagerConstruction() {
if (DEBUG_LAZY) {
Assertions.UNREACHABLE();
}
// Assertions.UNREACHABLE();
if (!eagerComputed) {
eagerComputed = true;
computeAllPDGs();
for (PDG pdg : pdgMap.values()) {
addPDGStatementNodes(pdg.getCallGraphNode());
}
}
}
private void addPDGStatementNodes(CGNode node) {
if (!statementsAdded.contains(node)) {
statementsAdded.add(node);
PDG<?> pdg = getPDG(node);
for (Statement statement : pdg) {
addNode(statement);
}
}
}
/**
* force computation of all PDGs in the SDG
*/
private void computeAllPDGs() {
for (CGNode n : cg) {
getPDG(n);
}
}
/**
* iterate over the nodes <b>without</b> constructing any new ones. Use with extreme care. May break graph traversals that
* lazily add more nodes.
*/
@Override
public Iterator<? extends Statement> iterateLazyNodes() {
return nodeMgr.iterateLazyNodes();
}
private class Nodes extends SlowNumberedNodeManager<Statement> {
private static final long serialVersionUID = -1450214776332091211L;
@Override
public boolean containsNode(Statement N) {
if (super.containsNode(N)) {
// first try it without eager construction.
return true;
}
// this may be bad. Are you sure you want to call this?
eagerConstruction();
return super.containsNode(N);
}
@Override
public int getMaxNumber() {
// this may be bad. Are you sure you want to call this?
eagerConstruction();
return super.getMaxNumber();
}
@Override
public Statement getNode(int number) {
Statement s = getNodeLazy(number);
if (s != null) {
// found it. don't do eager construction.
return s;
} else {
// this may be bad. Are you sure you want to do this?
eagerConstruction();
return super.getNode(number);
}
}
@Override
public int getNumber(Statement s) {
CGNode n = s.getNode();
addPDGStatementNodes(n);
return super.getNumber(s);
}
@Override
public Iterator<Statement> iterateNodes(IntSet s) {
Assertions.UNREACHABLE();
return super.iterateNodes(s);
}
@Override
public Iterator<Statement> iterator() {
eagerConstruction();
return super.iterator();
}
/**
* iterate over the nodes <b>without</b> constructing any new ones. Use with extreme care. May break graph traversals that
* lazily add more nodes.
*/
Iterator<? extends Statement> iterateLazyNodes() {
return super.iterator();
}
/**
* get the node with the given number if it already exists. Use with extreme care.
*/
public Statement getNodeLazy(int number) {
return super.getNode(number);
}
@Override
public int getNumberOfNodes() {
eagerConstruction();
return super.getNumberOfNodes();
}
}
private class Edges implements NumberedEdgeManager<Statement> {
@Override
public void addEdge(Statement src, Statement dst) {
Assertions.UNREACHABLE();
}
@Override
public int getPredNodeCount(Statement N) {
return IteratorUtil.count(getPredNodes(N));
}
@Override
public Iterator<Statement> getPredNodes(Statement N) {
if (dOptions.isIgnoreExceptions()) {
assert !N.getKind().equals(Kind.EXC_RET_CALLEE);
assert !N.getKind().equals(Kind.EXC_RET_CALLER);
}
addPDGStatementNodes(N.getNode());
switch (N.getKind()) {
case NORMAL:
case PHI:
case PI:
case EXC_RET_CALLEE:
case NORMAL_RET_CALLEE:
case PARAM_CALLER:
case HEAP_PARAM_CALLER:
case HEAP_RET_CALLEE:
case CATCH:
case METHOD_EXIT:
return getPDG(N.getNode()).getPredNodes(N);
case EXC_RET_CALLER: {
ExceptionalReturnCaller nrc = (ExceptionalReturnCaller) N;
SSAAbstractInvokeInstruction call = nrc.getInstruction();
Collection<Statement> result = Iterator2Collection.toSet(getPDG(N.getNode()).getPredNodes(N));
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode t : cg.getPossibleTargets(N.getNode(), call.getCallSite())) {
Statement s = new ExceptionalReturnCallee(t);
addNode(s);
result.add(s);
}
}
return result.iterator();
}
case NORMAL_RET_CALLER: {
NormalReturnCaller nrc = (NormalReturnCaller) N;
SSAAbstractInvokeInstruction call = nrc.getInstruction();
Collection<Statement> result = Iterator2Collection.toSet(getPDG(N.getNode()).getPredNodes(N));
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode t : cg.getPossibleTargets(N.getNode(), call.getCallSite())) {
Statement s = new NormalReturnCallee(t);
addNode(s);
result.add(s);
}
}
return result.iterator();
}
case HEAP_RET_CALLER: {
HeapStatement.HeapReturnCaller r = (HeapStatement.HeapReturnCaller) N;
SSAAbstractInvokeInstruction call = r.getCall();
Collection<Statement> result = Iterator2Collection.toSet(getPDG(N.getNode()).getPredNodes(N));
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode t : cg.getPossibleTargets(N.getNode(), call.getCallSite())) {
if (mod.get(t).contains(r.getLocation())) {
Statement s = new HeapStatement.HeapReturnCallee(t, r.getLocation());
addNode(s);
result.add(s);
}
}
}
return result.iterator();
}
case PARAM_CALLEE: {
ParamCallee pac = (ParamCallee) N;
int parameterIndex = pac.getValueNumber() - 1;
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
if (dOptions.isTerminateAtCast() && !pac.getNode().getMethod().isStatic() && pac.getValueNumber() == 1) {
// a virtual dispatch is just like a cast. No flow.
return EmptyIterator.instance();
}
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(pac.getNode())) {
// don't track flow for reflection
return EmptyIterator.instance();
}
// data dependence predecessors
for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(N.getNode()))) {
for (CallSiteReference site : Iterator2Iterable.make(cg.getPossibleSites(caller, N.getNode()))) {
IR ir = caller.getIR();
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) ir.getInstructions()[i];
if (call.getNumberOfUses() > parameterIndex) {
int p = call.getUse(parameterIndex);
Statement s = new ParamCaller(caller, i, p);
addNode(s);
result.add(s);
}
}
}
}
}
// if (!cOptions.equals(ControlDependenceOptions.NONE)) {
// Statement s = new MethodEntryStatement(N.getNode());
// addNode(s);
// result.add(s);
// }
return result.iterator();
}
case HEAP_PARAM_CALLEE: {
HeapStatement.HeapParamCallee hpc = (HeapStatement.HeapParamCallee) N;
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(N.getNode()))) {
for (CallSiteReference site : Iterator2Iterable.make(cg.getPossibleSites(caller, N.getNode()))) {
IR ir = caller.getIR();
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
Statement s = new HeapStatement.HeapParamCaller(caller, i, hpc.getLocation());
addNode(s);
result.add(s);
}
}
}
}
// if (!cOptions.equals(ControlDependenceOptions.NONE)) {
// Statement s = new MethodEntryStatement(N.getNode());
// addNode(s);
// result.add(s);
// }
return result.iterator();
}
case METHOD_ENTRY:
Collection<Statement> result = HashSetFactory.make(5);
if (!cOptions.isIgnoreInterproc()) {
for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(N.getNode()))) {
for (CallSiteReference site : Iterator2Iterable.make(cg.getPossibleSites(caller, N.getNode()))) {
IR ir = caller.getIR();
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
Statement s = new NormalStatement(caller, i);
addNode(s);
result.add(s);
}
}
}
}
return result.iterator();
default:
Assertions.UNREACHABLE(N.getKind().toString());
return null;
}
}
@Override
public int getSuccNodeCount(Statement N) {
return IteratorUtil.count(getSuccNodes(N));
}
@Override
public Iterator<Statement> getSuccNodes(Statement N) {
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(N.getNode())) {
return EmptyIterator.instance();
}
addPDGStatementNodes(N.getNode());
switch (N.getKind()) {
case NORMAL:
if (cOptions.isIgnoreInterproc()) {
return getPDG(N.getNode()).getSuccNodes(N);
} else {
NormalStatement ns = (NormalStatement) N;
if (ns.getInstruction() instanceof SSAAbstractInvokeInstruction) {
HashSet<Statement> result = HashSetFactory.make();
SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) ns.getInstruction();
for (CGNode t : cg.getPossibleTargets(N.getNode(), call.getCallSite())) {
Statement s = new MethodEntryStatement(t);
addNode(s);
result.add(s);
}
return new CompoundIterator<>(result.iterator(), getPDG(N.getNode()).getSuccNodes(N));
} else {
return getPDG(N.getNode()).getSuccNodes(N);
}
}
case PHI:
case PI:
case CATCH:
case EXC_RET_CALLER:
case NORMAL_RET_CALLER:
case PARAM_CALLEE:
case HEAP_PARAM_CALLEE:
case HEAP_RET_CALLER:
case METHOD_ENTRY:
case METHOD_EXIT:
return getPDG(N.getNode()).getSuccNodes(N);
case EXC_RET_CALLEE: {
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(N.getNode()))) {
for (CallSiteReference site : Iterator2Iterable.make(cg.getPossibleSites(caller, N.getNode()))) {
IR ir = caller.getIR();
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
Statement s = new ExceptionalReturnCaller(caller, i);
addNode(s);
result.add(s);
}
}
}
}
return result.iterator();
}
case NORMAL_RET_CALLEE: {
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(N.getNode()))) {
for (CallSiteReference site : Iterator2Iterable.make(cg.getPossibleSites(caller, N.getNode()))) {
IR ir = caller.getIR();
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
Statement s = new NormalReturnCaller(caller, i);
addNode(s);
result.add(s);
}
}
}
}
return result.iterator();
}
case HEAP_RET_CALLEE: {
HeapStatement.HeapReturnCallee r = (HeapStatement.HeapReturnCallee) N;
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence predecessors
for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(N.getNode()))) {
for (CallSiteReference site : Iterator2Iterable.make(cg.getPossibleSites(caller, N.getNode()))) {
IR ir = caller.getIR();
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
Statement s = new HeapStatement.HeapReturnCaller(caller, i, r.getLocation());
addNode(s);
result.add(s);
}
}
}
}
return result.iterator();
}
case PARAM_CALLER: {
ParamCaller pac = (ParamCaller) N;
SSAAbstractInvokeInstruction call = pac.getInstruction();
int numParamsPassed = call.getNumberOfUses();
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence successors
for (CGNode t : cg.getPossibleTargets(N.getNode(), call.getCallSite())) {
// in some languages (*cough* JavaScript *cough*) you can pass
// fewer parameters than the number of formals. So, only loop
// over the parameters actually being passed here
for (int i = 0; i < t.getMethod().getNumberOfParameters() && i < numParamsPassed; i++) {
if (dOptions.isTerminateAtCast() && call.isDispatch() && pac.getValueNumber() == call.getReceiver()) {
// a virtual dispatch is just like a cast.
continue;
}
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(t)) {
// don't track reflection into reflective invokes
continue;
}
if (call.getUse(i) == pac.getValueNumber()) {
Statement s = new ParamCallee(t, i + 1);
addNode(s);
result.add(s);
}
}
}
}
return result.iterator();
}
case HEAP_PARAM_CALLER:
HeapStatement.HeapParamCaller pc = (HeapStatement.HeapParamCaller) N;
SSAAbstractInvokeInstruction call = pc.getCall();
Collection<Statement> result = HashSetFactory.make(5);
if (!dOptions.equals(DataDependenceOptions.NONE)) {
// data dependence successors
for (CGNode t : cg.getPossibleTargets(N.getNode(), call.getCallSite())) {
if (ref.get(t).contains(pc.getLocation())) {
Statement s = new HeapStatement.HeapParamCallee(t, pc.getLocation());
addNode(s);
result.add(s);
}
}
}
return result.iterator();
default:
Assertions.UNREACHABLE(N.getKind().toString());
return null;
}
}
/**
* Should we cut off flow into node t when processing reflection?
*/
private boolean isUninformativeForReflection(CGNode t) {
if (t.getMethod().getDeclaringClass().getReference().equals(TypeReference.JavaLangReflectMethod)) {
return true;
}
if (t.getMethod().getDeclaringClass().getReference().equals(TypeReference.JavaLangReflectConstructor)) {
return true;
}
if (t.getMethod().getSelector().equals(MethodReference.equalsSelector)) {
return true;
}
return false;
}
@Override
public boolean hasEdge(Statement src, Statement dst) {
addPDGStatementNodes(src.getNode());
addPDGStatementNodes(dst.getNode());
switch (src.getKind()) {
case NORMAL:
if (cOptions.isIgnoreInterproc()) {
return getPDG(src.getNode()).hasEdge(src, dst);
} else {
NormalStatement ns = (NormalStatement) src;
if (dst instanceof MethodEntryStatement) {
if (ns.getInstruction() instanceof SSAAbstractInvokeInstruction) {
SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) ns.getInstruction();
return cg.getPossibleTargets(src.getNode(), call.getCallSite()).contains(dst.getNode());
} else {
return false;
}
} else {
return getPDG(src.getNode()).hasEdge(src, dst);
}
}
case PHI:
case PI:
case EXC_RET_CALLER:
case NORMAL_RET_CALLER:
case PARAM_CALLEE:
case HEAP_PARAM_CALLEE:
case HEAP_RET_CALLER:
case METHOD_ENTRY:
case METHOD_EXIT:
return getPDG(src.getNode()).hasEdge(src, dst);
case EXC_RET_CALLEE: {
if (dOptions.equals(DataDependenceOptions.NONE)) {
return false;
}
if (dst.getKind().equals(Kind.EXC_RET_CALLER)) {
ExceptionalReturnCaller r = (ExceptionalReturnCaller) dst;
return cg.getPossibleTargets(r.getNode(), r.getInstruction().getCallSite()).contains(src.getNode());
} else {
return false;
}
}
case NORMAL_RET_CALLEE: {
if (dOptions.equals(DataDependenceOptions.NONE)) {
return false;
}
if (dst.getKind().equals(Kind.NORMAL_RET_CALLER)) {
NormalReturnCaller r = (NormalReturnCaller) dst;
return cg.getPossibleTargets(r.getNode(), r.getInstruction().getCallSite()).contains(src.getNode());
} else {
return false;
}
}
case HEAP_RET_CALLEE: {
if (dOptions.equals(DataDependenceOptions.NONE)) {
return false;
}
if (dst.getKind().equals(Kind.HEAP_RET_CALLER)) {
HeapStatement.HeapReturnCaller r = (HeapStatement.HeapReturnCaller) dst;
HeapStatement h = (HeapStatement) src;
return h.getLocation().equals(r.getLocation())
&& cg.getPossibleTargets(r.getNode(), r.getCall().getCallSite()).contains(src.getNode());
} else {
return false;
}
}
case PARAM_CALLER: {
if (dOptions.equals(DataDependenceOptions.NONE)) {
return false;
}
if (dst.getKind().equals(Kind.PARAM_CALLEE)) {
ParamCallee callee = (ParamCallee) dst;
ParamCaller caller = (ParamCaller) src;
SSAAbstractInvokeInstruction call = caller.getInstruction();
final CGNode calleeNode = callee.getNode();
if (!cg.getPossibleTargets(caller.getNode(), call.getCallSite()).contains(calleeNode)) {
return false;
}
if (dOptions.isTerminateAtCast() && call.isDispatch() && caller.getValueNumber() == call.getReceiver()) {
// a virtual dispatch is just like a cast.
return false;
}
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(calleeNode)) {
// don't track reflection into reflective invokes
return false;
}
for (int i = 0; i < call.getNumberOfPositionalParameters(); i++) {
if (call.getUse(i) == caller.getValueNumber()) {
if (callee.getValueNumber() == i + 1) {
return true;
}
}
}
return false;
} else {
return false;
}
}
case HEAP_PARAM_CALLER:
if (dOptions.equals(DataDependenceOptions.NONE)) {
return false;
}
if (dst.getKind().equals(Kind.HEAP_PARAM_CALLEE)) {
HeapStatement.HeapParamCallee callee = (HeapStatement.HeapParamCallee) dst;
HeapStatement.HeapParamCaller caller = (HeapStatement.HeapParamCaller) src;
return caller.getLocation().equals(callee.getLocation())
&& cg.getPossibleTargets(caller.getNode(), caller.getCall().getCallSite()).contains(callee.getNode());
} else {
return false;
}
default:
Assertions.UNREACHABLE(src.getKind());
return false;
}
}
@Override
public void removeAllIncidentEdges(Statement node) {
Assertions.UNREACHABLE();
}
@Override
public void removeEdge(Statement src, Statement dst) {
Assertions.UNREACHABLE();
}
@Override
public void removeIncomingEdges(Statement node) {
Assertions.UNREACHABLE();
}
@Override
public void removeOutgoingEdges(Statement node) {
Assertions.UNREACHABLE();
}
@Override
public IntSet getPredNodeNumbers(Statement node) {
// TODO: optimize me.
MutableSparseIntSet result = MutableSparseIntSet.makeEmpty();
for (Statement s : Iterator2Iterable.make(getPredNodes(node))) {
result.add(getNumber(s));
}
return result;
}
@Override
public IntSet getSuccNodeNumbers(Statement node) {
// TODO: optimize me.
MutableSparseIntSet result = MutableSparseIntSet.makeEmpty();
for (Statement s : Iterator2Iterable.make(getSuccNodes(node))) {
result.add(getNumber(s));
}
return result;
}
}
@Override
protected NumberedEdgeManager<Statement> getEdgeManager() {
return edgeMgr;
}
@Override
public NumberedNodeManager<Statement> getNodeManager() {
return nodeMgr;
}
@Override
public PDG<T> getPDG(CGNode node) {
PDG<T> result = pdgMap.get(node);
if (result == null) {
result = new PDG<>(node, pa, mod, ref, dOptions, cOptions, heapExclude, cg, modRef);
pdgMap.put(node, result);
// Let's not eagerly add nodes, shall we?
// for (Iterator<? extends Statement> it = result.iterator(); it.hasNext();) {
// nodeMgr.addNode(it.next());
// }
}
return result;
}
@Override
public ControlDependenceOptions getCOptions() {
return cOptions;
}
public DataDependenceOptions getDOptions() {
return dOptions;
}
public CallGraph getCallGraph() {
return cg;
}
@Override
public IClassHierarchy getClassHierarchy() {
return cg.getClassHierarchy();
}
public PointerAnalysis<T> getPointerAnalysis() {
return pa;
}
}