/* Soot - a J*va Optimization Framework * Copyright (C) 2003 Navindra Umanee <navindra@cs.mcgill.ca> * * This library 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package soot.shimple; import soot.*; import soot.options.*; import soot.jimple.*; import soot.shimple.internal.*; import soot.util.*; import java.util.*; // * <p> We decided to hide all the intelligence in // * internal.ShimpleBodyBuilder for clarity of API. Eventually we will // * likely switch to an explicit Strategy pattern that will allow us to // * select different SSA behaviours and algorithms. /** * Implementation of the Body class for the SSA Shimple IR. * This class provides methods for maintaining SSA form as well as * eliminating SSA form. * * @author Navindra Umanee * @see soot.shimple.internal.ShimpleBodyBuilder * @see <a * href="http://citeseer.nj.nec.com/cytron91efficiently.html">Efficiently * Computing Static Single Assignment Form and the Control Dependence * Graph</a> **/ public class ShimpleBody extends StmtBody { /** * Holds our options map... **/ protected ShimpleOptions options; protected ShimpleBodyBuilder sbb; protected boolean isExtendedSSA = false; /** * Construct an empty ShimpleBody associated with m. **/ ShimpleBody(SootMethod m, Map options) { super(m); // must happen before SPatchingChain gets created this.options = new ShimpleOptions(options); setSSA(true); isExtendedSSA = this.options.extended(); unitChain = new SPatchingChain(this, new HashChain()); sbb = new ShimpleBodyBuilder(this); } /** * Constructs a ShimpleBody from the given Body and options. * * <p> Currently available option is "naive-phi-elimination", * typically in the "shimple" phase (eg, -p shimple * naive-phi-elimination) which can be useful for understanding * the effect of analyses. **/ ShimpleBody(Body body, Map options) { super(body.getMethod()); if (!(body instanceof JimpleBody || body instanceof ShimpleBody)) throw new RuntimeException("Cannot construct ShimpleBody from given Body type."); if(Options.v().verbose()) G.v().out.println("[" + getMethod().getName() + "] Constructing ShimpleBody..."); // must happen before SPatchingChain gets created this.options = new ShimpleOptions(options); unitChain = new SPatchingChain(this, new HashChain()); importBodyContentsFrom(body); /* Shimplise body */ sbb = new ShimpleBodyBuilder(this); if(body instanceof ShimpleBody) rebuild(true); else rebuild(false); } /** * Recompute SSA form. * * <p> Note: assumes presence of Phi nodes in body that require * elimination. If you *know* there are no Phi nodes present, * you may prefer to use rebuild(false) in order to skip some * transformations during the Phi elimination process. **/ public void rebuild() { rebuild(true); } /** * Rebuild SSA form. * * <p> If there are Phi nodes already present in the body, it is * imperative that we specify this so that the algorithm can * eliminate them before rebuilding SSA. * * <p> The eliminate Phi nodes stage is harmless, but if you * *know* that no Phi nodes are present and you wish to avoid the * transformations involved in eliminating Phi nodes, use * rebuild(false). **/ public void rebuild(boolean hasPhiNodes) { isExtendedSSA = options.extended(); sbb.transform(); setSSA(true); } /** * Returns an equivalent unbacked JimpleBody of the current Body * by eliminating the Phi nodes. * * <p> Currently available option is "naive-phi-elimination", * typically specified in the "shimple" phase (eg, -p shimple * naive-phi-elimination) which skips the dead code elimination * and register allocation phase before eliminating Phi nodes. * This can be useful for understanding the effect of analyses. * * <p> Remember to setActiveBody() if necessary in your * SootMethod. * * @see #eliminatePhiNodes() **/ public JimpleBody toJimpleBody() { ShimpleBody sBody = (ShimpleBody) this.clone(); sBody.eliminateNodes(); JimpleBody jBody = Jimple.v().newBody(sBody.getMethod()); jBody.importBodyContentsFrom(sBody); return jBody; } /** * Remove Phi nodes from body. SSA form is no longer a given * once done. * * <p> Currently available option is "naive-phi-elimination", * typically specified in the "shimple" phase (eg, -p shimple * naive-phi-elimination) which skips the dead code elimination * and register allocation phase before eliminating Phi nodes. * This can be useful for understanding the effect of analyses. * * @see #toJimpleBody() **/ public void eliminatePhiNodes() { sbb.preElimOpt(); sbb.eliminatePhiNodes(); sbb.postElimOpt(); setSSA(false); } public void eliminatePiNodes() { sbb.eliminatePiNodes(); } public void eliminateNodes() { sbb.preElimOpt(); sbb.eliminatePhiNodes(); if(isExtendedSSA) sbb.eliminatePiNodes(); sbb.postElimOpt(); setSSA(false); } /** * Returns a copy of the current ShimpleBody. **/ public Object clone() { Body b = Shimple.v().newBody(getMethod()); b.importBodyContentsFrom(this); return b; } /** * Set isSSA boolean to indicate whether a ShimpleBody is still in SSA * form or not. Could be useful for book-keeping purposes. **/ protected boolean isSSA = false; /** * Sets a flag that indicates whether ShimpleBody is still in SSA * form after a transformation or not. It is often up to the user * to indicate if a body is no longer in SSA form. **/ public void setSSA(boolean isSSA) { this.isSSA = isSSA; } /** * Returns value of, optional, user-maintained SSA boolean. * * @see #setSSA(boolean) **/ public boolean isSSA() { return isSSA; } public boolean isExtendedSSA() { return isExtendedSSA; } /** * Returns the Shimple options applicable to this body. **/ public ShimpleOptions getOptions() { return options; } /** * Make sure the locals in this body all have unique String names. * If the standard-local-names option is specified to Shimple, * this results in the LocalNameStandardizer being applied. * Otherwise, renaming is kept to a minimum and an underscore * notation is used to differentiate locals previously of the same * name. * * @see soot.jimple.toolkits.scalar.LocalNameStandardizer **/ public void makeUniqueLocalNames() { sbb.makeUniqueLocalNames(); } }