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

sootup.analysis.interprocedural.icfg.AbstractJimpleBasedICFG Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
package sootup.analysis.interprocedural.icfg;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2022 Kadiray Karakaya 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.*;
import javax.annotation.Nonnull;
import sootup.core.graph.StmtGraph;
import sootup.core.jimple.basic.Value;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.Body;
import sootup.core.model.SootMethod;
import sootup.core.views.View;

public abstract class AbstractJimpleBasedICFG implements BiDiInterproceduralCFG {

  protected final boolean enableExceptions;

  protected View view;

  @DontSynchronize("written by single thread; read afterwards")
  private final Map stmtToOwner = createStmtToOwnerMap();

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

  @SynchronizedBy("by use of synchronized LoadingCache class")
  protected LoadingCache> methodToParameterRefs =
      IDESolver.DEFAULT_CACHE_BUILDER.build(
          new CacheLoader>() {
            @Override
            public List load(@Nonnull SootMethod m) {
              return new ArrayList<>(m.getBody().getParameterLocals());
            }
          });

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

  protected AbstractJimpleBasedICFG() {
    this(true);
  }

  protected Map createStmtToOwnerMap() {
    return new LinkedHashMap<>();
  }

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

  public Body getBodyOf(Stmt stmt) {
    assert stmtToOwner.containsKey(stmt) : "Statement " + stmt + " not in Stmt-to-owner mapping";
    return stmtToOwner.get(stmt);
  }

  @Override
  public SootMethod getMethodOf(Stmt stmt) {
    Body b = getBodyOf(stmt);
    return b == null ? null : view.getMethod(b.getMethodSignature()).orElse(null);
  }

  @Override
  public List getSuccsOf(Stmt stmt) {
    Body body = getBodyOf(stmt);
    if (body == null) {
      return Collections.emptyList();
    }
    StmtGraph unitGraph = getOrCreateStmtGraph(body);
    return unitGraph.successors(stmt);
  }

  @Override
  public StmtGraph getOrCreateStmtGraph(SootMethod method) {
    return getOrCreateStmtGraph(method.getBody());
  }

  public StmtGraph getOrCreateStmtGraph(Body body) {
    return bodyToStmtGraph.getUnchecked(body);
  }

  protected StmtGraph makeGraph(Body body) {
    return body.getStmtGraph();
  }

  protected Set getCallsFromWithinMethod(SootMethod method) {
    Set res = null;
    for (Stmt u : method.getBody().getStmts()) {
      if (isCallStmt(u)) {
        if (res == null) {
          res = new LinkedHashSet<>();
        }
        res.add(u);
      }
    }
    return res == null ? Collections.emptySet() : res;
  }

  @Override
  public boolean isExitStmt(Stmt stmt) {
    Body body = getBodyOf(stmt);
    StmtGraph unitGraph = getOrCreateStmtGraph(body);
    return unitGraph.getTails().contains(stmt);
  }

  @Override
  public boolean isStartPoint(Stmt stmt) {
    Body body = getBodyOf(stmt);
    StmtGraph unitGraph = getOrCreateStmtGraph(body);
    return unitGraph.getEntrypoints().contains(stmt);
  }

  @Override
  public boolean isFallThroughSuccessor(Stmt stmt, Stmt successorCandidate) {
    assert getSuccsOf(stmt).contains(successorCandidate);
    if (!stmt.fallsThrough()) {
      return false;
    }
    Body body = getBodyOf(stmt);
    return body.getStmtGraph().successors(stmt).get(0) == successorCandidate;
  }

  @Override
  public boolean isBranchTarget(Stmt u, Stmt succ) {
    assert getSuccsOf(u).contains(succ);
    return u.branches();
  }

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

  @Override
  public Collection getStartPointsOf(SootMethod m) {
    if (m.hasBody()) {
      Body body = m.getBody();
      StmtGraph unitGraph = getOrCreateStmtGraph(body);
      return unitGraph.getEntrypoints();
    }
    return Collections.emptySet();
  }

  public boolean setOwnerStatement(Stmt u, Body b) {
    return stmtToOwner.put(u, b) == null;
  }

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

  @Override
  public Set allNonCallStartNodes() {
    Set res = new LinkedHashSet<>(stmtToOwner.keySet());
    res.removeIf(u -> isStartPoint(u) || isCallStmt(u));
    return res;
  }

  @Override
  public Set allNonCallEndNodes() {
    Set res = new LinkedHashSet<>(stmtToOwner.keySet());
    res.removeIf(u -> isExitStmt(u) || isCallStmt(u));
    return res;
  }

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

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

  public void initializeStmtToOwner(SootMethod m) {
    if (m.hasBody()) {
      Body b = m.getBody();
      for (Stmt node : b.getStmtGraph().getNodes()) {
        stmtToOwner.put(node, b);
      }
    }
  }

  @Override
  public List getPredsOf(Stmt u) {
    assert u != null;
    Body body = getBodyOf(u);
    if (body == null) {
      return Collections.emptyList();
    }
    StmtGraph unitGraph = getOrCreateStmtGraph(body);
    return unitGraph.predecessors(u);
  }

  @Override
  public Collection getEndPointsOf(SootMethod m) {
    if (m.hasBody()) {
      Body body = m.getBody();
      StmtGraph unitGraph = getOrCreateStmtGraph(body);
      return unitGraph.getTails();
    }
    return Collections.emptySet();
  }

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

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

  @Override
  public boolean isReachable(Stmt u) {
    return stmtToOwner.containsKey(u);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy