2012-09-04 22:56:05 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* 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.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.PointerKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey;
|
|
|
|
import com.ibm.wala.types.MethodReference;
|
|
|
|
import com.ibm.wala.util.WalaException;
|
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
2017-12-04 04:39:28 +00:00
|
|
|
import com.ibm.wala.util.collections.Iterator2Iterable;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Trivial method-level escape analysis.
|
|
|
|
*
|
|
|
|
* An instance does not escape from method m if the following hold:
|
|
|
|
* <ol>
|
|
|
|
* <li>the instance is only ever pointed to by locals (it is never stored in the heap)
|
|
|
|
* <li>the method m does NOT return (either normally or exceptionally) a pointer to the instance
|
|
|
|
* </ol>
|
|
|
|
*/
|
|
|
|
public class TrivialMethodEscape implements IMethodEscapeAnalysis, INodeEscapeAnalysis {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Heap graph representation of pointer analysis
|
|
|
|
*/
|
2017-03-15 05:04:21 +00:00
|
|
|
private final HeapGraph<InstanceKey> hg;
|
2012-09-04 22:56:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Governing call graph
|
|
|
|
*/
|
|
|
|
private final CallGraph cg;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param hg Heap graph representation of pointer analysis
|
|
|
|
* @param cg governing call graph
|
|
|
|
*/
|
2017-03-15 05:04:21 +00:00
|
|
|
public TrivialMethodEscape(CallGraph cg, HeapGraph<InstanceKey> hg) {
|
2012-09-04 22:56:05 +00:00
|
|
|
this.hg = hg;
|
|
|
|
this.cg = cg;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean mayEscape(MethodReference allocMethod, int allocPC, MethodReference m) throws WalaException {
|
|
|
|
|
|
|
|
if (allocMethod == null) {
|
|
|
|
throw new IllegalArgumentException("null allocMethod");
|
|
|
|
}
|
|
|
|
// nodes:= set of call graph nodes representing method m
|
|
|
|
Set nodes = cg.getNodes(m);
|
|
|
|
if (nodes.size() == 0) {
|
|
|
|
throw new WalaException("could not find call graph node for method " + m);
|
|
|
|
}
|
|
|
|
|
|
|
|
// allocN := set of call graph nodes representing method allocMethod
|
2017-11-28 20:02:37 +00:00
|
|
|
Set<CGNode> allocN = cg.getNodes(allocMethod);
|
2012-09-04 22:56:05 +00:00
|
|
|
if (allocN.size() == 0) {
|
|
|
|
throw new WalaException("could not find call graph node for allocation method " + allocMethod);
|
|
|
|
}
|
|
|
|
return mayEscape(allocN, allocPC, nodes);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-09-04 22:56:05 +00:00
|
|
|
public boolean mayEscape(CGNode allocNode, int allocPC, CGNode node) throws WalaException {
|
|
|
|
return mayEscape(Collections.singleton(allocNode), allocPC, Collections.singleton(node));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param allocN Set<CGNode> representing the allocation site.
|
|
|
|
* @param allocPC
|
|
|
|
* @param nodes Set<CGNode>, the nodes of interest
|
|
|
|
* @return true iff some instance allocated at a site N \in <allocN, allocPC> might escape from some activation of a node m \in
|
|
|
|
* { nodes }
|
|
|
|
* @throws WalaException
|
|
|
|
*/
|
2017-11-28 20:02:37 +00:00
|
|
|
private boolean mayEscape(Set<CGNode> allocN, int allocPC, Set nodes) throws WalaException {
|
2012-09-04 22:56:05 +00:00
|
|
|
Set<InstanceKey> instances = HashSetFactory.make();
|
|
|
|
// instances := set of instance key allocated at <allocMethod, allocPC>
|
2017-11-28 20:26:09 +00:00
|
|
|
for (CGNode n : allocN) {
|
2012-09-04 22:56:05 +00:00
|
|
|
NewSiteReference site = findAlloc(n, allocPC);
|
|
|
|
InstanceKey ik = hg.getHeapModel().getInstanceKeyForAllocation(n, site);
|
|
|
|
if (ik == null) {
|
|
|
|
throw new WalaException("could not get instance key at site " + site + " in " + n);
|
|
|
|
}
|
|
|
|
instances.add(ik);
|
|
|
|
}
|
|
|
|
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey ik : instances) {
|
2017-12-04 04:39:28 +00:00
|
|
|
for (Object o : Iterator2Iterable.make(hg.getPredNodes(ik))) {
|
|
|
|
PointerKey p = (PointerKey) o;
|
2012-09-04 22:56:05 +00:00
|
|
|
if (!(p instanceof AbstractLocalPointerKey)) {
|
|
|
|
// a pointer from the heap. give up.
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (p instanceof ReturnValueKey) {
|
|
|
|
ReturnValueKey rk = (ReturnValueKey) p;
|
|
|
|
if (nodes.contains(rk.getNode())) {
|
|
|
|
// some node representing method m returns the instance to its
|
|
|
|
// caller
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we get here, it may not escape
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param n a call graph node
|
|
|
|
* @param allocPC a bytecode index corresponding to an allocation
|
|
|
|
* @return the NewSiteReference for the allocation
|
|
|
|
* @throws WalaException
|
|
|
|
*/
|
|
|
|
static NewSiteReference findAlloc(CGNode n, int allocPC) throws WalaException {
|
|
|
|
if (n == null) {
|
|
|
|
throw new IllegalArgumentException("null n");
|
|
|
|
}
|
2017-12-04 04:39:28 +00:00
|
|
|
for (NewSiteReference site : Iterator2Iterable.make(n.iterateNewSites())) {
|
2012-09-04 22:56:05 +00:00
|
|
|
if (site.getProgramCounter() == allocPC) {
|
|
|
|
return site;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new WalaException("Failed to find an allocation at pc " + allocPC + " in node " + n);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|