/**
*
*
* @author Ju Qian {jqian@live.com}
* @date 2011-8-8
* @version
*/
package jqian.sootex.sideeffect;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import soot.Body;
import soot.Local;
import soot.RefLikeType;
import soot.SootMethod;
import soot.Type;
import soot.jimple.toolkits.typing.fast.BottomType;
import soot.Unit;
import soot.Value;
import soot.jimple.AnyNewExpr;
import soot.jimple.ArrayRef;
import soot.jimple.CastExpr;
import soot.jimple.Constant;
import soot.jimple.DefinitionStmt;
import soot.jimple.IdentityStmt;
import soot.jimple.InstanceFieldRef;
import soot.jimple.InvokeExpr;
import soot.jimple.ReturnStmt;
import soot.jimple.StaticFieldRef;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.shimple.PhiExpr;
import soot.toolkits.graph.HashMutableDirectedGraph;
import soot.toolkits.graph.MutableDirectedGraph;
import jqian.Global;
import jqian.sootex.Cache;
import jqian.sootex.util.SootUtils;
import jqian.sootex.util.callgraph.Callees;
import jqian.sootex.util.graph.GraphHelper;
import jqian.util.Utils;
/**
* Implement the fresh method and variable analysis provided by Gay@CC 2000
* A fresh method return a newly created objects (not exist before method call).
* NOTE that the object may already bean escaped or also return from parameters.
*
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class FreshAnalysis implements ILocalityQuery{
// ���ʶ����Ǵ�������
protected boolean[] _mfresh;
protected Set<Local>[] _vnfresh; //non fresh locals
protected CallGraph _cg;
public FreshAnalysis(CallGraph cg){
this._cg = cg;
}
protected MutableDirectedGraph<Object> initVarConnectionGraph(SootMethod m){
// build a variable connection graph
HashMutableDirectedGraph varConn = new HashMutableDirectedGraph();
Body body = m.retrieveActiveBody();
varConn.addNode(Boolean.TRUE);
varConn.addNode(Boolean.FALSE);
for(Local l: body.getLocals()){
Type t = l.getType();
if(t instanceof RefLikeType){
varConn.addNode(l);
}
else if(t instanceof BottomType){
varConn.addNode(l);
}
}
return varConn;
}
protected void freshAnalysis(SootMethod m){
Set<Local> returns = new HashSet<Local>();
// build a constraint graph
MutableDirectedGraph<Object> varConn = initVarConnectionGraph(m);
Body body = m.retrieveActiveBody();
for(Unit u: body.getUnits()){
if(u instanceof ReturnStmt){
Value v = ((ReturnStmt)u).getOp();
if(v.getType() instanceof RefLikeType && v instanceof Local){
returns.add((Local)v);
}
}
else if(u instanceof DefinitionStmt){
DefinitionStmt d = (DefinitionStmt)u;
Value left = d.getLeftOp();
Value right = d.getRightOp();
Type leftType = left.getType();
//assignment on non-reference variables
if(!(leftType instanceof RefLikeType) && !(leftType instanceof BottomType)){
}
else if(left instanceof Local){
//1. l = @param, l = @this
if(d instanceof IdentityStmt){
varConn.addEdge(Boolean.FALSE, left);
}
//2. "l = new C", "l = constant"
else if(right instanceof AnyNewExpr || right instanceof Constant){}
//3. l = r
else if(right instanceof Local){
varConn.addEdge(right, left);
}
//4. l = (cast)r
else if(right instanceof CastExpr){
CastExpr cast = (CastExpr)right;
Value op = cast.getOp();
if(op instanceof Local){
varConn.addEdge(op, left);
}
}
//5. l = r.f
else if(right instanceof InstanceFieldRef){
varConn.addEdge(Boolean.FALSE, left);
}
//6. l = r[]
else if(right instanceof ArrayRef){
varConn.addEdge(Boolean.FALSE, left);
}
//7. l = g
else if(right instanceof StaticFieldRef){
varConn.addEdge(Boolean.FALSE, left);
}//8. l=Phi();
else if (right instanceof PhiExpr) {
List<Value> args = ((PhiExpr) right).getValues();
for(Value a: args){
varConn.addEdge(a, left);
//varConn.addEdge(left, value);
}
}
else if(right instanceof InvokeExpr){
Callees callees = new Callees(_cg, u);
boolean allFresh = true;
for(SootMethod tgt: callees.explicits()){
if(!isFreshMethod(tgt)){
allFresh = false;
break;
}
}
if(!allFresh){
varConn.addEdge(Boolean.FALSE, left);
}
}
else{
if(!(leftType instanceof BottomType)){
// throw new RuntimeException();
}
else{
System.out.println("BottomType unit: "+u);
}
}
}
//6. g = r
else if(left instanceof StaticFieldRef){}
//7. l.f = r
else if(left instanceof InstanceFieldRef){}
//9. l[] = r
else if(left instanceof ArrayRef){}
//others
else{
throw new RuntimeException();
}
}
}
// solve constraints
// XXX
Set nonfresh = GraphHelper.getReachables(varConn, Boolean.FALSE);
_vnfresh[m.getNumber()] = nonfresh;
boolean rfresh = true;
for (Local r : returns) {
if (nonfresh.contains(r)) {
rfresh = false;
break;
}
}
_mfresh[m.getNumber()] = rfresh;
}
public void build() {
Date startTime = new Date();
_mfresh = new boolean[SootUtils.getMethodCount()];
_vnfresh = new Set[SootUtils.getMethodCount()];
List<?> rm = Cache.v().getTopologicalOrder();
for (Iterator<?> it = rm.iterator(); it.hasNext();) {
SootMethod m = (SootMethod) it.next();
if(m.isConcrete()){
freshAnalysis(m);
}
}
_cg = null;
Date endTime = new Date();
Global.v().out.println("[FreshAnalysis] " + rm.size() + " methods analyszed in " + Utils.getTimeConsumed(startTime, endTime));
}
public boolean isFreshMethod(SootMethod m){
return _mfresh[m.getNumber()];
}
public boolean isRefTgtLocal(SootMethod m, Local v) {
return false;
}
public boolean isRefTgtFresh(SootMethod m, Local v) {
Set<Local> nonfresh = _vnfresh[m.getNumber()];
if(nonfresh!=null){
return !nonfresh.contains(v);
}
else{
return false;
}
}
}