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

soot.jimple.toolkits.scalar.CopyPropagator 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) 1997 - 1999 Raja Vallee-Rai
 * %%
 * 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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

import soot.Body;
import soot.BodyTransformer;
import soot.G;
import soot.Local;
import soot.NullType;
import soot.RefLikeType;
import soot.Scene;
import soot.Singletons;
import soot.Timers;
import soot.Unit;
import soot.Value;
import soot.ValueBox;
import soot.jimple.AssignStmt;
import soot.jimple.CastExpr;
import soot.jimple.Constant;
import soot.jimple.DefinitionStmt;
import soot.jimple.IntConstant;
import soot.jimple.LongConstant;
import soot.jimple.NullConstant;
import soot.jimple.Stmt;
import soot.options.CPOptions;
import soot.options.Options;
import soot.tagkit.Host;
import soot.tagkit.LineNumberTag;
import soot.tagkit.SourceLnPosTag;
import soot.tagkit.Tag;
import soot.toolkits.exceptions.ThrowAnalysis;
import soot.toolkits.graph.ExceptionalUnitGraphFactory;
import soot.toolkits.graph.PseudoTopologicalOrderer;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.LocalDefs;

public class CopyPropagator extends BodyTransformer {
  private static final Logger logger = LoggerFactory.getLogger(CopyPropagator.class);

  protected ThrowAnalysis throwAnalysis = null;
  protected boolean forceOmitExceptingUnitEdges = false;

  public CopyPropagator(Singletons.Global g) {
  }

  public CopyPropagator(ThrowAnalysis ta) {
    this.throwAnalysis = ta;
  }

  public CopyPropagator(ThrowAnalysis ta, boolean forceOmitExceptingUnitEdges) {
    this.throwAnalysis = ta;
    this.forceOmitExceptingUnitEdges = forceOmitExceptingUnitEdges;
  }

  public static CopyPropagator v() {
    return G.v().soot_jimple_toolkits_scalar_CopyPropagator();
  }

  /**
   * Cascaded copy propagator.
   *
   * 

* If it encounters situations of the form: A: a = ...; B: ... x = a; C:... use (x); where a has only one definition, and x * has only one definition (B), then it can propagate immediately without checking between B and C for redefinitions of a * (namely) A because they cannot occur. In this case the propagator is global. * *

* Otherwise, if a has multiple definitions then it only checks for redefinitions of Propagates constants and copies in * extended basic blocks. * *

* Does not propagate stack locals when the "only-regular-locals" option is true. */ @Override protected void internalTransform(Body b, String phaseName, Map opts) { if (Options.v().verbose()) { logger.debug("[" + b.getMethod().getName() + "] Propagating copies..."); } if (Options.v().time()) { Timers.v().propagatorTimer.start(); } // Count number of definitions for each local. Map localToDefCount = new HashMap(b.getLocalCount() * 2 + 1); for (Unit u : b.getUnits()) { if (u instanceof DefinitionStmt) { Value leftOp = ((DefinitionStmt) u).getLeftOp(); if (leftOp instanceof Local) { Local loc = (Local) leftOp; Integer old = localToDefCount.get(loc); localToDefCount.put(loc, (old == null) ? 1 : (old + 1)); } } } if (throwAnalysis == null) { throwAnalysis = Scene.v().getDefaultThrowAnalysis(); } if (!forceOmitExceptingUnitEdges) { forceOmitExceptingUnitEdges = Options.v().omit_excepting_unit_edges(); } { // Go through the definitions, building the webs int fastCopyPropagationCount = 0; int slowCopyPropagationCount = 0; UnitGraph graph = ExceptionalUnitGraphFactory.createExceptionalUnitGraph(b, throwAnalysis, forceOmitExceptingUnitEdges); LocalDefs localDefs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(graph); CPOptions options = new CPOptions(opts); boolean onlyRegularLocals = options.only_regular_locals(); boolean onlyStackLocals = options.only_stack_locals(); boolean allLocals = onlyRegularLocals && onlyStackLocals; // Perform a local propagation pass. for (Unit u : (new PseudoTopologicalOrderer()).newList(graph, false)) { for (ValueBox useBox : u.getUseBoxes()) { Value value = useBox.getValue(); if (value instanceof Local) { Local l = (Local) value; // We force propagating nulls. If a target can only be // null due to typing, we always inline that constant. if (!allLocals && !(l.getType() instanceof NullType)) { if ((onlyRegularLocals && l.isStackLocal()) || (onlyStackLocals && !l.isStackLocal())) { continue; } } // We can propagate the definition if we either only have one definition // or all definitions are side-effect free and equal. For starters, we // only support constants in the case of multiple definitions. List defsOfUse = localDefs.getDefsOfAt(l, u); boolean propagateDef = defsOfUse.size() == 1; if (!propagateDef && defsOfUse.size() > 0) { boolean agrees = true; Constant constVal = null; for (Unit defUnit : defsOfUse) { boolean defAgrees = false; if (defUnit instanceof AssignStmt) { Value rightOp = ((AssignStmt) defUnit).getRightOp(); if (rightOp instanceof Constant) { if (constVal == null) { constVal = (Constant) rightOp; defAgrees = true; } else if (constVal.equals(rightOp)) { defAgrees = true; } } } agrees &= defAgrees; } propagateDef = agrees; } if (propagateDef) { final DefinitionStmt def = (DefinitionStmt) defsOfUse.get(0); final Value rightOp = def.getRightOp(); if (rightOp instanceof Constant) { if (useBox.canContainValue(rightOp)) { useBox.setValue(rightOp); copyLineTags(useBox, def); } } else if (rightOp instanceof CastExpr) { CastExpr ce = (CastExpr) rightOp; if (ce.getCastType() instanceof RefLikeType) { Value op = ce.getOp(); if ((op instanceof IntConstant && ((IntConstant) op).value == 0) || (op instanceof LongConstant && ((LongConstant) op).value == 0)) { if (useBox.canContainValue(NullConstant.v())) { useBox.setValue(NullConstant.v()); copyLineTags(useBox, def); } } } } else if (rightOp instanceof Local) { Local m = (Local) rightOp; if (l != m) { Integer defCount = localToDefCount.get(m); if (defCount == null || defCount == 0) { throw new RuntimeException("Variable " + m + " used without definition!"); } else if (defCount == 1) { useBox.setValue(m); copyLineTags(useBox, def); fastCopyPropagationCount++; continue; } List path = graph.getExtendedBasicBlockPathBetween(def, u); if (path == null) { // no path in the extended basic block continue; } { boolean isRedefined = false; Iterator pathIt = path.iterator(); // Skip first node pathIt.next(); // Make sure that m is not redefined along path while (pathIt.hasNext()) { Stmt s = (Stmt) pathIt.next(); if (u == s) { // Don't look at the last statement // since it is evaluated after the uses. break; } if (s instanceof DefinitionStmt) { if (((DefinitionStmt) s).getLeftOp() == m) { isRedefined = true; break; } } } if (isRedefined) { continue; } } useBox.setValue(m); slowCopyPropagationCount++; } } } } } } if (Options.v().verbose()) { logger.debug("[" + b.getMethod().getName() + "] Propagated: " + fastCopyPropagationCount + " fast copies " + slowCopyPropagationCount + " slow copies"); } } if (Options.v().time()) { Timers.v().propagatorTimer.end(); } } public static void copyLineTags(ValueBox useBox, DefinitionStmt def) { // we might have a def statement which contains a propagated constant itself as right-op. we // want to propagate the tags of this constant and not the def statement itself in this case. if (!copyLineTags(useBox, def.getRightOpBox())) { copyLineTags(useBox, (Host) def); } } /** * Copies the {@link SourceLnPosTag} and {@link LineNumberTag}s from the given host to the given ValueBox * * @param useBox * The box to which the position tags should be copied * @param host * The host from which the position tags should be copied * @return True if a copy was conducted, false otherwise */ private static boolean copyLineTags(ValueBox useBox, Host host) { boolean res = false; Tag tag = host.getTag(SourceLnPosTag.NAME); if (tag != null) { useBox.addTag(tag); res = true; } tag = host.getTag(LineNumberTag.NAME); if (tag != null) { useBox.addTag(tag); res = true; } return res; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy