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

soot.jimple.toolkits.annotation.nullcheck.BranchedRefVarsAnalysis Maven / Gradle / Ivy

There is a newer version: 1.12.0
Show newest version
/* BranchedRefVarsAnalysis
 * Copyright (C) 2000 Patrick Lam, Janus
 *
 * 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.jimple.toolkits.annotation.nullcheck;

import soot.*;
import soot.jimple.*;
import soot.toolkits.graph.*;
import soot.toolkits.scalar.*;
import java.util.*;


/*
     README FIRST - IMPORTANT IMPLEMENTATION NOTE

     As per the analysis presented in the report, there are four possible 
     pairs for given reference r:
     (r, kBottom)
     (r, kNonNull)
     (r, kNull)
     (r, kTop)

     To save space an simplify operations, we implemented those 4 values 
     with two bits rather than four, namely:

     (r, kTop) in a set is represented by having (r, kNull) and (r, kNonNull) 
     in the set. Ditto, (r, kBottom) is represented by having neither in the set.
    
     Keep this in mind as you read the code, it helps. Honnest :)

     -- Janus

 */


/*
      BranchedRefVarsAnalysis class

      Perform the analysis presented in the report.

      
      KNOWN LIMITATION: there is a problem in the ForwardBranchedFlowAnalysis
      or maybe the CompleteUnitGraph that prevent the analysis
      (at the ForwardBranchedFlowAnalysis level) to handle properly traps.
      We make the analysis conservative in case of exceptions by setting
      exceptions handler statements In to TOP.
      

 */


/**
 * @deprecated THIS IS KNOWN TO BE BUGGY. USE {@link NullnessAnalysis} INSTEAD!
 */
public class BranchedRefVarsAnalysis  extends ForwardBranchedFlowAnalysis
{
    /*
        COMPILATION OPTIONS
    */

    // we don't want the analysis to be conservative?
    // i.e. we don't want it to only care for locals
    private final  boolean isNotConservative = false;
    
    // do we want the analysis to handle if statements?
    private final  boolean isBranched = true;
    
    // do we want the analysis to care that f and g 
    // could be the same reference?
    private final  boolean careForAliases = false;
    
    // do we want the analysis to care that a method 
    // call could have side effects?
    private final  boolean careForMethodCalls = true;

    // **** END OF COMPILATION OPTIONS *****

/*
    {
        if (true) {
            G.v().out.println();
            G.v().out.println();
            G.v().out.println("BranchedRefVarsAnalysis:");
            G.v().out.println("     isNotConservative = "+isNotConservative);
            G.v().out.println("            isBranched = "+isBranched);
            G.v().out.println("        careForAliases = "+careForAliases);
            G.v().out.println("    careForMethodCalls = "+careForMethodCalls);
        }
    } // end 
*/

    // constants for the analysis
    public final static int kBottom = 0;
    public final static int kNull = 1;
    public final static int kNonNull = 2;
    public final static int kTop = 99;


    // bottom and top sets
    protected FlowSet emptySet;
    protected FlowSet fullSet;


    // gen and preserve sets (for each statement)
    protected Map unitToGenerateSet;
    protected Map unitToPreserveSet;

    
    // sets of variables that need a null pointer check (for each statement)
    protected Map> unitToAnalyzedChecksSet;
    protected Map> unitToArrayRefChecksSet;
    protected Map> unitToInstanceFieldRefChecksSet;
    protected Map> unitToInstanceInvokeExprChecksSet;
    protected Map> unitToLengthExprChecksSet;


    // keep track of the different kinds of reference types this analysis is working on
    protected List refTypeLocals;
    protected List refTypeInstFields;
    protected List refTypeInstFieldBases;
    protected List refTypeStaticFields;
    protected List refTypeValues; // sum of all the above


    // used in flowThrough.
    protected FlowSet tempFlowSet = null;

    // fast conversion from Value -> EquivalentValue
    //  because used in  methods
    private final  HashMap valueToEquivValue = new HashMap(2293, 0.7f);

    public  EquivalentValue getEquivalentValue(Value v)
    {
        if (valueToEquivValue.containsKey(v))
            return valueToEquivValue.get(v);
        else {
            EquivalentValue ev = new EquivalentValue(v);
            valueToEquivValue.put(v, ev);
            return ev;
        }
    } // end getEquivalentValue
    
    // constant (r, v) pairs
    //  because used in  methods
    private final  HashMap kRefBotttomPairs = new HashMap(2293, 0.7f);
    private final  HashMap kRefNonNullPairs = new HashMap(2293, 0.7f);
    private final  HashMap kRefNullPairs = new HashMap(2293, 0.7f);
    private final  HashMap kRefTopPairs = new HashMap(2293, 0.7f);

    // make that (r, v) pairs are constants
    // i.e. the same r and v values always generate the same (r, v) object    
    public  RefIntPair getKRefIntPair(EquivalentValue r, int v)
    {
        HashMap pairsMap = null;

        if (v == kNonNull)
            pairsMap =  kRefNonNullPairs;
        else if (v == kNull)
            pairsMap = kRefNullPairs;
        else if (v == kTop)
            pairsMap = kRefTopPairs;
        else if (v == kBottom)
            pairsMap = kRefBotttomPairs;
        else
            throw new RuntimeException("invalid constant ("+v+")");
        
        if (pairsMap.containsKey(r))
            return pairsMap.get(r);
        else {
            RefIntPair pair = new RefIntPair(r, v, this);
            pairsMap.put(r, pair);
            return pair;
        }
    } // end getKRefIntPair

    /*
        Utility methods.

        They are used all over the place. Most of them are declared 
        "private  final" so they can be inlined with javac -O.

     */


    // isAlwaysNull returns true if the reference r is known to be always null
    private  final boolean isAlwaysNull(Value r)
    {
        return ((r instanceof NullConstant) || 
                (r.getType() instanceof NullType));
    } // end isAlwaysNull


    // isAlwaysTop returns true if the reference r is known to be always top for this analysis
    // i.e. its value is undecidable by this analysis
    private  final boolean isAlwaysTop(Value r)
    {
        if (isNotConservative)
            return false;
        else
            return r instanceof InstanceFieldRef || r instanceof StaticFieldRef;
    } // end isAlwaysTop

    protected boolean isAlwaysNonNull(Value ro) {
        if( ro instanceof NewExpr ) return true;
        if( ro instanceof NewArrayExpr ) return true;
        if( ro instanceof NewMultiArrayExpr ) return true;
        if( ro instanceof ThisRef ) return true;
        if( ro instanceof CaughtExceptionRef ) return true;
        if( ro instanceof StringConstant ) return true;
        return false;
    }



    // isAnalyzedRef returns true if the reference r is to be analyzed by this analysis
    // i.e. its value is not always known (or undecidable)
    private  final boolean isAnalyzedRef(Value r)
    {
        if (isAlwaysNull(r) || isAlwaysTop(r)) 
            return false;
        else if (r instanceof Local ||
                 r instanceof InstanceFieldRef ||
                 r instanceof StaticFieldRef) {
            Type rType = r.getType();
            
            return (rType instanceof RefType || rType instanceof ArrayType);
        } else
            return false;
    } // end isAnalyzedRef

    // refInfo is a helper method to tranform our two bit representation back to the four constants
    // For a given reference and a flow set, tell us if r is bottom, top, null or non-null
    // Note: this method will fail if r is not in the flow set
    protected  final int refInfo(EquivalentValue r, FlowSet fs)
    {
        boolean isNull = fs.contains(getKRefIntPair(r, kNull));
        boolean isNonNull = fs.contains(getKRefIntPair(r, kNonNull));
        
        if (isNull && isNonNull)
            return kTop;
        else if (isNull)
            return kNull;
        else if (isNonNull)
            return kNonNull;
        else
            return kBottom;
    } // end refInfo

    protected  final int refInfo(Value r, FlowSet fs)
    {
        return refInfo(getEquivalentValue(r), fs);
    } // end refInfo
    
    // Like refInfo, but the reference doesn't have to be in the flow set
    // note: it still need to be a reference, i.e. ArrayType or RefType
    public int anyRefInfo(Value r, FlowSet f)
    {
        if (isAlwaysNull(r))
            return kNull;
        else if (isAlwaysTop(r))
            return kTop;
        else if( isAlwaysNonNull(r) )
            return kNonNull;
        else
            return refInfo(r, f);
    } // end anyRefInfo
    

    /*
       methods: uAddTopToFlowSet
                uAddInfoToFlowSet
                uListAddTopToFlowSet

       Adding a pair (r, v) to a set is always a two steps process:
       a) remove all pairs (r, *)
       b) add the pair (r, v)
       
       The methods above handle that.

       Most of them come in two flavors: to act on one set or two act on separate
       generate and preserve sets.

    */

    // method to add (r, kTop) to the gen set (and remove it from the pre set)
    private  final void uAddTopToFlowSet(EquivalentValue r, FlowSet genFS, FlowSet preFS)
    {
        RefIntPair nullPair = getKRefIntPair(r, kNull);
        RefIntPair nullNonPair = getKRefIntPair(r, kNonNull);
        
        if (genFS != preFS) {
            preFS.remove(nullPair, preFS);
            preFS.remove(nullNonPair, preFS);
        }
        
        genFS.add(nullPair, genFS);
        genFS.add(nullNonPair, genFS);
    } // end uAddTopToFlowSet
    
    private  final void uAddTopToFlowSet(Value r, FlowSet genFS, FlowSet preFS)
    {
        uAddTopToFlowSet(getEquivalentValue(r), genFS, preFS);
    } // end uAddTopToFlowSet

    // method to add (r, kTop) to a set
    private  final void uAddTopToFlowSet(Value r, FlowSet fs)
    {
        uAddTopToFlowSet(getEquivalentValue(r), fs, fs);
    } // end uAddTopToFlowSet
    
    // method to add (r, kTop) to a set
    private  final void uAddTopToFlowSet(EquivalentValue r, FlowSet fs)
    {
        uAddTopToFlowSet(r, fs, fs);
    } // end uAddTopToFlowSet

    // method to add (r, kNonNull) or (r, kNull) to the gen set (and remove it from the pre set)
    private  final void uAddInfoToFlowSet(EquivalentValue r, int v, FlowSet genFS, FlowSet preFS)
    {
        int kill;
        if (v == kNull)
            kill = kNonNull;
        else if (v == kNonNull)
            kill = kNull;
        else
            throw new RuntimeException("invalid info");
        
        if (genFS != preFS) {
            preFS.remove(getKRefIntPair(r, kill), preFS);
        }
        
        genFS.remove(getKRefIntPair(r, kill), genFS);
        genFS.add(getKRefIntPair(r, v), genFS);
    } // end uAddInfoToFlowSet

    private  final void uAddInfoToFlowSet(Value r, int v, FlowSet genF, FlowSet preF)
    {
        uAddInfoToFlowSet(getEquivalentValue(r), v, genF, preF);
    } // end uAddInfoToFlowSet

    // method to add (r, kNonNull) or (r, kNull) to a set
    private  final void uAddInfoToFlowSet(Value r, int v, FlowSet fs)
    {
        uAddInfoToFlowSet(getEquivalentValue(r), v, fs, fs);
    } // end uAddInfoToFlowSet

    // method to add (r, kNonNull) or (r, kNull) to a set
    private  final void uAddInfoToFlowSet(EquivalentValue r, int v, FlowSet fs)
    {
        uAddInfoToFlowSet(r, v, fs, fs);
    } // end uAddInfoToFlowSet


