All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.spark.solver.OnFlyCallGraph Maven / Gradle / Ivy

package soot.jimple.spark.solver;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2002 - 2003 Ondrej Lhotak
 * %%
 * 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 soot.Context;
import soot.Local;
import soot.MethodOrMethodContext;
import soot.Scene;
import soot.Type;
import soot.jimple.IntConstant;
import soot.jimple.NewArrayExpr;
import soot.jimple.spark.pag.AllocDotField;
import soot.jimple.spark.pag.AllocNode;
import soot.jimple.spark.pag.ArrayElement;
import soot.jimple.spark.pag.MethodPAG;
import soot.jimple.spark.pag.Node;
import soot.jimple.spark.pag.PAG;
import soot.jimple.spark.pag.StringConstantNode;
import soot.jimple.spark.pag.VarNode;
import soot.jimple.spark.sets.P2SetVisitor;
import soot.jimple.spark.sets.PointsToSetInternal;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.CallGraphBuilder;
import soot.jimple.toolkits.callgraph.ContextManager;
import soot.jimple.toolkits.callgraph.Edge;
import soot.jimple.toolkits.callgraph.OnFlyCallGraphBuilder;
import soot.jimple.toolkits.callgraph.ReachableMethods;
import soot.util.queue.QueueReader;

/**
 * The interface between the pointer analysis engine and the on-the-fly call graph builder.
 * 
 * @author Ondrej Lhotak
 */

public class OnFlyCallGraph {
  protected final OnFlyCallGraphBuilder ofcgb;
  protected final ReachableMethods reachableMethods;
  protected final QueueReader reachablesReader;
  protected final QueueReader callEdges;
  protected final CallGraph callGraph;

  public ReachableMethods reachableMethods() {
    return reachableMethods;
  }

  public CallGraph callGraph() {
    return callGraph;
  }

  public OnFlyCallGraph(PAG pag, boolean appOnly) {
    this.pag = pag;
    callGraph = Scene.v().internalMakeCallGraph();
    Scene.v().setCallGraph(callGraph);
    ContextManager cm = CallGraphBuilder.makeContextManager(callGraph);
    reachableMethods = Scene.v().getReachableMethods();
    ofcgb = new OnFlyCallGraphBuilder(cm, reachableMethods, appOnly);
    reachablesReader = reachableMethods.listener();
    callEdges = cm.callGraph().listener();
  }

  public void build() {
    ofcgb.processReachables();
    processReachables();
    processCallEdges();
  }

  private void processReachables() {
    reachableMethods.update();
    while (reachablesReader.hasNext()) {
      MethodOrMethodContext m = reachablesReader.next();
      MethodPAG mpag = MethodPAG.v(pag, m.method());
      mpag.build();
      mpag.addToPAG(m.context());
    }
  }

  private void processCallEdges() {
    while (callEdges.hasNext()) {
      Edge e = callEdges.next();
      MethodPAG amp = MethodPAG.v(pag, e.tgt());
      amp.build();
      amp.addToPAG(e.tgtCtxt());
      pag.addCallTarget(e);
    }
  }

  public OnFlyCallGraphBuilder ofcgb() {
    return ofcgb;
  }

  public void updatedFieldRef(final AllocDotField df, PointsToSetInternal ptsi) {
    if (df.getField() != ArrayElement.v()) {
      return;
    }
    if (ofcgb.wantArrayField(df)) {
      ptsi.forall(new P2SetVisitor() {
        @Override
        public void visit(Node n) {
          ofcgb.addInvokeArgType(df, null, n.getType());
        }
      });
    }
  }

  public void updatedNode(VarNode vn) {
    Object r = vn.getVariable();
    if (!(r instanceof Local)) {
      return;
    }
    final Local receiver = (Local) r;
    final Context context = vn.context();

    PointsToSetInternal p2set = vn.getP2Set().getNewSet();
    if (ofcgb.wantTypes(receiver)) {
      p2set.forall(new P2SetVisitor() {
        public final void visit(Node n) {
          if (n instanceof AllocNode) {
            ofcgb.addType(receiver, context, n.getType(), (AllocNode) n);
          }
        }
      });
    }
    if (ofcgb.wantStringConstants(receiver)) {
      p2set.forall(new P2SetVisitor() {
        public final void visit(Node n) {
          if (n instanceof StringConstantNode) {
            String constant = ((StringConstantNode) n).getString();
            ofcgb.addStringConstant(receiver, context, constant);
          } else {
            ofcgb.addStringConstant(receiver, context, null);
          }
        }
      });
    }
    if (ofcgb.wantInvokeArg(receiver)) {
      p2set.forall(new P2SetVisitor() {
        @Override
        public void visit(Node n) {
          if (n instanceof AllocNode) {
            AllocNode an = ((AllocNode) n);
            ofcgb.addInvokeArgDotField(receiver, pag.makeAllocDotField(an, ArrayElement.v()));
            assert an.getNewExpr() instanceof NewArrayExpr;
            NewArrayExpr nae = (NewArrayExpr) an.getNewExpr();
            if (!(nae.getSize() instanceof IntConstant)) {
              ofcgb.setArgArrayNonDetSize(receiver, context);
            } else {
              IntConstant sizeConstant = (IntConstant) nae.getSize();
              ofcgb.addPossibleArgArraySize(receiver, sizeConstant.value, context);
            }
          }
        }
      });
      for (Type ty : pag.reachingObjectsOfArrayElement(p2set).possibleTypes()) {
        ofcgb.addInvokeArgType(receiver, context, ty);
      }
    }
  }

  /** Node uses this to notify PAG that n2 has been merged into n1. */
  public void mergedWith(Node n1, Node n2) {
  }

  /* End of public methods. */
  /* End of package methods. */

  private PAG pag;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy