204 lines
6.8 KiB
Java
204 lines
6.8 KiB
Java
/*******************************************************************************
|
|
* 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.escape;
|
|
|
|
import java.util.Collections;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.analysis.pointers.HeapGraph;
|
|
import com.ibm.wala.classLoader.NewSiteReference;
|
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
|
import com.ibm.wala.ipa.callgraph.CallGraph;
|
|
import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey;
|
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
|
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
|
|
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder.TypedPointerKey;
|
|
import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey;
|
|
import com.ibm.wala.ssa.DefUse;
|
|
import com.ibm.wala.ssa.IR;
|
|
import com.ibm.wala.util.WalaException;
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
import com.ibm.wala.util.collections.Iterator2Iterable;
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
import com.ibm.wala.util.graph.impl.GraphInverter;
|
|
import com.ibm.wala.util.graph.traverse.DFS;
|
|
import com.ibm.wala.util.intset.IntIterator;
|
|
import com.ibm.wala.util.intset.IntSet;
|
|
|
|
/**
|
|
* A simple liveness analysis based on flow-insensitive pointer analysis.
|
|
*/
|
|
public class FILiveObjectAnalysis implements ILiveObjectAnalysis {
|
|
|
|
/**
|
|
* governing call graph
|
|
*/
|
|
private final CallGraph callGraph;
|
|
|
|
/**
|
|
* Graph view of pointer analysis results
|
|
*/
|
|
private final HeapGraph<?> heapGraph;
|
|
|
|
/**
|
|
* Cached map from InstanceKey -> Set<CGNode>
|
|
*/
|
|
final private Map<InstanceKey, Set<CGNode>> liveNodes = HashMapFactory.make();
|
|
|
|
/**
|
|
* Set of instanceKeys which are live everywhere
|
|
*/
|
|
final private Set<InstanceKey> liveEverywhere = HashSetFactory.make();
|
|
|
|
/**
|
|
* A hack for now .. since right now the intraprocedural analysis is expensive
|
|
*/
|
|
private final boolean expensiveIntraproceduralAnalysis;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public FILiveObjectAnalysis(CallGraph callGraph, HeapGraph<?> heapGraph, boolean expensiveIntraproceduralAnalysis) {
|
|
super();
|
|
this.callGraph = callGraph;
|
|
this.heapGraph = heapGraph;
|
|
this.expensiveIntraproceduralAnalysis = expensiveIntraproceduralAnalysis;
|
|
}
|
|
|
|
@Override
|
|
public boolean mayBeLive(CGNode allocMethod, int allocPC, CGNode m, int instructionIndex) throws IllegalArgumentException,
|
|
WalaException {
|
|
if (allocMethod == null) {
|
|
throw new IllegalArgumentException("allocMethod == null");
|
|
}
|
|
NewSiteReference site = TrivialMethodEscape.findAlloc(allocMethod, allocPC);
|
|
InstanceKey ik = heapGraph.getHeapModel().getInstanceKeyForAllocation(allocMethod, site);
|
|
return mayBeLive(ik, m, instructionIndex);
|
|
}
|
|
|
|
/**
|
|
* @param instructionIndex index of an SSA instruction
|
|
*/
|
|
@Override
|
|
public boolean mayBeLive(InstanceKey ik, CGNode m, int instructionIndex) {
|
|
if (liveEverywhere.contains(ik)) {
|
|
return true;
|
|
} else {
|
|
Set<CGNode> live = liveNodes.get(ik);
|
|
if (live != null) {
|
|
if (live.contains(m)) {
|
|
if (instructionIndex == -1) {
|
|
return true;
|
|
} else {
|
|
if (mayBeLiveInSomeCaller(ik, m)) {
|
|
// a hack. if it's live in some caller of m, assume it's live
|
|
// throughout m. this may be imprecise.
|
|
return true;
|
|
} else {
|
|
if (expensiveIntraproceduralAnalysis) {
|
|
return mayBeLiveIntraprocedural(ik, m, instructionIndex);
|
|
} else {
|
|
// be conservative
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
live = computeLiveNodes(ik);
|
|
liveNodes.put(ik, live);
|
|
return mayBeLive(ik, m, instructionIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean mayBeLiveInSomeCaller(InstanceKey ik, CGNode m) {
|
|
for (CGNode n : Iterator2Iterable.make(callGraph.getPredNodes(m))) {
|
|
if (mayBeLive(ik, n, -1)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* precondition: !mayBeLiveInSomeCaller(ik, m)
|
|
*
|
|
* @param instructionIndex index of an SSA instruction
|
|
*/
|
|
private boolean mayBeLiveIntraprocedural(InstanceKey ik, CGNode m, int instructionIndex) {
|
|
|
|
IR ir = m.getIR();
|
|
DefUse du = m.getDU();
|
|
|
|
for (Object p : Iterator2Iterable.make(DFS.iterateDiscoverTime(GraphInverter.invert(heapGraph), ik))) {
|
|
if (p instanceof LocalPointerKey) {
|
|
LocalPointerKey lpk = (LocalPointerKey) p;
|
|
if (lpk.getNode().equals(m)) {
|
|
if (LocalLiveRangeAnalysis.isLive(lpk.getValueNumber(), instructionIndex, ir, du)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Compute the set of nodes in which ik may be live. If it's live everywhere, return an EMPTY_SET, but also record this fact in
|
|
* the "liveEverywhere" set as a side effect
|
|
*/
|
|
private Set<CGNode> computeLiveNodes(InstanceKey ik) {
|
|
Set<CGNode> localRootNodes = HashSetFactory.make();
|
|
for (Object node : Iterator2Iterable.make(DFS.iterateDiscoverTime(GraphInverter.invert(heapGraph), ik))) {
|
|
if (node instanceof StaticFieldKey) {
|
|
liveEverywhere.add(ik);
|
|
return Collections.emptySet();
|
|
} else {
|
|
if (node instanceof AbstractLocalPointerKey) {
|
|
AbstractLocalPointerKey local = (AbstractLocalPointerKey) node;
|
|
localRootNodes.add(local.getNode());
|
|
} else if (node instanceof TypedPointerKey) {
|
|
TypedPointerKey t = (TypedPointerKey) node;
|
|
node = t.getBase();
|
|
if (node instanceof AbstractLocalPointerKey) {
|
|
AbstractLocalPointerKey local = (AbstractLocalPointerKey) node;
|
|
localRootNodes.add(local.getNode());
|
|
} else {
|
|
Assertions.UNREACHABLE("unexpected base of TypedPointerKey: " + node.getClass() + " " + node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return DFS.getReachableNodes(callGraph, localRootNodes);
|
|
}
|
|
|
|
@Override
|
|
public boolean mayBeLive(InstanceKey ik, CGNode m, IntSet instructionIndices) {
|
|
if (instructionIndices == null) {
|
|
throw new IllegalArgumentException("instructionIndices is null");
|
|
}
|
|
// TODO this sucks
|
|
for (IntIterator it = instructionIndices.intIterator(); it.hasNext();) {
|
|
int i = it.next();
|
|
if (mayBeLive(ik, m, i)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|