/******************************************************************************* * 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 java.util.Arrays; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.ipa.callgraph.ContextItem; import com.ibm.wala.util.intset.IntSet; import com.ibm.wala.util.intset.IntSetAction; import com.ibm.wala.util.intset.IntSetUtil; import com.ibm.wala.util.intset.MutableIntSet; /** * A {@link PointerKey} which carries a type filter, used during pointer analysis */ public interface FilteredPointerKey extends PointerKey { public interface TypeFilter extends ContextItem { boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R); boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R); boolean isRootFilter(); } public class SingleClassFilter implements TypeFilter { private final IClass concreteType; public SingleClassFilter(IClass concreteType) { this.concreteType = concreteType; } @Override public String toString() { return "SingleClassFilter: " + concreteType; } public IClass getConcreteType() { return concreteType; } @Override public int hashCode() { return concreteType.hashCode(); } @Override public boolean equals(Object o) { return (o instanceof SingleClassFilter) && ((SingleClassFilter) o).getConcreteType().equals(concreteType); } @Override public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { IntSet f = system.getInstanceKeysForClass(concreteType); return (f == null) ? false : L.addAllInIntersection(R, f); } @Override public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { IntSet f = system.getInstanceKeysForClass(concreteType); // SJF: this is horribly inefficient. we really don't want to do // diffs in here. TODO: fix it. probably keep not(f) cached and // use addAllInIntersection return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f)); } @Override public boolean isRootFilter() { return concreteType.equals(concreteType.getClassHierarchy().getRootClass()); } } public class MultipleClassesFilter implements TypeFilter { private final IClass[] concreteType; public MultipleClassesFilter(IClass[] concreteType) { this.concreteType = concreteType; } @Override public String toString() { return "MultipleClassesFilter: " + Arrays.toString(concreteType); } public IClass[] getConcreteTypes() { return concreteType; } @Override public int hashCode() { return concreteType[0].hashCode(); } @Override public boolean equals(Object o) { if (! (o instanceof MultipleClassesFilter)) { return false; } MultipleClassesFilter f = (MultipleClassesFilter)o; if (concreteType.length != f.concreteType.length) { return false; } for(int i = 0; i < concreteType.length; i++) { if (! (concreteType[i].equals(f.concreteType[i]))) { return false; } } return true; } private IntSet bits(PropagationSystem system) { IntSet f = null; for(IClass cls : concreteType) { if (f == null) { f = system.getInstanceKeysForClass(cls); } else { f = f.union(system.getInstanceKeysForClass(cls)); } } return f; } @Override public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { IntSet f = bits(system); return (f == null) ? false : L.addAllInIntersection(R, f); } @Override public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { IntSet f = bits(system); // SJF: this is horribly inefficient. we really don't want to do // diffs in here. TODO: fix it. probably keep not(f) cached and // use addAllInIntersection return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f)); } @Override public boolean isRootFilter() { return concreteType.length == 1 && concreteType[0].getClassHierarchy().getRootClass().equals(concreteType[0]); } } public class SingleInstanceFilter implements TypeFilter { private final InstanceKey concreteType; public SingleInstanceFilter(InstanceKey concreteType) { this.concreteType = concreteType; } @Override public String toString() { return "SingleInstanceFilter: " + concreteType + " (" + concreteType.getClass() + ")"; } public InstanceKey getInstance() { return concreteType; } @Override public int hashCode() { return concreteType.hashCode(); } @Override public boolean equals(Object o) { return (o instanceof SingleInstanceFilter) && ((SingleInstanceFilter) o).getInstance().equals(concreteType); } @Override public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { int idx = system.findOrCreateIndexForInstanceKey(concreteType); if (R.contains(idx)) { if (!L.contains(idx)) { L.add(idx); return true; } } return false; } @Override public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { int idx = system.findOrCreateIndexForInstanceKey(concreteType); if (!R.contains(idx) || L.contains(idx)) { return L.addAll(R); } else { MutableIntSet copy = IntSetUtil.makeMutableCopy(R.getValue()); copy.remove(idx); return L.addAll(copy); } } @Override public boolean isRootFilter() { return false; } } public class TargetMethodFilter implements TypeFilter { private final IMethod targetMethod; public TargetMethodFilter(IMethod targetMethod) { this.targetMethod = targetMethod; } @Override public String toString() { return "TargetMethodFilter: " + targetMethod; } public IMethod getMethod() { return targetMethod; } @Override public int hashCode() { return targetMethod.hashCode(); } @Override public boolean equals(Object o) { return (o instanceof TargetMethodFilter) && ((TargetMethodFilter) o).getMethod().equals(targetMethod); } private class UpdateAction implements IntSetAction { private boolean result = false; private final PointsToSetVariable L; private final PropagationSystem system; private final boolean sense; private UpdateAction(PropagationSystem system, PointsToSetVariable L, boolean sense) { this.L = L; this.sense = sense; this.system = system; } @Override public void act(int i) { InstanceKey I = system.getInstanceKey(i); IClass C = I.getConcreteType(); if ((C.getMethod(targetMethod.getSelector()) == targetMethod) == sense) { if (!L.contains(i)) { result = true; L.add(i); } } } } @Override public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { if (R.getValue() == null) { return false; } else { UpdateAction act = new UpdateAction(system, L, true); R.getValue().foreach(act); return act.result; } } @Override public boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) { if (R.getValue() == null) { return false; } else { UpdateAction act = new UpdateAction(system, L, false); R.getValue().foreach(act); return act.result; } } @Override public boolean isRootFilter() { return false; } } /** * @return the class which should govern filtering of instances to which this pointer points, or null if no filtering needed */ public TypeFilter getTypeFilter(); }