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

soot.jimple.toolkits.ide.icfg.AbstractJimpleBasedICFG Maven / Gradle / Ivy

package soot.jimple.toolkits.ide.icfg;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
 * %%
 * 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 com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import heros.DontSynchronize;
import heros.SynchronizedBy;
import heros.solver.IDESolver;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import soot.Body;
import soot.SootMethod;
import soot.Unit;
import soot.UnitBox;
import soot.Value;
import soot.jimple.Stmt;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.ExceptionalUnitGraph;

public abstract class AbstractJimpleBasedICFG implements BiDiInterproceduralCFG {

  protected final boolean enableExceptions;

  @DontSynchronize("written by single thread; read afterwards")
  protected final Map unitToOwner = new HashMap();

  @SynchronizedBy("by use of synchronized LoadingCache class")
  protected LoadingCache> bodyToUnitGraph
      = IDESolver.DEFAULT_CACHE_BUILDER.build(new CacheLoader>() {
        @Override
        public DirectedGraph load(Body body) throws Exception {
          return makeGraph(body);
        }
      });

  @SynchronizedBy("by use of synchronized LoadingCache class")
  protected LoadingCache> methodToParameterRefs
      = IDESolver.DEFAULT_CACHE_BUILDER.build(new CacheLoader>() {
        @Override
        public List load(SootMethod m) throws Exception {
          return m.getActiveBody().getParameterRefs();
        }
      });

  @SynchronizedBy("by use of synchronized LoadingCache class")
  protected LoadingCache> methodToCallsFromWithin
      = IDESolver.DEFAULT_CACHE_BUILDER.build(new CacheLoader>() {
        @Override
        public Set load(SootMethod m) throws Exception {
          return getCallsFromWithinMethod(m);
        }
      });

  public AbstractJimpleBasedICFG() {
    this(true);
  }

  public AbstractJimpleBasedICFG(boolean enableExceptions) {
    this.enableExceptions = enableExceptions;
  }

  @Override
  public SootMethod getMethodOf(Unit u) {
    assert unitToOwner.containsKey(u) : "Statement " + u + " not in unit-to-owner mapping";
    Body b = unitToOwner.get(u);
    return b == null ? null : b.getMethod();
  }

  @Override
  public List getSuccsOf(Unit u) {
    Body body = unitToOwner.get(u);
    if (body == null) {
      return Collections.emptyList();
    }
    DirectedGraph unitGraph = getOrCreateUnitGraph(body);
    return unitGraph.getSuccsOf(u);
  }

  @Override
  public DirectedGraph getOrCreateUnitGraph(SootMethod m) {
    return getOrCreateUnitGraph(m.getActiveBody());
  }

  public DirectedGraph getOrCreateUnitGraph(Body body) {
    return bodyToUnitGraph.getUnchecked(body);
  }

  protected DirectedGraph makeGraph(Body body) {
    return enableExceptions ? new ExceptionalUnitGraph(body) : new BriefUnitGraph(body);
  }

  protected Set getCallsFromWithinMethod(SootMethod m) {
    Set res = null;
    for (Unit u : m.getActiveBody().getUnits()) {
      if (isCallStmt(u)) {
        if (res == null) {
          res = new LinkedHashSet();
        }
        res.add(u);
      }
    }
    return res == null ? Collections.emptySet() : res;
  }

  @Override
  public boolean isExitStmt(Unit u) {
    Body body = unitToOwner.get(u);
    DirectedGraph unitGraph = getOrCreateUnitGraph(body);
    return unitGraph.getTails().contains(u);
  }

  @Override
  public boolean isStartPoint(Unit u) {
    Body body = unitToOwner.get(u);
    DirectedGraph unitGraph = getOrCreateUnitGraph(body);
    return unitGraph.getHeads().contains(u);
  }

  @Override
  public boolean isFallThroughSuccessor(Unit u, Unit succ) {
    assert getSuccsOf(u).contains(succ);
    if (!u.fallsThrough()) {
      return false;
    }
    Body body = unitToOwner.get(u);
    return body.getUnits().getSuccOf(u) == succ;
  }

  @Override
  public boolean isBranchTarget(Unit u, Unit succ) {
    assert getSuccsOf(u).contains(succ);
    if (!u.branches()) {
      return false;
    }
    for (UnitBox ub : u.getUnitBoxes()) {
      if (ub.getUnit() == succ) {
        return true;
      }
    }
    return false;
  }

  public List getParameterRefs(SootMethod m) {
    return methodToParameterRefs.getUnchecked(m);
  }

  @Override
  public Collection getStartPointsOf(SootMethod m) {
    if (m.hasActiveBody()) {
      Body body = m.getActiveBody();
      DirectedGraph unitGraph = getOrCreateUnitGraph(body);
      return unitGraph.getHeads();
    }
    return Collections.emptySet();
  }

  @Override
  public boolean isCallStmt(Unit u) {
    return ((Stmt) u).containsInvokeExpr();
  }

  @Override
  public Set allNonCallStartNodes() {
    Set res = new LinkedHashSet(unitToOwner.keySet());
    for (Iterator iter = res.iterator(); iter.hasNext();) {
      Unit u = iter.next();
      if (isStartPoint(u) || isCallStmt(u)) {
        iter.remove();
      }
    }
    return res;
  }

  @Override
  public Set allNonCallEndNodes() {
    Set res = new LinkedHashSet(unitToOwner.keySet());
    for (Iterator iter = res.iterator(); iter.hasNext();) {
      Unit u = iter.next();
      if (isExitStmt(u) || isCallStmt(u)) {
        iter.remove();
      }
    }
    return res;
  }

  @Override
  public Collection getReturnSitesOfCallAt(Unit u) {
    return getSuccsOf(u);
  }

  @Override
  public Set getCallsFromWithin(SootMethod m) {
    return methodToCallsFromWithin.getUnchecked(m);
  }

  @Override
  public List getPredsOf(Unit u) {
    assert u != null;
    Body body = unitToOwner.get(u);
    if (body == null) {
      return Collections.emptyList();
    }
    DirectedGraph unitGraph = getOrCreateUnitGraph(body);
    return unitGraph.getPredsOf(u);
  }

  @Override
  public Collection getEndPointsOf(SootMethod m) {
    if (m.hasActiveBody()) {
      Body body = m.getActiveBody();
      DirectedGraph unitGraph = getOrCreateUnitGraph(body);
      return unitGraph.getTails();
    }
    return Collections.emptySet();
  }

  @Override
  public List getPredsOfCallAt(Unit u) {
    return getPredsOf(u);
  }

  @Override
  public boolean isReturnSite(Unit n) {
    for (Unit pred : getPredsOf(n)) {
      if (isCallStmt(pred)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public boolean isReachable(Unit u) {
    return unitToOwner.containsKey(u);
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy