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

soot.jimple.toolkits.scalar.SlowAvailableExpressionsAnalysis Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
package soot.jimple.toolkits.scalar;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2000 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.ArrayList;
import java.util.HashMap;
import java.util.Map;

import soot.EquivalentValue;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.jimple.AssignStmt;
import soot.jimple.Expr;
import soot.jimple.InvokeExpr;
import soot.jimple.NewArrayExpr;
import soot.jimple.NewExpr;
import soot.jimple.NewMultiArrayExpr;
import soot.jimple.Stmt;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.ArrayFlowUniverse;
import soot.toolkits.scalar.ArrayPackedSet;
import soot.toolkits.scalar.BoundedFlowSet;
import soot.toolkits.scalar.FlowSet;
import soot.toolkits.scalar.FlowUniverse;
import soot.toolkits.scalar.ForwardFlowAnalysis;
import soot.util.Chain;
import soot.util.HashChain;

// future work: fieldrefs.

/**
 * Implements an available expressions analysis on local variables. The current implementation is slow but correct. A better
 * implementation would use an implicit universe and the kill rule would be computed on-the-fly for each statement.
 */
public class SlowAvailableExpressionsAnalysis extends ForwardFlowAnalysis> {
  Map> unitToGenerateSet;
  Map> unitToPreserveSet;
  Map rhsToContainingStmt;
  private final HashMap valueToEquivValue;

  FlowSet emptySet;

  public SlowAvailableExpressionsAnalysis(DirectedGraph dg) {
    super(dg);

    UnitGraph g = (UnitGraph) dg;

    /* we need a universe of all of the expressions. */
    ArrayList exprs = new ArrayList();

    // Consider "a + b". containingExprs maps a and b (object equality) both to "a + b" (equivalence).
    HashMap> containingExprs
        = new HashMap>();

    // maps a Value to its EquivalentValue.
    valueToEquivValue = new HashMap();

    // maps an rhs to its containing stmt. object equality in rhs.
    rhsToContainingStmt = new HashMap();

    HashMap> equivValToSiblingList = new HashMap>();

    // Create the set of all expressions, and a map from values to their containing expressions.
    for (Unit u : g.getBody().getUnits()) {
      Stmt s = (Stmt) u;

      if (s instanceof AssignStmt) {
        Value v = ((AssignStmt) s).getRightOp();
        rhsToContainingStmt.put(v, s);
        EquivalentValue ev = valueToEquivValue.get(v);
        if (ev == null) {
          ev = new EquivalentValue(v);
          valueToEquivValue.put(v, ev);
        }

        Chain sibList = null;
        if (equivValToSiblingList.get(ev) == null) {
          sibList = new HashChain();
          equivValToSiblingList.put(ev, sibList);
        } else {
          sibList = equivValToSiblingList.get(ev);
        }

        if (!sibList.contains(v)) {
          sibList.add(v);
        }

        if (!(v instanceof Expr)) {
          continue;
        }

        if (!exprs.contains(v)) {
          exprs.add(v);

          // Add map values for contained objects.
          for (ValueBox vb : v.getUseBoxes()) {
            Value o = vb.getValue();
            EquivalentValue eo = valueToEquivValue.get(o);
            if (eo == null) {
              eo = new EquivalentValue(o);
              valueToEquivValue.put(o, eo);
            }

            if (equivValToSiblingList.get(eo) == null) {
              sibList = new HashChain();
              equivValToSiblingList.put(eo, sibList);
            } else {
              sibList = equivValToSiblingList.get(eo);
            }
            if (!sibList.contains(o)) {
              sibList.add(o);
            }

            Chain l = null;
            if (containingExprs.containsKey(eo)) {
              l = containingExprs.get(eo);
            } else {
              l = new HashChain();
              containingExprs.put(eo, l);
            }

            if (!l.contains(ev)) {
              l.add(ev);
            }
          }
        }
      }
    }

    FlowUniverse exprUniv = new ArrayFlowUniverse(exprs.toArray(new Value[exprs.size()]));
    emptySet = new ArrayPackedSet(exprUniv);

    // Create preserve sets.
    {
      unitToPreserveSet = new HashMap>(g.size() * 2 + 1, 0.7f);

      for (Unit s : g) {
        BoundedFlowSet killSet = new ArrayPackedSet(exprUniv);

        // We need to do more! In particular handle invokeExprs, etc.

        // For each def (say of x), kill the set of exprs containing x.
        for (ValueBox box : s.getDefBoxes()) {
          Value v = box.getValue();
          EquivalentValue ev = valueToEquivValue.get(v);

          Chain c = containingExprs.get(ev);
          if (c != null) {
            for (EquivalentValue container : c) {
              // Add all siblings of it.next().
              for (Value sibVal : equivValToSiblingList.get(container)) {
                killSet.add(sibVal, killSet);
              }
            }
          }
        }

        // Store complement
        killSet.complement(killSet);
        unitToPreserveSet.put(s, killSet);
      }
    }

    // Create generate sets
    {
      unitToGenerateSet = new HashMap>(g.size() * 2 + 1, 0.7f);

      for (Unit s : g) {
        BoundedFlowSet genSet = new ArrayPackedSet(exprUniv);
        // In Jimple, expressions only occur as the RHS of an AssignStmt.
        if (s instanceof AssignStmt)

        {
          AssignStmt as = (AssignStmt) s;
          if (as.getRightOp() instanceof Expr) {
            // canonical rep of as.getRightOp();
            Value gen = as.getRightOp();

            boolean cantAdd = false;
            if (gen instanceof NewExpr || gen instanceof NewArrayExpr || gen instanceof NewMultiArrayExpr) {
              cantAdd = true;
            }
            if (gen instanceof InvokeExpr) {
              cantAdd = true;
            }

            // Whee, double negative!
            if (!cantAdd) {
              genSet.add(gen, genSet);
            }
          }
        }

        // remove the kill set
        genSet.intersection(unitToPreserveSet.get(s), genSet);

        unitToGenerateSet.put(s, genSet);
      }
    }

    doAnalysis();
  }

  protected FlowSet newInitialFlow() {
    BoundedFlowSet out = (BoundedFlowSet) emptySet.clone();
    out.complement(out);
    return out;
  }

  protected FlowSet entryInitialFlow() {
    return emptySet.clone();
  }

  protected void flowThrough(FlowSet in, Unit unit, FlowSet out) {
    // Perform kill
    in.intersection(unitToPreserveSet.get(unit), out);

    // Perform generation
    out.union(unitToGenerateSet.get(unit), out);
  }

  protected void merge(FlowSet inSet1, FlowSet inSet2, FlowSet outSet) {
    inSet1.intersection(inSet2, outSet);
  }

  protected void copy(FlowSet sourceSet, FlowSet destSet) {
    sourceSet.copy(destSet);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy