heros.FlowFunctionCache.java Source code

Java tutorial

Introduction

Here is the source code for heros.FlowFunctionCache.java

Source

/*******************************************************************************
 * Copyright (c) 2012 Eric Bodden.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Eric Bodden - initial API and implementation
 ******************************************************************************/
package heros;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class FlowFunctionCache<N, D, M> implements FlowFunctions<N, D, M> {

    protected final FlowFunctions<N, D, M> delegate;

    protected final LoadingCache<NNKey, FlowFunction<D>> normalCache;

    protected final LoadingCache<CallKey, FlowFunction<D>> callCache;

    protected final LoadingCache<ReturnKey, FlowFunction<D>> returnCache;

    protected final LoadingCache<NNKey, FlowFunction<D>> callToReturnCache;

    @SuppressWarnings("unchecked")
    public FlowFunctionCache(final FlowFunctions<N, D, M> delegate,
            @SuppressWarnings("rawtypes") CacheBuilder builder) {
        this.delegate = delegate;

        normalCache = builder.build(new CacheLoader<NNKey, FlowFunction<D>>() {
            public FlowFunction<D> load(NNKey key) throws Exception {
                return delegate.getNormalFlowFunction(key.getCurr(), key.getSucc());
            }
        });

        callCache = builder.build(new CacheLoader<CallKey, FlowFunction<D>>() {
            public FlowFunction<D> load(CallKey key) throws Exception {
                return delegate.getCallFlowFunction(key.getCallStmt(), key.getDestinationMethod());
            }
        });

        returnCache = builder.build(new CacheLoader<ReturnKey, FlowFunction<D>>() {
            public FlowFunction<D> load(ReturnKey key) throws Exception {
                return delegate.getReturnFlowFunction(key.getCallStmt(), key.getDestinationMethod(),
                        key.getExitStmt(), key.getReturnSite());
            }
        });

        callToReturnCache = builder.build(new CacheLoader<NNKey, FlowFunction<D>>() {
            public FlowFunction<D> load(NNKey key) throws Exception {
                return delegate.getCallToReturnFlowFunction(key.getCurr(), key.getSucc());
            }
        });
    }

    public FlowFunction<D> getNormalFlowFunction(N curr, N succ) {
        return normalCache.getUnchecked(new NNKey(curr, succ));
    }

    public FlowFunction<D> getCallFlowFunction(N callStmt, M destinationMethod) {
        return callCache.getUnchecked(new CallKey(callStmt, destinationMethod));
    }

    public FlowFunction<D> getReturnFlowFunction(N callSite, M calleeMethod, N exitStmt, N returnSite) {
        return returnCache.getUnchecked(new ReturnKey(callSite, calleeMethod, exitStmt, returnSite));
    }

    public FlowFunction<D> getCallToReturnFlowFunction(N callSite, N returnSite) {
        return callToReturnCache.getUnchecked(new NNKey(callSite, returnSite));
    }

    private class NNKey {
        private final N curr, succ;

        private NNKey(N curr, N succ) {
            this.curr = curr;
            this.succ = succ;
        }

        public N getCurr() {
            return curr;
        }

        public N getSucc() {
            return succ;
        }

        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((curr == null) ? 0 : curr.hashCode());
            result = prime * result + ((succ == null) ? 0 : succ.hashCode());
            return result;
        }

        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            @SuppressWarnings("unchecked")
            NNKey other = (NNKey) obj;
            if (curr == null) {
                if (other.curr != null)
                    return false;
            } else if (!curr.equals(other.curr))
                return false;
            if (succ == null) {
                if (other.succ != null)
                    return false;
            } else if (!succ.equals(other.succ))
                return false;
            return true;
        }
    }

    private class CallKey {
        private final N callStmt;
        private final M destinationMethod;

        private CallKey(N callStmt, M destinationMethod) {
            this.callStmt = callStmt;
            this.destinationMethod = destinationMethod;
        }

        public N getCallStmt() {
            return callStmt;
        }

        public M getDestinationMethod() {
            return destinationMethod;
        }

        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((callStmt == null) ? 0 : callStmt.hashCode());
            result = prime * result + ((destinationMethod == null) ? 0 : destinationMethod.hashCode());
            return result;
        }

        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            @SuppressWarnings("unchecked")
            CallKey other = (CallKey) obj;
            if (callStmt == null) {
                if (other.callStmt != null)
                    return false;
            } else if (!callStmt.equals(other.callStmt))
                return false;
            if (destinationMethod == null) {
                if (other.destinationMethod != null)
                    return false;
            } else if (!destinationMethod.equals(other.destinationMethod))
                return false;
            return true;
        }
    }

    private class ReturnKey extends CallKey {

        private final N exitStmt, returnSite;

        private ReturnKey(N callStmt, M destinationMethod, N exitStmt, N returnSite) {
            super(callStmt, destinationMethod);
            this.exitStmt = exitStmt;
            this.returnSite = returnSite;
        }

        public N getExitStmt() {
            return exitStmt;
        }

        public N getReturnSite() {
            return returnSite;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = super.hashCode();
            result = prime * result + ((exitStmt == null) ? 0 : exitStmt.hashCode());
            result = prime * result + ((returnSite == null) ? 0 : returnSite.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (!super.equals(obj))
                return false;
            if (getClass() != obj.getClass())
                return false;
            @SuppressWarnings("unchecked")
            ReturnKey other = (ReturnKey) obj;
            if (exitStmt == null) {
                if (other.exitStmt != null)
                    return false;
            } else if (!exitStmt.equals(other.exitStmt))
                return false;
            if (returnSite == null) {
                if (other.returnSite != null)
                    return false;
            } else if (!returnSite.equals(other.returnSite))
                return false;
            return true;
        }
    }

    public void printStats() {
        System.err.println("Stats for flow-function cache:");
        System.err.print("Normal:         ");
        System.err.println(normalCache.stats());
        System.err.print("Call:           ");
        System.err.println(callCache.stats());
        System.err.print("Return:         ");
        System.err.println(returnCache.stats());
        System.err.print("Call-to-return: ");
        System.err.println(callToReturnCache.stats());
    }

}