soot.jimple.toolkits.pointer.LocalMustNotAliasAnalysis Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
package soot.jimple.toolkits.pointer;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2007 Patrick Lam
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import soot.Body;
import soot.Local;
import soot.RefType;
import soot.Unit;
import soot.Value;
import soot.jimple.DefinitionStmt;
import soot.jimple.NewExpr;
import soot.jimple.Stmt;
import soot.jimple.internal.AbstractNewExpr;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.ForwardFlowAnalysis;
/**
* LocalNotMayAliasAnalysis attempts to determine if two local variables (at two potentially different program points)
* definitely point to different objects.
*
* The underlying abstraction is that of definition expressions. When a local variable gets assigned a new object (unlike
* LocalMust, only NewExprs), the analysis tracks the source of the value. If two variables have different sources, then they
* are different.
*
* See Sable TR 2007-8 for details.
*
* @author Patrick Lam
*/
public class LocalMustNotAliasAnalysis extends ForwardFlowAnalysis>> {
@SuppressWarnings("serial")
protected static final NewExpr UNKNOWN = new AbstractNewExpr() {
@Override
public String toString() {
return "UNKNOWN";
}
@Override
public Object clone() {
return this;
}
};
protected final Set locals;
public LocalMustNotAliasAnalysis(UnitGraph g) {
this(g, g.getBody());
}
public LocalMustNotAliasAnalysis(DirectedGraph directedGraph, Body b) {
super(directedGraph);
this.locals = new HashSet(b.getLocals());
doAnalysis();
}
@Override
protected void merge(HashMap> in1, HashMap> in2, HashMap> o) {
for (Local l : locals) {
Set l1 = in1.get(l), l2 = in2.get(l);
Set out = o.get(l);
out.clear();
if (l1.contains(UNKNOWN) || l2.contains(UNKNOWN)) {
out.add(UNKNOWN);
} else {
out.addAll(l1);
out.addAll(l2);
}
}
}
@Override
protected void flowThrough(HashMap> in, Unit unit, HashMap> out) {
out.clear();
out.putAll(in);
if (unit instanceof DefinitionStmt) {
DefinitionStmt ds = (DefinitionStmt) unit;
Value lhs = ds.getLeftOp();
if (lhs instanceof Local) {
HashSet lv = new HashSet();
out.put((Local) lhs, lv);
Value rhs = ds.getRightOp();
if (rhs instanceof NewExpr) {
lv.add((NewExpr) rhs);
} else if (rhs instanceof Local) {
lv.addAll(in.get((Local) rhs));
} else {
lv.add(UNKNOWN);
}
}
}
}
@Override
protected void copy(HashMap> source, HashMap> dest) {
dest.putAll(source);
}
@Override
protected HashMap> entryInitialFlow() {
HashMap> m = new HashMap>();
for (Local l : locals) {
HashSet s = new HashSet();
s.add(UNKNOWN);
m.put(l, s);
}
return m;
}
@Override
protected HashMap> newInitialFlow() {
HashMap> m = new HashMap>();
for (Local l : locals) {
m.put(l, new HashSet());
}
return m;
}
/**
* Returns true if this analysis has any information about local l at statement s (i.e. it is not {@link #UNKNOWN}). In
* particular, it is safe to pass in locals/statements that are not even part of the right method. In those cases
* false
will be returned. Permits s to be null
, in which case false
will be
* returned.
*/
public boolean hasInfoOn(Local l, Stmt s) {
HashMap> flowBefore = getFlowBefore(s);
if (flowBefore == null) {
return false;
} else {
Set info = flowBefore.get(l);
return info != null && !info.contains(UNKNOWN);
}
}
/**
* @return true if values of l1 (at s1) and l2 (at s2) are known to point to different objects
*/
public boolean notMayAlias(Local l1, Stmt s1, Local l2, Stmt s2) {
Set l1n = getFlowBefore(s1).get(l1);
Set l2n = getFlowBefore(s2).get(l2);
if (l1n.contains(UNKNOWN) || l2n.contains(UNKNOWN)) {
return false;
}
Set n = new HashSet(l1n);
n.retainAll(l2n);
return n.isEmpty();
}
/**
* If the given local at the given statement was initialized with a single, concrete new-expression then the type of this
* expression is returned. Otherwise this method returns null.
*/
public RefType concreteType(Local l, Stmt s) {
Set set = getFlowBefore(s).get(l);
if (set.size() != 1) {
return null;
} else {
NewExpr singleNewExpr = set.iterator().next();
return (singleNewExpr == UNKNOWN) ? null : (RefType) singleNewExpr.getType();
}
}
}