/******************************************************************************* * Copyright (c) 2002 - 2006 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.wala.dataflow.IFDS; import java.util.Iterator; import com.ibm.wala.util.collections.SparseVector; import com.ibm.wala.util.intset.BasicNaturalRelation; import com.ibm.wala.util.intset.IBinaryNaturalRelation; import com.ibm.wala.util.intset.IntPair; import com.ibm.wala.util.intset.IntSet; import com.ibm.wala.util.intset.MutableSparseIntSet; import com.ibm.wala.util.intset.SparseLongIntVector; import com.ibm.wala.util.math.LongUtil; /** * A set of summary edges for a particular procedure. */ public class LocalSummaryEdges { /** * A map from integer n -> (IBinaryNonNegativeIntRelation) * * Let s_p be an entry to this procedure, and x be an exit. n is a integer which uniquely identifies an (s_p,x) relation. For any * such n, summaries[n] gives a relation R=(d1,d2) s.t. (<s_p, d1> -> <x,d2>) is a summary edge. * * Note that this representation is a little different from the representation described in the PoPL 95 paper. We cache summary * edges at the CALLEE, not at the CALLER!!! This allows us to avoid eagerly installing summary edges at all call sites to a * procedure, which may be a win. * * we don't technically need this class, since this information is redundantly stored in LocalPathEdges. However, we're keeping it * cached for now for more efficient access when looking up summary edges. * * TODO: more representation optimization. */ private final SparseVector<IBinaryNaturalRelation> summaries = new SparseVector<IBinaryNaturalRelation>(1, 1.1f); /** * Let (s_p,x) be an entry-exit pair, and let l := the long whose high word is s_p and low word is x. * * Then entryExitMap(l) is an int which uniquely identifies (s_p,x) * * we populate this map on demand! */ private final static int UNASSIGNED = -1; private final SparseLongIntVector entryExitMap = new SparseLongIntVector(UNASSIGNED); private int nextEntryExitIndex = 0; /** * */ public LocalSummaryEdges() { } /** * Record a summary edge for the flow d1 -> d2 from an entry s_p to an exit x. * * @param s_p local block number an entry * @param x local block number of an exit block * @param d1 source dataflow fact * @param d2 target dataflow fact */ public void insertSummaryEdge(int s_p, int x, int d1, int d2) { int n = getIndexForEntryExitPair(s_p, x); IBinaryNaturalRelation R = summaries.get(n); if (R == null) { // we expect R to usually be sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.SIMPLE); summaries.set(n, R); } R.add(d1, d2); // if (TabulationSolver.DEBUG_LEVEL > 1) { // // System.err.println("recording summary edge, now n=" + n + " summarized by " + R); // } } /** * Does a particular summary edge exist? * * @param s_p local block number an entry * @param x local block number of an exit block * @param d1 source dataflow fact * @param d2 target dataflow fact */ public boolean contains(int s_p, int x, int d1, int d2) { int n = getIndexForEntryExitPair(s_p, x); IBinaryNaturalRelation R = summaries.get(n); if (R == null) { return false; } else { return R.contains(d1, d2); } } /** * @param s_p local block number an entry * @param x local block number of an exit block * @param d1 source dataflow fact * @return set of d2 s.t. d1->d2 recorded as a summary edge for (s_p,x), or null if none */ public IntSet getSummaryEdges(int s_p, int x, int d1) { int n = getIndexForEntryExitPair(s_p, x); IBinaryNaturalRelation R = summaries.get(n); if (R == null) { return null; } else { return R.getRelated(d1); } } /** * Note: This is inefficient. Use with care. * * @param s_p local block number an entry * @param x local block number of an exit block * @param d2 target dataflow fact * @return set of d1 s.t. d1->d2 recorded as a summary edge for (s_p,x), or null if none */ public IntSet getInvertedSummaryEdgesForTarget(int s_p, int x, int d2) { int n = getIndexForEntryExitPair(s_p, x); IBinaryNaturalRelation R = summaries.get(n); if (R == null) { return null; } else { MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); for (Iterator it = R.iterator(); it.hasNext();) { IntPair p = (IntPair) it.next(); if (p.getY() == d2) { result.add(p.getX()); } } return result; } } /** * @return unique id n that represents the pair (s_p,x) */ private int getIndexForEntryExitPair(int c, int r) { long id = LongUtil.pack(c, r); int result = entryExitMap.get(id); if (result == UNASSIGNED) { result = nextEntryExitIndex++; entryExitMap.set(id, result); } return result; } }