    // method to apply uAddTopToFlowSet to a whole list of references
    private  final void uListAddTopToFlowSet(List refs, FlowSet genFS, FlowSet preFS)
    {
        Iterator it = refs.iterator();

        while (it.hasNext()) {
            uAddTopToFlowSet(it.next(), genFS, preFS);
        }
    } // end uListAddTopToFlowSet


    /********** end of utility methods *********/


    // here come the method that start it all, the constructor
    // initialize the object and run the analysis
    /**
     * @deprecated THIS IS KNOWN TO BE BUGGY. USE {@link NullnessAnalysis} INSTEAD!
     */
    public BranchedRefVarsAnalysis (UnitGraph g)
    {
        super(g);

        // initialize all the refType lists
        initRefTypeLists();
        
        // initialize emptySet, fullSet and tempFlowSet
        initUniverseSets();
        
        // initialize unitTo...Sets
        // perform  preservation and generation
        initUnitSets();
        
        doAnalysis();
    } // end constructor


    // method to initialize refTypeLocals, refTypeInstFields, refTypeInstFieldBases
    // refTypeStaticFields, and refTypeValues
    // those lists contains fields that can/need to be analyzed
    private void initRefTypeLists()
    {
        refTypeLocals = new ArrayList();
        refTypeInstFields = new ArrayList();
        refTypeInstFieldBases = new ArrayList();
        refTypeStaticFields = new ArrayList();
        refTypeValues = new ArrayList();

        // build list of locals
        Iterator it = ((UnitGraph)graph).getBody().getLocals().iterator();
        
        while (it.hasNext()) {
            Local l = (Local) (it.next());
            
            if (l.getType() instanceof RefType ||
                l.getType() instanceof ArrayType) {
                refTypeLocals.add(getEquivalentValue(l));
            }
        }
        
        if (isNotConservative) {
            // build list of fields
            // if the analysis is not conservative (if it is then we will only work on locals)
            
            Iterator unitIt = graph.iterator();
            
            while(unitIt.hasNext()) {
                
                Unit s = (Unit) unitIt.next();
                
                Iterator boxIt;
                boxIt = s.getUseBoxes().iterator();
                while(boxIt.hasNext()) initRefTypeLists( (ValueBox) boxIt.next() );
                boxIt = s.getDefBoxes().iterator();
                while(boxIt.hasNext()) initRefTypeLists( (ValueBox) boxIt.next() );
                
            }
            
        } // end build list of fields

        refTypeValues.addAll(refTypeLocals);
        refTypeValues.addAll(refTypeInstFields);
        refTypeValues.addAll(refTypeStaticFields);
        
        // G.v().out.println("Analyzed references: " + refTypeValues);
    } // end initRefTypeLists 
    
    private void initRefTypeLists( ValueBox box ) {
        Value val = box.getValue();
        Type opType = null;
        
        if (val instanceof InstanceFieldRef) {
            
            InstanceFieldRef ir = (InstanceFieldRef) val;
            
            opType = ir.getType(); 
            if (opType instanceof RefType ||
                opType instanceof ArrayType) {
                
                EquivalentValue eir = getEquivalentValue(ir); 
                
                if (!refTypeInstFields.contains(eir)) {
                    refTypeInstFields.add(eir);

                    EquivalentValue eirbase = getEquivalentValue(ir.getBase());
                    if (!refTypeInstFieldBases.contains(eirbase))
                        refTypeInstFieldBases.add(eirbase);
                }

            }
        } else if (val instanceof StaticFieldRef) {
            
            StaticFieldRef sr = (StaticFieldRef) val;
            opType = sr.getType();
            
            if (opType instanceof RefType ||
                opType instanceof ArrayType) {
                
                EquivalentValue esr = getEquivalentValue(sr);

                if (!refTypeStaticFields.contains(esr)) {
                    refTypeStaticFields.add(esr);
                }
            }
        }
    }
    // method to initialize the emptySet, fullSet and tempFlowSet
    // from the refTypeValues
    private void initUniverseSets()
    {
        FlowUniverse localUniverse;
        
        Object[] refTypeValuesArray = refTypeValues.toArray();
        int len = refTypeValuesArray.length;
        Object[] universeArray = new Object[2*len];
        int i;
        
        // kRefIntPairs = new HashMap(len*2 + 1, 0.7f);
        // ideally we would like to be able to do the above to avoid that Map growth
        // but that would screw concurent execution of this analysis
        // and making that field non- would require changing our  utility methods to non-
        
        for (i = 0; i < len; i++) {
            int j = i*2;
            EquivalentValue  r = (EquivalentValue) refTypeValuesArray[i];
            universeArray[j] = getKRefIntPair(r, kNull);
            universeArray[j+1] = getKRefIntPair(r,  kNonNull);
        }
        
        localUniverse = new ArrayFlowUniverse(universeArray);
        
        emptySet = new ArrayPackedSet(localUniverse);   
        fullSet = emptySet.clone();
        ((ArrayPackedSet) emptySet).complement(fullSet);
        
        tempFlowSet = (FlowSet) newInitialFlow();
    } // end initUniverseSets
    


    private void initUnitSets()
    {
        int cap = graph.size() * 2 + 1;
        float load = 0.7f;
        
        unitToGenerateSet = new HashMap(cap, load);
        unitToPreserveSet = new HashMap(cap, load);
        
        unitToAnalyzedChecksSet = new HashMap>(cap, load);
        unitToArrayRefChecksSet = new HashMap>(cap, load);
        unitToInstanceFieldRefChecksSet = new HashMap>(cap, load);
        unitToInstanceInvokeExprChecksSet = new HashMap>(cap, load);
        unitToLengthExprChecksSet = new HashMap>(cap, load);
        
        
        Iterator unitIt = graph.iterator();
        
        while(unitIt.hasNext()) {
            
            Unit s = (Unit) unitIt.next();
            
            FlowSet genSet = emptySet.clone();
            FlowSet preSet = fullSet.clone();
            
            HashSet analyzedChecksSet = new HashSet(5,  load);
            HashSet arrayRefChecksSet = new HashSet(5,  load);
            HashSet instanceFieldRefChecksSet = new HashSet(5,  load);
            HashSet instanceInvokeExprChecksSet = new HashSet(5,  load);
            HashSet lengthExprChecksSet = new HashSet(5,  load);
            
            
            // *** KILL PHASE ***
            
            // naivity here.  kill all the fields after an invoke, i.e. promote them to top
            if (careForMethodCalls && ((Stmt)s).containsInvokeExpr()) {
                uListAddTopToFlowSet(refTypeInstFields, genSet, preSet);
                uListAddTopToFlowSet(refTypeStaticFields, genSet, preSet);
            }
            
            if (careForAliases && (s instanceof AssignStmt)) {
                AssignStmt as = (AssignStmt) s;
                Value lhs = as.getLeftOp();
                
                if (refTypeInstFieldBases.contains(lhs)) {
                    // we have a write to a local 'f' and 
                    // there is a reference to f.x.
                    // The LHS will certainly be a local.
                    // here, we kill "f.*".

                    Iterator refTypeInstFieldsIt=refTypeInstFields.iterator();
                    
                    while (refTypeInstFieldsIt.hasNext()) {
                        EquivalentValue eifr = refTypeInstFieldsIt.next();
                        InstanceFieldRef ifr = (InstanceFieldRef) eifr.getValue();
                        
                        if (ifr.getBase() == lhs) {
                            uAddTopToFlowSet(eifr, genSet, preSet);
                        }
                    }
                }
                
                if (lhs instanceof InstanceFieldRef) {
                    
                    // we have a write to 'f.x', 
                    // so we'd better kill 'g.x' for all g.
                    
                    String lhsName = 
                        ((InstanceFieldRef) lhs).getField().getName();
                    
                    Iterator refTypeInstFieldsIt = refTypeInstFields.iterator();
                    
                    while (refTypeInstFieldsIt.hasNext()) {
                        EquivalentValue eifr = refTypeInstFieldsIt.next();
                        InstanceFieldRef ifr = (InstanceFieldRef) eifr.getValue();
                        
                        String name = ifr.getField().getName();
                        
                        if (name.equals(lhsName)) {
                            uAddTopToFlowSet(eifr, genSet, preSet);
                        }
                    }
                }
            } // end if (s instanceof AssignStmt)
            
            // kill rhs of defs
            {
                Iterator boxIt = s.getDefBoxes().iterator();
                
                while(boxIt.hasNext()) {
                    
                    ValueBox box = (ValueBox) boxIt.next();
                    Value boxValue = box.getValue();
                    
                    if (isAnalyzedRef(boxValue)) {
                        uAddTopToFlowSet(boxValue, genSet, preSet);
                    }
                }
            } // done killing rhs of defs
            
            // GENERATION PHASE
            
            if (s instanceof DefinitionStmt) {
                DefinitionStmt as = (DefinitionStmt) s;
                Value ro = as.getRightOp();
                Value lo = as.getLeftOp();
                
                // take out the cast from "x = (type) y;"
                if (ro instanceof CastExpr)
                    ro = ((CastExpr) ro).getOp();
                
                if (isAnalyzedRef(lo)) {
                    if (isAlwaysNonNull(ro)) {
                        uAddInfoToFlowSet(lo, kNonNull, genSet, preSet);
                    } else if (isAlwaysNull(ro)) {
                        uAddInfoToFlowSet(lo, kNull, genSet, preSet);
                    } else if (isAlwaysTop(ro)) {
                        uAddTopToFlowSet(lo, genSet, preSet);
                    }
                }
            } // end DefinitionStmt gen case

            // check use and def boxes for dereferencing operations
            // since those operations cause a null pointer check
            // after the statement we know the involved references are non-null
            {
                Iterator boxIt;
                boxIt = s.getUseBoxes().iterator();
                while(boxIt.hasNext()) {
                    Value boxValue = ((ValueBox) boxIt.next()).getValue();
                    Value base = null;
                    
                    if(boxValue instanceof InstanceFieldRef) {
                        base = ((InstanceFieldRef) (boxValue)).getBase();
                        instanceFieldRefChecksSet.add(base);
                    } else if (boxValue instanceof ArrayRef) {
                        base = ((ArrayRef) (boxValue)).getBase();
                        arrayRefChecksSet.add(base);
                    } else if (boxValue instanceof InstanceInvokeExpr) {
                        base = ((InstanceInvokeExpr) boxValue).getBase();
                        instanceInvokeExprChecksSet.add(base);                        
                    } else if (boxValue instanceof LengthExpr) {
                        base = ((LengthExpr) boxValue).getOp();
                        lengthExprChecksSet.add(base);
                    } else if (s instanceof ThrowStmt) {
                        base = ((ThrowStmt)s).getOp();
                    } else if (s instanceof MonitorStmt) {
                        base = ((MonitorStmt)s).getOp();
                    }
                    
                    if (base != null && isAnalyzedRef(base)) { 
                        uAddInfoToFlowSet(base, kNonNull, genSet, preSet);
                        analyzedChecksSet.add(base);
                    }
                }
                boxIt = s.getDefBoxes().iterator();
                while(boxIt.hasNext()) {
                    
                    Value boxValue = ((ValueBox) boxIt.next()).getValue();
                    Value base = null;
                    
                    if(boxValue instanceof InstanceFieldRef) {
                        base = ((InstanceFieldRef) (boxValue)).getBase();
                        instanceFieldRefChecksSet.add(base);
                    } else if (boxValue instanceof ArrayRef) {
                        base = ((ArrayRef) (boxValue)).getBase();
                        arrayRefChecksSet.add(base);
                    } else if (boxValue instanceof InstanceInvokeExpr) {
                        base = ((InstanceInvokeExpr) boxValue).getBase();
                        instanceInvokeExprChecksSet.add(base);                        
                    } else if (boxValue instanceof LengthExpr) {
                        base = ((LengthExpr) boxValue).getOp();
                        lengthExprChecksSet.add(base);
                    } else if (s instanceof ThrowStmt) {
                        base = ((ThrowStmt)s).getOp();
                    } else if (s instanceof MonitorStmt) {
                        base = ((MonitorStmt)s).getOp();
                    }
                    
                    if (base != null && isAnalyzedRef(base)) { 
                        uAddInfoToFlowSet(base, kNonNull, genSet, preSet);
                        analyzedChecksSet.add(base);
                    }
                }
            } // done check use and def boxes

            unitToGenerateSet.put(s, genSet);
            unitToPreserveSet.put(s, preSet);
            
            unitToAnalyzedChecksSet.put(s, analyzedChecksSet);
            unitToArrayRefChecksSet.put(s, arrayRefChecksSet);
            unitToInstanceFieldRefChecksSet.put(s, instanceFieldRefChecksSet);
            unitToInstanceInvokeExprChecksSet.put(s, instanceInvokeExprChecksSet);
            unitToLengthExprChecksSet.put(s, lengthExprChecksSet);
        }
    } // initUnitSets
    
    protected void flowThrough(Object inValue, Unit stmt, List outFallValue, List outBranchValues)
    {
        FlowSet in = (FlowSet) inValue;
        FlowSet out = tempFlowSet;
        FlowSet pre = unitToPreserveSet.get(stmt);
        FlowSet gen = unitToGenerateSet.get(stmt);

        // Perform perservation
        in.intersection(pre, out);
        
        // Perform generation
        out.union(gen, out);
        
        // Manually add any x = y; when x and y are both analyzed references
        // these are not  sets.
        if (stmt instanceof AssignStmt) {
            AssignStmt as = (AssignStmt) stmt;
            Value rightOp = as.getRightOp();
            Value leftOp = as.getLeftOp();
            
            // take out the cast from "x = (type) y;"
            if (rightOp instanceof CastExpr)
                rightOp = ((CastExpr) rightOp).getOp();
            
            if (isAnalyzedRef(leftOp) && isAnalyzedRef(rightOp)) {
                int roInfo = refInfo(rightOp, in);
                
                if (roInfo == kTop)
                    uAddTopToFlowSet(leftOp, out);
                else if (roInfo != kBottom)
                    uAddInfoToFlowSet(leftOp, roInfo, out);
            }
        }
        
        // Copy the out value to all branch boxes.
        {
            Iterator it = outBranchValues.iterator();
            while (it.hasNext()) {
                FlowSet fs = (FlowSet) (it.next());
                
                copy(out, fs);
            }
        }
        
        // Copy the out value to the fallthrough box (don't need iterator)
        {
            Iterator it = outFallValue.iterator();
            while (it.hasNext()) {
                FlowSet fs = (FlowSet) (it.next());
                
                copy(out, fs);
            }
        }
        
        if (isBranched && (stmt instanceof IfStmt)) {
            Value cond = ((IfStmt) stmt).getCondition();
            Value op1 = ((BinopExpr) cond).getOp1();
            Value op2 = ((BinopExpr) cond).getOp2();

            // make sure at least one of the op is a reference being analyzed
            // and that none is a reference that is always Top
            if ((!(isAlwaysTop(op1) || isAlwaysTop(op2))) && (isAnalyzedRef(op1) || isAnalyzedRef(op2))) {
                Value toGen = null;
                int toGenInfo = kBottom;

                int op1Info = anyRefInfo(op1, in);
                int op2Info = anyRefInfo(op2, in);
                boolean op1isKnown = (op1Info == kNull || op1Info == kNonNull);
                boolean op2isKnown = (op2Info == kNull || op2Info == kNonNull);
                
                if (op1isKnown) {
                    if (!op2isKnown) {
                        toGen = op2;
                        toGenInfo = op1Info;
                    }
                } else if (op2isKnown) {
                    toGen =  op1;
                    toGenInfo = op2Info;
                }
                
                // only generate info for analyzed references that are top or bottom
                if ((toGen != null) && isAnalyzedRef(toGen)) {
                    int fInfo = kBottom;
                    int bInfo = kBottom;
                    
                    if (cond instanceof EqExpr) {
                        // branching mean op1 == op2
                        bInfo = toGenInfo;
                        if (toGenInfo == kNull) {
                            // falling through mean toGen != null
                            fInfo = kNonNull;
                        }
                        
                    } else if (cond instanceof NeExpr) {
                        // if we don't branch that mean op1 == op2
                        fInfo = toGenInfo;
                        if (toGenInfo == kNull) {
                            // branching through mean toGen != null
                            bInfo = kNonNull;
                        }
                    } else
                        throw new RuntimeException("invalid condition");

                    if (fInfo != kBottom) {
                        Iterator it = outFallValue.iterator();

                        while(it.hasNext()) {
                            FlowSet fs = (FlowSet) (it.next());

                            copy(out, fs);
                            uAddInfoToFlowSet(toGen, fInfo, fs);
                        }
                    }

                    if (bInfo !=  kBottom) {
                        Iterator it = outBranchValues.iterator();

                        while (it.hasNext()) {
                            FlowSet fs = (FlowSet) (it.next());

                            copy(out, fs);
                            uAddInfoToFlowSet(toGen, bInfo, fs);
                        }
                    } 
                }
            }
        }
    } // end flowThrough


    protected void merge(Object in1, Object in2, Object out)
    {
        FlowSet inSet1 = (FlowSet) in1;
        FlowSet inSet2 = (FlowSet) in2;
        FlowSet inSet1Copy = inSet1.clone();
        FlowSet inSet2Copy = inSet2.clone();
        // we do that in case out is in1 or in2

        FlowSet outSet = (FlowSet) out;

        inSet1.intersection(inSet2, outSet);
        // first step, set out to the intersection of in1 & in2
        // but we are not over, the intersection doesn't handle the top & bottom cases
        Iterator it = refTypeValues.iterator();
        while (it.hasNext()) {
            EquivalentValue r = it.next();
            int refInfoIn1 = refInfo(r, inSet1Copy);
            int refInfoIn2 = refInfo(r, inSet2Copy);
            if (refInfoIn1 != refInfoIn2) {
                // only process if they are not equal, otherwise the intersection has done its job
                if ((refInfoIn1 == kTop) || (refInfoIn2 == kTop)) {
                    // ok, r is top in one of the sets but not the other, make it top in the outSet
                    uAddTopToFlowSet(r, outSet);
                } else if (refInfoIn1 == kBottom) {
                    // r is bottom in set1 but not set2, promote to the value in set2
                    uAddInfoToFlowSet(r, refInfoIn2, outSet);
                } else if (refInfoIn2 == kBottom) {
                    // r is bottom in set2 but not set1, promote to the value in set1
                    uAddInfoToFlowSet(r, refInfoIn1, outSet);
                } else {
                    // r is known in both set, but it's a different value in each set, make it top
                    uAddTopToFlowSet(r, outSet);
                }
            }
        }
    } // end merge
    

    protected void copy(Object source, Object dest)
    {
        FlowSet sourceSet = (FlowSet) source,
            destSet = (FlowSet) dest;
            
        sourceSet.copy(destSet);
    } // end copy


    protected Object newInitialFlow()
    {
        return emptySet.clone();
    } // end newInitialFlow


    protected Object entryInitialFlow()
    {
        return fullSet.clone();
    }

    // try to workaround exception limitation of ForwardBranchedFlowAnalysis
    // this will make for a very conservative analysys when exception handling
    // statements are in the code :-(
    public boolean treatTrapHandlersAsEntries()
    {
        return true;
    }

} // end class BranchedRefVarsAnalysis





© 2015 - 2024 Weber Informatics LLC | Privacy Policy