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

Java Open Source » Code Analyzer » soot 
soot » soot » shimple » internal » SPhiExpr.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 soot.shimple.*;
import soot.util.*;
import java.util.*;
import soot.toolkits.scalar.*;
import soot.toolkits.graph.*;

/**
 * Internal implementation of Phi nodes.
 *
 * @author Navindra Umanee
 * @see soot.shimple.PhiExpr
 **/
public class SPhiExpr implements PhiExpr
{
    protected List argPairs = new ArrayList();
    protected Map predToPair = new HashMap();  // cache
    protected Type type;
    
    /**
     * Create a trivial Phi expression for leftLocal.  preds is an ordered
     * list of the control flow predecessor Blocks of the PhiExpr.
     **/
    public SPhiExpr(Local leftLocal, List preds)
    {
        type = leftLocal.getType();

        Iterator predsIt = preds.iterator();
        while(predsIt.hasNext())
        {
            Object pred = predsIt.next();

            if(pred instanceof Block)
                addArg(leftLocal, (Block)pred);
            else if(pred instanceof Unit)
                addArg(leftLocal, (Unit)pred);
            else
                throw new RuntimeException("Must be a CFG block or tail unit.");
        }
    }

    /**
     * Create a Phi expression from the given list of Values and Blocks.
     **/
    public SPhiExpr(List<Value> args, List<Unit> preds)
    {
        if(args.size() == 0)
            throw new RuntimeException("Arg list may not be empty");
        
        if(args.size() != preds.size())
            throw new RuntimeException("Arg list does not match Pred list");

        type = args.get(0).getType();
        Iterator<Value> argsIt = args.iterator();
        Iterator<Unit> predsIt = preds.iterator();

        while(argsIt.hasNext()){
            Value arg = argsIt.next();
            Object pred = predsIt.next();

            if(pred instanceof Block)
                addArg(arg, (Block)pred);
            else if(pred instanceof Unit)
                addArg(arg, (Unit)pred);
            else
                throw new RuntimeException("Must be a CFG block or tail unit.");
        }
    }

    /* get-accessor implementations */
    
    public List getArgs()
    {
        return Collections.unmodifiableList(argPairs);
    }

    public List<Value> getValues()
    {
        List<Value> args = new ArrayList<Value>();
        Iterator argPairsIt = argPairs.iterator();

        while(argPairsIt.hasNext()){
            Value arg = ((ValueUnitPair)argPairsIt.next()).getValue();
            args.add(arg);
        }
        
        return args;
    }

    public List<Unit> getPreds()
    {
        List<Unit> preds = new ArrayList<Unit>();
        Iterator argPairsIt = argPairs.iterator();

        while(argPairsIt.hasNext()){
            Unit arg = ((ValueUnitPair)argPairsIt.next()).getUnit();
            preds.add(arg);
        }
        
        return preds;
    }

    public int getArgCount()
    {
        return argPairs.size();
    }

    public ValueUnitPair getArgBox(int index)
    {
        if(index < 0 || index >= argPairs.size())
            return null;
        return (ValueUnitPair) argPairs.get(index);
    }
    
    public Value getValue(int index)
    {
        ValueUnitPair arg = getArgBox(index);
        if(arg == null)
            return null;
        return arg.getValue();
    }

    public Unit getPred(int index)
    {
        ValueUnitPair arg = getArgBox(index);
        if(arg == null)
            return null;
        return arg.getUnit();
    }

    public int getArgIndex(Unit predTailUnit)
    {
        ValueUnitPair pair = getArgBox(predTailUnit);
        return argPairs.indexOf(pair); // (-1 on null)
    }

    public ValueUnitPair getArgBox(Unit predTailUnit)
    {
        ValueUnitPair vup = (ValueUnitPair) predToPair.get(predTailUnit);

        // we pay a penalty for misses but hopefully the common case
        // is faster than an iteration over argPairs every time
        if(vup == null || vup.getUnit() != predTailUnit){
            updateCache();
            vup = (ValueUnitPair) predToPair.get(predTailUnit);
            if((vup != null) && (vup.getUnit() != predTailUnit))
                throw new RuntimeException("Assertion failed.");
        }

        // (null if not found)
        return vup;
    }
    
    public Value getValue(Unit predTailUnit)
    {
        ValueBox vb = getArgBox(predTailUnit);
        if(vb == null)
            return null;
        return vb.getValue();
    }

    public int getArgIndex(Block pred)
    {
        ValueUnitPair box = getArgBox(pred);
        return argPairs.indexOf(box); // (-1 on null)
    }

    public ValueUnitPair getArgBox(Block pred)
    {
        Unit predTailUnit = pred.getTail();
        ValueUnitPair box = getArgBox(predTailUnit);

        // workaround added for internal cases where the predTailUnit
        // may not be at the end of the predecessor block
        // (eg, fall-through pointer not moved)
        while(box == null){
            predTailUnit = pred.getPredOf(predTailUnit);
            if(predTailUnit == null)
                break;
            box = getArgBox(predTailUnit);
        }

        return box;
    }

    public Value getValue(Block pred)
    {
        ValueBox vb = getArgBox(pred);
        if(vb == null)
            return null;
        return vb.getValue();
    }

    /* set-accessor implementations */
    
    public boolean setArg(int index, Value arg, Unit predTailUnit)
    {
        boolean ret1 = setValue(index, arg);
        boolean ret2 = setPred(index, predTailUnit);
        if(ret1 != ret2)
            throw new RuntimeException("Assertion failed.");
        return ret1;
    }
    
    public boolean setArg(int index, Value arg, Block pred)
    {
        return setArg(index, arg, pred.getTail());
    }
    
    public boolean setValue(int index, Value arg)
    {
        ValueUnitPair argPair = getArgBox(index);
        if(argPair == null)
            return false;
        argPair.setValue(arg);
        return true;
    }

    public boolean setValue(Unit predTailUnit, Value arg)
    {
        int index = getArgIndex(predTailUnit);
        return setValue(index, arg);
    }

    public boolean setValue(Block pred, Value arg)
    {
        int index = getArgIndex(pred);
        return setValue(index, arg);
    }

    public boolean setPred(int index, Unit predTailUnit)
    {
        ValueUnitPair argPair = getArgBox(index);
        if(argPair == null)
            return false;

        int other = getArgIndex(predTailUnit);
        if(other != -1){
            G.v().out.println("WARNING: An argument with control flow predecessor " +  predTailUnit + " already exists in " + this + "!");
            G.v().out.println("WARNING: setPred resulted in deletion of " + argPair + " from " + this + ".");
            removeArg(argPair);
            return false;
        }

        argPair.setUnit(predTailUnit);
        return true;
    }

    public boolean setPred(int index, Block pred)
    {
        return setPred(index, pred.getTail());
    }
    
    /* add/remove implementations */
    
    public boolean removeArg(int index)
    {
        ValueUnitPair arg = getArgBox(index);
        return removeArg(arg);
    }

    public boolean removeArg(Unit predTailUnit)
    {
        ValueUnitPair arg = getArgBox(predTailUnit);
        return removeArg(arg);
    }

    public boolean removeArg(Block pred)
    {
        ValueUnitPair arg = getArgBox(pred);
        return removeArg(arg);
    }
    
    public boolean removeArg(ValueUnitPair arg)
    {
        if(argPairs.remove(arg)){
            // update cache
            predToPair.remove(arg.getUnit());
            // remove back-pointer
            arg.getUnit().removeBoxPointingToThis(arg);
            return true;
        }
        
        return false;
    }

    public boolean addArg(Value arg, Block pred)
    {
        return addArg(arg, pred.getTail());
    }
    
    public boolean addArg(Value arg, Unit predTailUnit)
    {
        // we have no choice but to flush the cache
        updateCache();

        // we disallow duplicate arguments
        if(predToPair.keySet().contains(predTailUnit))
            return false;

        ValueUnitPair vup = new SValueUnitPair(arg, predTailUnit);

        // add and update cache
        argPairs.add(vup);
        predToPair.put(predTailUnit, vup);
        return true;
    }

    int blockId = -1;

    public void setBlockId(int blockId)
    {
        this.blockId = blockId;
    }

    public int getBlockId()
    {
        if(blockId == -1)
            throw new RuntimeException("Assertion failed:  Block Id unknown.");
        return blockId;
    }
    
    /* misc */

    /**
     * Update predToPair cache map which could be out-of-sync due to
     * external setUnit or clone operations on the UnitBoxes.
     **/
    protected void updateCache()
    {
        predToPair = new HashMap();
        Iterator pairsIt = argPairs.iterator();
        while(pairsIt.hasNext()){
            ValueUnitPair vup = (ValueUnitPair) pairsIt.next();
            predToPair.put(vup.getUnit(), vup);
        }
    }

    public boolean equivTo(Object o)
    {
        if(o instanceof SPhiExpr){
            SPhiExpr pe = (SPhiExpr) o;

            if(getArgCount() != pe.getArgCount())
                return false;

            for(int i = 0; i < getArgCount(); i++){
                if(!getArgBox(i).equivTo(pe.getArgBox(i)))
                    return false;
            }

            return true;
        }

        return false;
    }

    public int equivHashCode()
    {
        int hashcode = 1;
        
        for(int i = 0; i < getArgCount(); i++){
            hashcode = hashcode * 17 + getArgBox(i).equivHashCode();
        }

        return hashcode;
    }

    public List getUnitBoxes()
    {
        return argPairs;
    }

    public void clearUnitBoxes()
    {
        Iterator boxesIt = getUnitBoxes().iterator();
        while(boxesIt.hasNext()){
            UnitBox box = (UnitBox) boxesIt.next();
            box.setUnit(null);
        }
    }
    
    public List getUseBoxes()
    {
        Set set = new HashSet();

        Iterator argPairsIt = argPairs.iterator();

        while(argPairsIt.hasNext()){
            ValueUnitPair argPair = (ValueUnitPair) argPairsIt.next();
            set.addAll(argPair.getValue().getUseBoxes());
            set.add(argPair);
        }

        return new ArrayList(set);
    }

    public Type getType()
    {
        return type;
    }

    public String toString()
    {
        StringBuffer expr = new StringBuffer(Shimple.PHI + "(");
        Iterator argPairsIt = argPairs.iterator();

        while(argPairsIt.hasNext()){
            ValueUnitPair vuPair = (ValueUnitPair)argPairsIt.next();
            Value arg = vuPair.getValue();
            expr.append(arg.toString());

            if(argPairsIt.hasNext())
                expr.append(", ");
        }

        expr.append(")");

        return expr.toString();
    }
    
    public void toString(UnitPrinter up)
    {
        up.literal(Shimple.PHI);
        up.literal("(");

        Iterator argPairsIt = argPairs.iterator();
        while(argPairsIt.hasNext()){
            ValueUnitPair vuPair = (ValueUnitPair)argPairsIt.next();
            vuPair.toString(up);

            if(argPairsIt.hasNext())
                up.literal(", ");
        }

        up.literal(")");
    }
        
    public void apply(Switch sw)
    {
        ((ShimpleExprSwitch) sw).casePhiExpr(this);
    }

    public Object clone()
    {
        // Note to self: Do not try to "fix" this *again*.  Yes, it
        // should be a shallow copy in order to conform with the rest
        // of Soot.  When a body is cloned, the Values are cloned
        // explicitly and replaced, and UnitBoxes are explicitly
        // patched.  See Body.importBodyContentsFrom for details.
        return new SPhiExpr(getValues(), getPreds());
    }
}
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.