ShimpleBodyBuilder.java :  » Code-Analyzer » soot » soot » shimple » internal » Java Open Source

Java Open Source » Code Analyzer » soot 
soot » soot » shimple » internal » ShimpleBodyBuilder.java
/* 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.internal;

import soot.*;
import java.util.*;
import soot.shimple.*;
import soot.options.*;
import soot.jimple.*;
import soot.jimple.internal.*;
import soot.jimple.toolkits.base.*;
import soot.jimple.toolkits.scalar.*;
import soot.toolkits.graph.*;
import soot.toolkits.scalar.*;

/**
 * This class does the real high-level work.  It takes a Jimple body
 * or Jimple/Shimple hybrid body and produces pure Shimple.
 *
 * <p> The work is done in two main steps:
 *
 * <ol>
 * <li> Trivial Phi nodes are added.
 * <li> A renaming algorithm is executed.
 * </ol>
 *
 * <p> This class can also translate out of Shimple by producing an
 * equivalent Jimple body with all Phi nodes removed.
 *
 * <p> Note that this is an internal class, understanding it should
 * not be necessary from a user point-of-view and relying on it
 * directly is not recommended.
 *
 * @author Navindra Umanee
 * @see soot.shimple.ShimpleBody
 * @see <a
 * href="http://citeseer.nj.nec.com/cytron91efficiently.html">Efficiently
 * Computing Static Single Assignment Form and the Control Dependence
 * Graph</a>
 **/
public class ShimpleBodyBuilder
{
    protected ShimpleBody body;
    protected ShimpleFactory sf;
    protected DominatorTree dt;
    protected BlockGraph cfg;
    
    /**
     * A fixed list of all original Locals.
     **/
    protected List<Local> origLocals;

    public PhiNodeManager phi;
    public PiNodeManager pi;

    ShimpleOptions options;
    
    /**
     * Transforms the provided body to pure SSA form.
     **/
    public ShimpleBodyBuilder(ShimpleBody body)
    {
        this.body = body;
        sf = G.v().shimpleFactory;
        sf.setBody(body);
        sf.clearCache();
        phi = new PhiNodeManager(body);
        pi = new PiNodeManager(body, false);
        options = body.getOptions();
        makeUniqueLocalNames();
    }
    
    public void update()
    {
        cfg = sf.getBlockGraph();
        dt = sf.getDominatorTree();
        origLocals = new ArrayList<Local>(body.getLocals());
    }

    public void transform()
    {
        phi.insertTrivialPhiNodes();

        boolean change = false;
        if(options.extended()){
            change = pi.insertTrivialPiNodes();
        
            while(change){
                if(phi.insertTrivialPhiNodes()){
                    change = pi.insertTrivialPiNodes();
                }
                else{
                    break;
                }
            }
        }

        renameLocals();
        phi.trimExceptionalPhiNodes();
        makeUniqueLocalNames();
    }

    public void preElimOpt()
    {
        boolean optElim = options.node_elim_opt();

        // *** FIXME: 89e9a0470601091906j26489960j65290849dbe0481f@mail.gmail.com
        //if(optElim)
        //DeadAssignmentEliminator.v().transform(body);
    }

    public void postElimOpt()
    {
        boolean optElim = options.node_elim_opt();
        
        if(optElim){
            DeadAssignmentEliminator.v().transform(body);
            UnreachableCodeEliminator.v().transform(body);
            UnconditionalBranchFolder.v().transform(body);
            Aggregator.v().transform(body);
            UnusedLocalEliminator.v().transform(body);
        }
    }
    
    /**
     * Remove Phi nodes from current body, high probablity this
     * destroys SSA form.
     *
     * <p> Dead code elimination + register aggregation are performed
     * as recommended by Cytron.  The Aggregator looks like it could
     * use some improvements.
     *
     * @see soot.options.ShimpleOptions
     **/
    public void eliminatePhiNodes()
    {
        if(phi.doEliminatePhiNodes())
            makeUniqueLocalNames();

    }

    public void eliminatePiNodes()
    {
        boolean optElim = options.node_elim_opt();
        pi.eliminatePiNodes(optElim);
    }
    
    /**
     * Maps new name Strings to Locals.
     **/
    protected Map<String, Local> newLocals;

    /**
     * Maps renamed Locals to original Locals.
     **/
    protected Map<Local,Local> newLocalsToOldLocal;

    protected int[] assignmentCounters;
    protected Stack[] namingStacks;
    
    /**
     * Variable Renaming Algorithm from Cytron et al 91, P26-8,
     * implemented in various bits and pieces by the next functions.
     * Must be called after trivial nodes have been added.
     **/
    public void renameLocals()
    {
        update();
        newLocals = new HashMap<String, Local>();
        newLocalsToOldLocal = new HashMap<Local, Local>();

        assignmentCounters = new int[origLocals.size()];
        namingStacks = new Stack[origLocals.size()];

        for(int i = 0; i < namingStacks.length; i++)
            namingStacks[i] = new Stack();

        List heads = cfg.getHeads();

        if(heads.size() == 0)
            return;

        if(heads.size() != 1)
            throw new RuntimeException("Assertion failed:  Only one head expected.");
        
        Block entry = (Block) heads.get(0);
        renameLocalsSearch(entry);
    }

    /**
     * Driven by renameLocals().
     **/
    public void renameLocalsSearch(Block block)
    {
        // accumulated in Step 1 to be re-processed in Step 4
        List<Local> lhsLocals = new ArrayList<Local>();
        
        // Step 1 of 4 -- Rename block's uses (ordinary) and defs
        {
            // accumulated and re-processed in a later loop
            Iterator unitsIt = block.iterator();

            while(unitsIt.hasNext()){
                Unit unit = (Unit) unitsIt.next();

                // Step 1/2 of 1
                {
                    List useBoxes = new ArrayList();

                    if(!Shimple.isPhiNode(unit))
                        useBoxes.addAll(unit.getUseBoxes());

                    Iterator useBoxesIt = useBoxes.iterator();
                
                    while(useBoxesIt.hasNext()){
                        ValueBox useBox = (ValueBox) useBoxesIt.next();
                        Value use = useBox.getValue();

                        int localIndex = indexOfLocal(use);

                        // not one of our locals
                        if(localIndex == -1)
                            continue;

                        Local localUse = (Local) use;

                        if(namingStacks[localIndex].empty())
                            continue;

                        Integer subscript = (Integer) namingStacks[localIndex].peek();

                        Local renamedLocal = fetchNewLocal(localUse, subscript);
                        useBox.setValue(renamedLocal);
                    }
                }

                // Step 1 of 1
                {
                    if(!(unit instanceof DefinitionStmt))
                        continue;
                
                    DefinitionStmt defStmt = (DefinitionStmt) unit;
                    
                    Value lhsValue = defStmt.getLeftOp();
                    
                    // not something we're interested in
                    if(!origLocals.contains(lhsValue))
                        continue;

                    ValueBox lhsLocalBox = defStmt.getLeftOpBox();
                    Local lhsLocal = (Local) lhsValue;

                    // re-processed in Step 4
                    lhsLocals.add(lhsLocal);

                    int localIndex = indexOfLocal(lhsLocal);
                    if(localIndex == -1)
                        throw new RuntimeException("Assertion failed.");
                
                    Integer subscript = new Integer(assignmentCounters[localIndex]);

                    Local newLhsLocal = fetchNewLocal(lhsLocal, subscript);
                    lhsLocalBox.setValue(newLhsLocal);

                    namingStacks[localIndex].push(subscript);
                    assignmentCounters[localIndex]++;                    
                    
                }
            }
        }

        // Step 2 of 4 -- Rename Phi node uses in Successors
        {
            Iterator succsIt = cfg.getSuccsOf(block).iterator();

            while(succsIt.hasNext()){
                Block succ = (Block) succsIt.next();

                Iterator unitsIt = succ.iterator();

                while(unitsIt.hasNext()){
                    Unit unit = (Unit) unitsIt.next();

                    PhiExpr phiExpr = Shimple.getPhiExpr(unit);

                    if(phiExpr == null)
                        continue;

                    // simulate whichPred
                    int argIndex = phiExpr.getArgIndex(block);
                    if(argIndex == -1)
                        throw new RuntimeException("Assertion failed.");
                        
                    ValueBox phiArgBox = phiExpr.getArgBox(argIndex);

                    Local phiArg = (Local) phiArgBox.getValue();
                    
                    int localIndex = indexOfLocal(phiArg);
                    if(localIndex == -1)
                        throw new RuntimeException("Assertion failed.");
                    
                    if(namingStacks[localIndex].empty())
                        continue;

                    Integer subscript = (Integer) namingStacks[localIndex].peek();
                    
                    Local newPhiArg = fetchNewLocal(phiArg, subscript);
                    phiArgBox.setValue(newPhiArg);
                }
            }
        }

        // Step 3 of 4 -- Recurse over children.
        {
            DominatorNode node = dt.getDode(block);

            // now we recurse over children

            Iterator childrenIt = dt.getChildrenOf(node).iterator();

            while(childrenIt.hasNext()){
                DominatorNode childNode = (DominatorNode) childrenIt.next();

                renameLocalsSearch((Block) childNode.getGode());
            }
        }

        // Step 4 of 4 -- Tricky name stack updates.
        {
            Iterator<Local> lhsLocalsIt = lhsLocals.iterator();

            while(lhsLocalsIt.hasNext()){
                Local lhsLocal = lhsLocalsIt.next();

                int lhsLocalIndex = indexOfLocal(lhsLocal);
                if(lhsLocalIndex == -1)
                    throw new RuntimeException("Assertion failed.");
                
                namingStacks[lhsLocalIndex].pop();
            }
        }

        /* And we're done.  The renaming process is complete. */
    }

    /**
     * Clever convenience function to fetch or create new Local's
     * given a Local and the desired subscript.
     **/
    protected Local fetchNewLocal(Local local, Integer subscript)
    {
        Local oldLocal = local;
        
        if(!origLocals.contains(local))
            oldLocal = newLocalsToOldLocal.get(local);
        
        if(subscript.intValue() == 0)
            return oldLocal;

        // If the name already exists, makeUniqueLocalNames() will
        // take care of it.
        String name = oldLocal.getName() + "_" + subscript;

        Local newLocal = newLocals.get(name);

        if(newLocal == null){
            newLocal = new JimpleLocal(name, oldLocal.getType());
            newLocals.put(name, newLocal);
            newLocalsToOldLocal.put(newLocal, oldLocal);

            // add proper Local declation
            body.getLocals().add(newLocal);
        }

        return newLocal;
    }

    /**
     * Convenient function that maps new Locals to the originating
     * Local, and finds the appropriate array index into the naming
     * structures.
     **/
    protected int indexOfLocal(Value local)
    {
        int localIndex = origLocals.indexOf(local);

        if(localIndex == -1){
            // might be null
            Local oldLocal = newLocalsToOldLocal.get(local);

            localIndex = origLocals.indexOf(oldLocal);
        }
        
        return localIndex;
    }

    /**
     * Make sure the locals in the given body all have unique String
     * names.  Renaming is done if necessary.
     **/
    public void makeUniqueLocalNames()
    {
        if(options.standard_local_names()){
            LocalNameStandardizer.v().transform(body);
            return;
        }

        Set<String> localNames = new HashSet<String>();
        Iterator localsIt = body.getLocals().iterator();

        while(localsIt.hasNext()){
            Local local = (Local) localsIt.next();
            String localName = local.getName();
            
            if(localNames.contains(localName)){
                String uniqueName = makeUniqueLocalName(localName, localNames);
                local.setName(uniqueName);
                localNames.add(uniqueName);
            }
            else
                localNames.add(localName);
        }
    }

    /**
     * Given a set of Strings, return a new name for dupName that is
     * not currently in the set.
     **/
    public String makeUniqueLocalName(String dupName, Set<String> localNames)
    {
        int counter = 1;
        String newName = dupName;

        while(localNames.contains(newName))
            newName = dupName + "_" + counter++;

        return newName;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.