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

soot.toolkits.scalar.CombinedDUAnalysis Maven / Gradle / Ivy

package soot.toolkits.scalar;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.Local;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.options.Options;
import soot.toolkits.graph.UnitGraph;
import soot.util.Cons;
import soot.util.HashMultiMap;
import soot.util.MultiMap;

/**
 * Analysis that computes live locals, local defs, and local uses all at once.
 *
 * SA, 09.09.2014: Inefficient as hell (memory). Use the distinct analyses or fix this class before using it.
 */
public class CombinedDUAnalysis extends BackwardFlowAnalysis>
    implements CombinedAnalysis, LocalDefs, LocalUses, LiveLocals {
  private static final Logger logger = LoggerFactory.getLogger(CombinedDUAnalysis.class);
  // Implementations of our interfaces...
  private final Map, List> defsOfAt = new HashMap, List>();

  @Override
  public List getDefsOfAt(Local l, Unit s) {
    Cons cons = new Cons(l, s);
    List ret = defsOfAt.get(cons);
    if (ret == null) {
      defsOfAt.put(cons, ret = new ArrayList());
    }
    return ret;
  }

  @Override
  public List getDefsOf(Local l) {
    throw new RuntimeException("Not implemented");
  }

  private final Map> usesOf = new HashMap>();

  public List getUsesOf(Unit u) {
    List ret = usesOf.get(u);
    if (ret == null) {
      Local def = localDefed(u);
      if (def == null) {
        usesOf.put(u, ret = Collections.emptyList());
      } else {
        usesOf.put(u, ret = new ArrayList());
        for (ValueBox vb : getFlowAfter(u)) {
          if (vb.getValue() != def) {
            continue;
          }
          ret.add(new UnitValueBoxPair(useBoxToUnit.get(vb), vb));
        }
      }
    }
    return ret;
  }

  private final Map> liveLocalsBefore = new HashMap>();

  public List getLiveLocalsBefore(Unit u) {
    List ret = liveLocalsBefore.get(u);
    if (ret == null) {
      HashSet hs = new HashSet();
      for (ValueBox vb : getFlowBefore(u)) {
        hs.add((Local) vb.getValue());
      }
      liveLocalsBefore.put(u, ret = new ArrayList(hs));
    }
    return ret;
  }

  private final Map> liveLocalsAfter = new HashMap>();

  public List getLiveLocalsAfter(Unit u) {
    List ret = liveLocalsAfter.get(u);
    if (ret == null) {
      HashSet hs = new HashSet();
      for (ValueBox vb : getFlowAfter(u)) {
        hs.add((Local) vb.getValue());
      }
      liveLocalsAfter.put(u, ret = new ArrayList(hs));
    }
    return ret;
  }

  // The actual analysis is below.

  private final Map useBoxToUnit = new HashMap();
  private final Map unitToLocalDefed = new HashMap();

  private Local localDefed(Unit u) {
    return (Local) unitToLocalDefed.get(u);
  }

  private final Map> unitToLocalUseBoxes = new HashMap>();
  private final MultiMap localToUseBoxes = new HashMultiMap();

  public CombinedDUAnalysis(UnitGraph graph) {
    super(graph);
    if (Options.v().verbose()) {
      logger.debug("[" + graph.getBody().getMethod().getName() + "]     Constructing CombinedDUAnalysis...");
    }

    for (Unit u : graph) {
      List defs = localsInBoxes(u.getDefBoxes());
      if (defs.size() == 1) {
        unitToLocalDefed.put(u, defs.get(0));
      } else if (defs.size() != 0) {
        throw new RuntimeException("Locals defed in " + u + ": " + defs.size());
      }
      ArraySparseSet localUseBoxes = new ArraySparseSet();
      for (ValueBox vb : u.getUseBoxes()) {
        Value v = vb.getValue();
        if (!(v instanceof Local)) {
          continue;
        }
        localUseBoxes.add(vb);
        if (useBoxToUnit.containsKey(vb)) {
          throw new RuntimeException("Aliased ValueBox " + vb + " in Unit " + u);
        }
        useBoxToUnit.put(vb, u);
        localToUseBoxes.put(v, vb);
      }
      unitToLocalUseBoxes.put(u, localUseBoxes);
    }

    doAnalysis();

    for (Unit defUnit : graph) {
      Local localDefed = localDefed(defUnit);
      if (localDefed == null) {
        continue;
      }
      for (ValueBox vb : getFlowAfter(defUnit)) {
        if (vb.getValue() != localDefed) {
          continue;
        }
        Unit useUnit = useBoxToUnit.get(vb);
        getDefsOfAt(localDefed, useUnit).add(defUnit);
      }
    }
    if (Options.v().verbose()) {
      logger.debug("[" + graph.getBody().getMethod().getName() + "]     Finished CombinedDUAnalysis...");
    }

  }

  private List localsInBoxes(List boxes) {
    List ret = new ArrayList();
    for (ValueBox vb : boxes) {
      Value v = vb.getValue();
      if (!(v instanceof Local)) {
        continue;
      }
      ret.add(v);
    }
    return ret;
  }

  // STEP 1: What are we computing?
  // SETS OF USE BOXES CONTAINING LOCALS => Use HashSet.
  //
  // STEP 2: Precisely define what we are computing.
  // A use box B is live at program point P if there exists a path from P to the
  // unit using B on which the local in B is not defined.
  //
  // STEP 3: Decide whether it is a backwards or forwards analysis.
  // BACKWARDS
  //
  // STEP 4: Is the merge operator union or intersection?
  // UNION
  protected void merge(FlowSet inout, FlowSet in) {
    inout.union(in);
  }

  protected void merge(FlowSet in1, FlowSet in2, FlowSet out) {
    in1.union(in2, out);
  }

  // STEP 5: Define flow equations.
  // in(s) = ( out(s) minus boxes(def(s)) ) union useboxes(s)
  protected void flowThrough(FlowSet out, Unit u, FlowSet in) {
    Local def = localDefed(u);
    out.copy(in);
    if (def != null) {
      Collection boxesDefed = localToUseBoxes.get(def);
      for (ValueBox vb : in) {
        if (boxesDefed.contains(vb)) {
          in.remove(vb);
        }
      }
    }
    in.union(unitToLocalUseBoxes.get(u));
  }

  // STEP 6: Determine value for start/end node, and
  // initial approximation.
  //
  // end node: empty set
  // initial approximation: empty set
  protected FlowSet entryInitialFlow() {
    return new ArraySparseSet();
  }

  protected FlowSet newInitialFlow() {
    return new ArraySparseSet();
  }

  protected void copy(FlowSet source, FlowSet dest) {
    source.copy(dest);
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy