/******************************************************************************* * 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.ipa.callgraph.propagation; import com.ibm.wala.analysis.typeInference.TypeInference; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.fixpoint.IntSetVariable; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ssa.IR; import com.ibm.wala.types.TypeReference; import com.ibm.wala.util.debug.Assertions; import com.ibm.wala.util.intset.IntSet; import com.ibm.wala.util.intset.IntSetAction; import com.ibm.wala.util.intset.MutableMapping; import com.ibm.wala.util.intset.MutableSparseIntSet; /** * Representation of a points-to set during an andersen-style analysis. */ public class PointsToSetVariable extends IntSetVariable<PointsToSetVariable> { /** * if set, emits a warning whenever a points-to set grows bigger than {@link #SIZE_THRESHOLD} */ public static final boolean CRY_ABOUT_BIG_POINTSTO_SETS = false; public static final int SIZE_THRESHOLD = 100; /** * if set, check that all instance keys in a points-to set are consistent with the type of the corresponding pointer key */ public static final boolean PARANOID = false; /** * used only for paranoid checking. a bit ugly, but avoids adding an instance field just for debugging */ public static MutableMapping<InstanceKey> instanceKeys = null; private PointerKey pointerKey; public PointsToSetVariable(PointerKey key) { super(); if (key == null) { throw new IllegalArgumentException("null key"); } this.pointerKey = key; } public PointerKey getPointerKey() { return pointerKey; } @Override public boolean equals(Object obj) { if (obj instanceof PointsToSetVariable) { return pointerKey.equals(((PointsToSetVariable) obj).pointerKey); } else { return false; } } private boolean cried = false; @SuppressWarnings("unused") private void cryIfTooBig() { if (CRY_ABOUT_BIG_POINTSTO_SETS && !cried && super.size() > SIZE_THRESHOLD) { cried = true; System.err.println("too big: " + pointerKey + ": " + size()); } } @Override public void add(int b) { if (PARANOID) { MutableSparseIntSet m = MutableSparseIntSet.createMutableSparseIntSet(1); m.add(b); checkTypes(m); } super.add(b); cryIfTooBig(); } @Override public boolean addAll(IntSet B) { if (PARANOID) { checkTypes(B); } boolean v = super.addAll(B); cryIfTooBig(); return v; } /** * check that the types of all instance keys are assignable to declared type of pointer key */ private void checkTypes(IntSet b) { assert PARANOID; if (b == null) return; if (!(pointerKey instanceof LocalPointerKey)) { return; } final LocalPointerKey lpk = (LocalPointerKey) pointerKey; CGNode node = lpk.getNode(); final IClassHierarchy cha = node.getClassHierarchy(); final IR ir = node.getIR(); if (ir == null) return; TypeInference ti = TypeInference.make(ir, false); final IClass type = ti.getType(lpk.getValueNumber()).getType(); if (type == null) return; // don't perform checking for exception variables if (cha.isAssignableFrom(cha.lookupClass(TypeReference.JavaLangThrowable), type)) { return; } b.foreach(new IntSetAction() { @Override public void act(int x) { InstanceKey ik = instanceKeys.getMappedObject(x); IClass concreteType = ik.getConcreteType(); if (!cha.isAssignableFrom(type, concreteType)) { System.err.println("BOOM"); System.err.println(ir); System.err.println(lpk + " type " + type); System.err.println(ik + " type " + concreteType); Assertions.UNREACHABLE(); } } }); } @Override public boolean addAll(PointsToSetVariable other) { if (PARANOID) { checkTypes(other.getValue()); } // TODO Auto-generated method stub boolean v = super.addAll(other); cryIfTooBig(); return v; } /** * Use this with extreme care, to add filters to this variable.. * * @param pointerKey The pointerKey to set. */ void setPointerKey(PointerKey pointerKey) { // check that we haven't modified the hash code!!! this is crucial assert this.pointerKey.hashCode() == pointerKey.hashCode(); this.pointerKey = pointerKey; } @Override public String toString() { return pointerKey.toString() + ":" + super.toString(); } }