org.sosy_lab.cpachecker.cpa.reachdef.ReachingDefState.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.cpa.reachdef.ReachingDefState.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package org.sosy_lab.cpachecker.cpa.reachdef;

import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;

import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.core.defaults.LatticeAbstractState;
import org.sosy_lab.cpachecker.core.interfaces.AbstractState;
import org.sosy_lab.cpachecker.core.interfaces.Graphable;
import org.sosy_lab.cpachecker.util.globalinfo.CFAInfo;
import org.sosy_lab.cpachecker.util.globalinfo.GlobalInfo;
import org.sosy_lab.cpachecker.util.reachingdef.ReachingDefinitionStorage;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

public class ReachingDefState
        implements AbstractState, Serializable, LatticeAbstractState<ReachingDefState>, Graphable {

    private static final long serialVersionUID = -7715698130795640052L;

    private static final SerialProxyReach proxy = new SerialProxyReach();

    public static final ReachingDefState topElement = new ReachingDefState();

    private ReachingDefState stateOnLastFunctionCall;

    private transient Map<String, Set<DefinitionPoint>> localReachDefs;

    private transient Map<String, Set<DefinitionPoint>> globalReachDefs;

    private ReachingDefState() {
    }

    public ReachingDefState(Set<String> globalVariableNames) {
        stateOnLastFunctionCall = null;
        localReachDefs = new HashMap<>();
        globalReachDefs = new HashMap<>();
        addVariables(globalReachDefs, globalVariableNames, UninitializedDefinitionPoint.getInstance());
    }

    public ReachingDefState(Map<String, Set<DefinitionPoint>> pLocalReachDefs,
            Map<String, Set<DefinitionPoint>> pGlobalReachDefs, ReachingDefState stateLastFuncCall) {
        stateOnLastFunctionCall = stateLastFuncCall;
        localReachDefs = pLocalReachDefs;
        globalReachDefs = pGlobalReachDefs;
    }

    public ReachingDefState addLocalReachDef(String variableName, CFANode pEntry, CFANode pExit) {
        ProgramDefinitionPoint definition = new ProgramDefinitionPoint(pEntry, pExit);
        return new ReachingDefState(replaceReachDef(localReachDefs, variableName, definition), globalReachDefs,
                stateOnLastFunctionCall);
    }

    public ReachingDefState addGlobalReachDef(String variableName, CFANode pEntry, CFANode pExit) {
        ProgramDefinitionPoint definition = new ProgramDefinitionPoint(pEntry, pExit);
        return new ReachingDefState(localReachDefs, replaceReachDef(globalReachDefs, variableName, definition),
                stateOnLastFunctionCall);
    }

    private Map<String, Set<DefinitionPoint>> replaceReachDef(Map<String, Set<DefinitionPoint>> toChange,
            String variableName, ProgramDefinitionPoint definition) {
        Map<String, Set<DefinitionPoint>> changed = new HashMap<>(toChange);
        ImmutableSet<DefinitionPoint> insert = ImmutableSet.of((DefinitionPoint) definition);
        changed.put(variableName, insert);
        return changed;
    }

    public ReachingDefState initVariables(Set<String> uninitVariableNames, Set<String> parameters, CFANode pEntry,
            CFANode pExit) {
        ProgramDefinitionPoint definition = new ProgramDefinitionPoint(pEntry, pExit);
        HashMap<String, Set<DefinitionPoint>> localVarsDef = new HashMap<>();
        addVariables(localVarsDef, uninitVariableNames, UninitializedDefinitionPoint.getInstance());
        addVariables(localVarsDef, parameters, definition);
        return new ReachingDefState(localVarsDef, globalReachDefs, this);
    }

    private void addVariables(Map<String, Set<DefinitionPoint>> addTo, Set<String> variableNames,
            DefinitionPoint definition) {
        ImmutableSet<DefinitionPoint> insert = ImmutableSet.of(definition);
        for (String name : variableNames) {
            addTo.put(name, insert);
        }
    }

    public ReachingDefState pop() {
        return new ReachingDefState(stateOnLastFunctionCall.localReachDefs, globalReachDefs,
                stateOnLastFunctionCall.stateOnLastFunctionCall);
    }

    public Map<String, Set<DefinitionPoint>> getLocalReachingDefinitions() {
        return this == topElement ? null : localReachDefs;
    }

    public Map<String, Set<DefinitionPoint>> getGlobalReachingDefinitions() {
        return this == topElement ? null : globalReachDefs;
    }

    @Override
    public boolean isLessOrEqual(ReachingDefState superset) {
        if (superset == this || superset == topElement) {
            return true;
        }
        if (stateOnLastFunctionCall != superset.stateOnLastFunctionCall
                && !compareStackStates(stateOnLastFunctionCall, superset.stateOnLastFunctionCall)) {
            return false;
        }
        boolean isLocalSubset;
        isLocalSubset = isSubsetOf(localReachDefs, superset.localReachDefs);
        return isLocalSubset && isSubsetOf(globalReachDefs, superset.globalReachDefs);
    }

    private boolean compareStackStates(ReachingDefState sub, ReachingDefState sup) {
        boolean result;
        do {
            if (sub == null || sup == null) {
                return false;
            }
            result = isSubsetOf(sub.getLocalReachingDefinitions(), sup.getLocalReachingDefinitions());
            result = result && isSubsetOf(sub.getGlobalReachingDefinitions(), sup.getGlobalReachingDefinitions());
            sub = sub.stateOnLastFunctionCall;
            sup = sup.stateOnLastFunctionCall;
        } while (sub != sup && result);
        return result;
    }

    private boolean isSubsetOf(Map<String, Set<DefinitionPoint>> subset,
            Map<String, Set<DefinitionPoint>> superset) {
        Set<DefinitionPoint> setSub, setSuper;
        if (subset == superset) {
            return true;
        }
        for (Entry<String, Set<DefinitionPoint>> entry : subset.entrySet()) {
            setSub = entry.getValue();
            setSuper = superset.get(entry.getKey());
            if (setSub == setSuper) {
                continue;
            }
            if (setSuper == null || Sets.intersection(setSub, setSuper).size() != setSub.size()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public ReachingDefState join(ReachingDefState toJoin) {
        Map<String, Set<DefinitionPoint>> newLocal = null;
        boolean changed = false;
        ReachingDefState lastFunctionCall;
        if (toJoin == this) {
            return this;
        }
        if (toJoin == topElement || this == topElement) {
            return topElement;
        }
        if (stateOnLastFunctionCall != toJoin.stateOnLastFunctionCall) {
            lastFunctionCall = mergeStackStates(stateOnLastFunctionCall, toJoin.stateOnLastFunctionCall);
            if (lastFunctionCall == topElement) {
                return topElement;
            }
            if (lastFunctionCall != stateOnLastFunctionCall) {
                changed = true;
            } else {
                lastFunctionCall = toJoin.stateOnLastFunctionCall;
            }
        } else {
            lastFunctionCall = toJoin.stateOnLastFunctionCall;
        }

        Map<String, Set<DefinitionPoint>> resultOfMapUnion;
        resultOfMapUnion = unionMaps(localReachDefs, toJoin.localReachDefs);
        if (resultOfMapUnion == localReachDefs) {
            newLocal = toJoin.localReachDefs;
        } else {
            changed = true;
            newLocal = resultOfMapUnion;
        }

        resultOfMapUnion = unionMaps(globalReachDefs, toJoin.globalReachDefs);
        if (resultOfMapUnion == globalReachDefs) {
            resultOfMapUnion = toJoin.globalReachDefs;
        } else {
            changed = true;
        }

        if (changed) {
            assert (newLocal != null);
            return new ReachingDefState(newLocal, resultOfMapUnion, lastFunctionCall);
        }
        return toJoin;
    }

    private ReachingDefState mergeStackStates(ReachingDefState e1, ReachingDefState e2) {
        Vector<ReachingDefState> statesToMerge = new Vector<>();
        do {
            if (e1.stateOnLastFunctionCall == null || e2.stateOnLastFunctionCall == null) {
                return topElement;
            }
            statesToMerge.add(e1);
            statesToMerge.add(e2);
            e1 = e1.stateOnLastFunctionCall;
            e2 = e2.stateOnLastFunctionCall;
        } while (e1 != e2);

        boolean changed = false;
        Map<String, Set<DefinitionPoint>> resultOfMapUnion;
        Map<String, Set<DefinitionPoint>> newLocal;
        ReachingDefState newStateOnLastFunctionCall = e1;

        for (int i = statesToMerge.size() - 1; i >= 0; i = i - 2) {
            resultOfMapUnion = unionMaps(statesToMerge.get(i - 1).localReachDefs,
                    statesToMerge.get(i).localReachDefs);
            if (resultOfMapUnion != statesToMerge.get(i - 1).localReachDefs) {
                changed = true;
                newLocal = resultOfMapUnion;
            } else {
                newLocal = statesToMerge.get(i).localReachDefs;
            }

            resultOfMapUnion = unionMaps(statesToMerge.get(i - 1).globalReachDefs,
                    statesToMerge.get(i).globalReachDefs);
            if (resultOfMapUnion != statesToMerge.get(i - 1).globalReachDefs) {
                changed = true;
            } else {
                resultOfMapUnion = statesToMerge.get(i).globalReachDefs;
            }
            if (!isSubsetOf(statesToMerge.get(i).globalReachDefs, resultOfMapUnion)) {
                isSubsetOf(statesToMerge.get(i).globalReachDefs, resultOfMapUnion);
            }
            newStateOnLastFunctionCall = new ReachingDefState(newLocal, resultOfMapUnion,
                    newStateOnLastFunctionCall);
        }

        if (changed) {
            return newStateOnLastFunctionCall;
        }
        return statesToMerge.get(0);
    }

    private Map<String, Set<DefinitionPoint>> unionMaps(Map<String, Set<DefinitionPoint>> map1,
            Map<String, Set<DefinitionPoint>> map2) {
        Map<String, Set<DefinitionPoint>> newMap = new HashMap<>();
        // every declared local variable of a function, global variable occurs in respective map, possibly undefined
        assert (map1.keySet().equals(map2.keySet()));
        if (map1 == map2) {
            return map1;
        }
        Set<DefinitionPoint> unionResult;
        boolean changed = false;
        for (Entry<String, Set<DefinitionPoint>> entry : map1.entrySet()) {
            String var = entry.getKey();
            // decrease merge time, avoid building union if unnecessary
            if (entry.getValue() == map2.get(var)) {
                newMap.put(var, map2.get(var));
                continue;
            }
            unionResult = unionSets(entry.getValue(), map2.get(var));
            if (unionResult.size() != map2.get(var).size()) {
                changed = true;
            }
            newMap.put(var, unionResult);
        }
        assert (map1.keySet().equals(newMap.keySet()));
        if (changed) {
            return newMap;
        }
        return map1;
    }

    private Set<DefinitionPoint> unionSets(Set<DefinitionPoint> set1, Set<DefinitionPoint> set2) {
        HashSet<DefinitionPoint> result = new HashSet<>();
        for (DefinitionPoint p : set1) {
            result.add(p);
        }
        for (DefinitionPoint p : set2) {
            result.add(p);
        }
        return result;
    }

    private Object writeReplace() throws ObjectStreamException {
        if (this == topElement) {
            return proxy;
        } else {
            return this;

        }
    }

    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();

        out.writeInt(ReachingDefinitionStorage.getInstance().saveMap(localReachDefs));
        out.writeInt(ReachingDefinitionStorage.getInstance().saveMap(globalReachDefs));
    }

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();

        int id;

        id = in.readInt();
        localReachDefs = ReachingDefinitionStorage.getInstance().getMap(id);

        id = in.readInt();
        globalReachDefs = ReachingDefinitionStorage.getInstance().getMap(id);
    }

    private static class SerialProxyReach implements Serializable {

        private static final long serialVersionUID = 2843708585446089623L;

        public SerialProxyReach() {
        }

        private Object readResolve() throws ObjectStreamException {
            return topElement;
        }
    }

    public interface DefinitionPoint {

    }

    public static class UninitializedDefinitionPoint implements DefinitionPoint, Serializable {

        private static final long serialVersionUID = 6987753908487106524L;
        private static UninitializedDefinitionPoint instance = new UninitializedDefinitionPoint();
        private static final SerialProxy writeReplace = new SerialProxy();

        private UninitializedDefinitionPoint() {
        }

        public static UninitializedDefinitionPoint getInstance() {
            return instance;
        }

        @Override
        public String toString() {
            return "?";
        }

        private Object writeReplace() throws ObjectStreamException {
            return writeReplace;
        }

        private static class SerialProxy implements Serializable {

            private static final long serialVersionUID = 2843708585446089623L;

            public SerialProxy() {
            }

            private Object readResolve() throws ObjectStreamException {
                return instance;
            }
        }
    }

    public static class ProgramDefinitionPoint implements DefinitionPoint, Serializable {

        private static final long serialVersionUID = -7601382286840053882L;
        private transient CFANode entry;
        private transient CFANode exit;

        public ProgramDefinitionPoint(CFANode pEntry, CFANode pExit) {
            entry = pEntry;
            exit = pExit;
        }

        public CFANode getDefinitionEntryLocation() {
            return entry;
        }

        public CFANode getDefinitionExitLocation() {
            return exit;
        }

        @Override
        public String toString() {
            return "(N" + entry.getNodeNumber() + ",N" + exit.getNodeNumber() + ")";
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((entry == null) ? 0 : entry.hashCode());
            result = prime * result + ((exit == null) ? 0 : exit.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            ProgramDefinitionPoint other = (ProgramDefinitionPoint) obj;
            if (entry == null) {
                if (other.entry != null) {
                    return false;
                }
            } else if (!entry.equals(other.entry)) {
                return false;
            }
            if (exit == null) {
                if (other.exit != null) {
                    return false;
                }
            } else if (!exit.equals(other.exit)) {
                return false;
            }
            return true;
        }

        private void writeObject(java.io.ObjectOutputStream out) throws IOException {
            out.writeInt(entry.getNodeNumber());
            out.writeInt(exit.getNodeNumber());
        }

        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
            int nodeNumber = in.readInt();
            CFAInfo cfaInfo = GlobalInfo.getInstance().getCFAInfo().get();
            entry = cfaInfo.getNodeByNodeNumber(nodeNumber);
            nodeNumber = in.readInt();
            exit = cfaInfo.getNodeByNodeNumber(nodeNumber);
        }

    }

    @Override
    public String toDOTLabel() {

        StringBuilder sb = new StringBuilder();

        sb.append("{");
        sb.append("\\n");

        sb.append(System.identityHashCode(this));
        sb.append("\\n");

        // create a string like: global:  [varName1; varName2; ... ; ...]
        sb.append("global:");
        sb.append(createStringOfMap(globalReachDefs));
        sb.append("\\n");

        // create a string like: local:  [varName1; varName2; ... ; ...]
        sb.append("local:");
        sb.append(createStringOfMap(localReachDefs));
        sb.append("\\n");

        sb.append(System.identityHashCode(stateOnLastFunctionCall));
        sb.append("\\n");

        sb.append("}");

        return sb.toString();
    }

    private String createStringOfMap(Map<String, Set<DefinitionPoint>> map) {
        StringBuilder sb = new StringBuilder();
        sb.append(" [");

        boolean first = true;

        for (Entry<String, Set<DefinitionPoint>> entry : map.entrySet()) {
            if (first) {
                first = false;
            } else {
                sb.append(", ");
            }

            sb.append(" (");
            sb.append(entry.getKey());
            sb.append(": [");
            Joiner.on("; ").appendTo(sb, entry.getValue());
            sb.append("])");
        }
        sb.append("]");
        return sb.toString();
    }

    @Override
    public boolean shouldBeHighlighted() {
        return false;
    }

}