adapt to checkcast change

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@3817 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
dolby-oss 2010-04-28 19:33:34 +00:00
parent c3ea5a8a86
commit 00871016cb
16 changed files with 273 additions and 140 deletions

View File

@ -35,6 +35,7 @@ import com.ibm.wala.shrikeBT.IComparisonInstruction;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.shrikeBT.IConversionInstruction;
import com.ibm.wala.shrikeBT.IGetInstruction;
import com.ibm.wala.shrikeBT.IInstanceofInstruction;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeBT.ILoadInstruction;
@ -42,7 +43,6 @@ import com.ibm.wala.shrikeBT.IPutInstruction;
import com.ibm.wala.shrikeBT.IShiftInstruction;
import com.ibm.wala.shrikeBT.IStoreInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.shrikeBT.InstanceofInstruction;
import com.ibm.wala.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrikeBT.NewInstruction;
import com.ibm.wala.shrikeBT.PopInstruction;
@ -1023,10 +1023,10 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
}
/**
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInstanceof(InstanceofInstruction)
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitInstanceof(IInstanceofInstruction)
*/
@Override
public void visitInstanceof(InstanceofInstruction instruction) {
public void visitInstanceof(IInstanceofInstruction instruction) {
workingState.pop();
workingState.push(UNANALYZED);
}

View File

@ -586,14 +586,20 @@ public class TypeInference extends SSAInference<TypeVariable> implements FixedPo
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
TypeReference type = instruction.getDeclaredResultType();
IClass klass = cha.lookupClass(type);
if (klass == null) {
// a type that cannot be loaded.
// be pessimistic
result = new DeclaredTypeOperator(BOTTOM);
} else {
result = new DeclaredTypeOperator(new ConeType(klass));
TypeAbstraction typeAbs = null;
for (TypeReference type : instruction.getDeclaredResultTypes()) {
IClass klass = cha.lookupClass(type);
if (klass == null) {
// a type that cannot be loaded.
// be pessimistic
typeAbs = BOTTOM;
} else {
if (typeAbs == null) {
typeAbs = new ConeType(klass);
} else {
typeAbs = typeAbs.meet(new ConeType(klass));
}
}
}
}

View File

@ -278,7 +278,9 @@ public class CodeScanner {
if (statements[i] != null) {
if (statements[i] instanceof SSACheckCastInstruction) {
SSACheckCastInstruction c = (SSACheckCastInstruction) statements[i];
result.add(c.getDeclaredResultType());
for(TypeReference t : c.getDeclaredResultTypes()) {
result.add(t);
}
}
}
}

View File

@ -16,6 +16,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import javax.naming.OperationNotSupportedException;
import com.ibm.wala.analysis.typeInference.JavaPrimitiveType;
import com.ibm.wala.analysis.typeInference.PrimitiveType;
import com.ibm.wala.ipa.cha.IClassHierarchy;
@ -62,6 +64,7 @@ import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.shrike.ShrikeUtil;
import com.ibm.wala.util.shrike.Exceptions.MethodResolutionFailure;
import com.ibm.wala.util.strings.Atom;
@ -128,14 +131,27 @@ public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Cons
};
}
public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference type) {
return new SSACheckCastInstruction(result, val, type) {
public SSACheckCastInstruction CheckCastInstruction(int result, int val, int[] typeValues) {
throw new UnsupportedOperationException();
}
public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference[] types) {
assert types.length == 1;
return new SSACheckCastInstruction(result, val, types) {
@Override
public Collection<TypeReference> getExceptionTypes() {
return getClassCastException();
}
};
}
public SSACheckCastInstruction CheckCastInstruction(int result, int val, int typeValue) {
return CheckCastInstruction(result, val, new int[]{ typeValue });
}
public SSACheckCastInstruction CheckCastInstruction(int result, int val, TypeReference type) {
return CheckCastInstruction(result, val, new TypeReference[]{ type });
}
public SSAComparisonInstruction ComparisonInstruction(IComparisonInstruction.Operator operator, int result, int val1, int val2) {
return new SSAComparisonInstruction(operator, result, val1, val2);

View File

@ -20,7 +20,6 @@ import java.util.List;
import java.util.Set;
import com.ibm.wala.shrikeBT.BytecodeConstants;
import com.ibm.wala.shrikeBT.CheckCastInstruction;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.Decoder;
import com.ibm.wala.shrikeBT.ExceptionHandler;
@ -30,6 +29,7 @@ import com.ibm.wala.shrikeBT.IGetInstruction;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.shrikeBT.IPutInstruction;
import com.ibm.wala.shrikeBT.ITypeTestInstruction;
import com.ibm.wala.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrikeBT.NewInstruction;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
@ -647,10 +647,11 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
}
@Override
public void visitCheckCast(CheckCastInstruction instruction) {
castTypes.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
public void visitCheckCast(ITypeTestInstruction instruction) {
for(String t : instruction.getTypes()) {
castTypes.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), t));
}
}
}
/**

View File

@ -103,6 +103,7 @@ import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.callgraph.propagation.ReturnValueKey;
import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.MultipleClassesFilter;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleClassFilter;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleInstanceFilter;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.TypeFilter;
@ -903,6 +904,21 @@ public class DemandRefinementPointsTo extends AbstractDemandPointsTo {
});
vals = tmp;
} else if (typeFilter instanceof MultipleClassesFilter) {
final MutableIntSet tmp = intSetFactory.make();
vals.foreach(new IntSetAction() {
public void act(int x) {
InstanceKeyAndState ikAndState = ikAndStates.getMappedObject(x);
for (IClass t : ((MultipleClassesFilter)typeFilter).getConcreteTypes()) {
if (cha.isAssignableFrom(t, ikAndState.getInstanceKey().getConcreteType())) {
tmp.add(x);
}
}
}
});
vals = tmp;
} else if (typeFilter instanceof SingleInstanceFilter) {
final InstanceKey theOnlyInstanceKey = ((SingleInstanceFilter) typeFilter).getInstance();
final MutableIntSet tmp = intSetFactory.make();

View File

@ -213,34 +213,23 @@ public class DemandPointerFlowGraph extends AbstractDemandFlowGraph implements I
*/
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
// Assertions.UNREACHABLE();
IClass cls = cha.lookupClass(instruction.getDeclaredResultType());
PointerKey result = null;
if (cls == null) {
// warnings.add(
// CheckcastFailure.create(instruction.getDeclaredResultType()));
// we failed to find the type.
// conservatively it would make sense to ignore the filter and
// be
// conservative, assuming
// java.lang.Object.
// however, this breaks the invariants downstream that assume
// every
// variable is
// strongly typed ... we can't have bad types flowing around.
// since things are broken anyway, just give up.
// result = getPointerKeyForLocal(node,
// instruction.getResult());
return;
} else {
FilteredPointerKey.SingleClassFilter singleClassFilter = new FilteredPointerKey.SingleClassFilter(cls);
result = heapModel.getPointerKeyForLocal(node, instruction.getResult());
PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal());
g.addNode(result);
g.addNode(value);
g.addEdge(result, value, AssignLabel.make(singleClassFilter));
Set<IClass> types = HashSetFactory.make();
for(TypeReference t : instruction.getDeclaredResultTypes()) {
IClass cls = cha.lookupClass(t);
if (cls == null) {
return;
} else {
types.add(cls);
}
}
FilteredPointerKey.MultipleClassesFilter filter = new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ]));
PointerKey result = heapModel.getPointerKeyForLocal(node, instruction.getResult());
PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal());
g.addNode(result);
g.addNode(value);
g.addEdge(result, value, AssignLabel.make(filter));
}
/*

View File

@ -79,6 +79,8 @@ import com.ibm.wala.ssa.SSAUnaryOpInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.ssa.SSAInstruction.Visitor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.MapUtil;
import com.ibm.wala.util.debug.Assertions;
@ -186,32 +188,24 @@ public class DemandValueFlowGraph extends AbstractDemandFlowGraph {
*/
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
// Assertions.UNREACHABLE();
IClass cls = cha.lookupClass(instruction.getDeclaredResultType());
PointerKey result = null;
if (cls == null) {
// warnings.add(
// CheckcastFailure.create(instruction.getDeclaredResultType()));
// we failed to find the type.
// conservatively it would make sense to ignore the filter and
// be
// conservative, assuming
// java.lang.Object.
// however, this breaks the invariants downstream that assume
// every
// variable is
// strongly typed ... we can't have bad types flowing around.
// since things are broken anyway, just give up.
// result = getPointerKeyForLocal(node,
// instruction.getResult());
return;
} else {
result = heapModel.getFilteredPointerKeyForLocal(node, instruction.getResult(), new FilteredPointerKey.SingleClassFilter(
cls));
Set<IClass> types = HashSetFactory.make();
for(TypeReference t : instruction.getDeclaredResultTypes()) {
IClass cls = cha.lookupClass(t);
if (cls == null) {
return;
} else {
types.add(cls);
}
}
PointerKey result = heapModel.getFilteredPointerKeyForLocal(node,
instruction.getResult(),
new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])) );
PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal());
// TODO actually use the cast type
addNode(result);
addNode(value);
addEdge(result, value, AssignLabel.noFilter());

View File

@ -732,27 +732,22 @@ public class SimpleDemandPointerFlowGraph extends SlowSparseNumberedGraph<Object
*/
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
// Assertions.UNREACHABLE();
IClass cls = cha.lookupClass(instruction.getDeclaredResultType());
PointerKey result = null;
if (cls == null) {
// warnings.add(
// CheckcastFailure.create(instruction.getDeclaredResultType()));
// we failed to find the type.
// conservatively it would make sense to ignore the filter and be
// conservative, assuming
// java.lang.Object.
// however, this breaks the invariants downstream that assume every
// variable is
// strongly typed ... we can't have bad types flowing around.
// since things are broken anyway, just give up.
// result = getPointerKeyForLocal(node, instruction.getResult());
return;
} else {
result = heapModel.getFilteredPointerKeyForLocal(node, instruction.getResult(), new FilteredPointerKey.SingleClassFilter(
cls));
Set<IClass> types = HashSetFactory.make();
for(TypeReference t : instruction.getDeclaredResultTypes()) {
IClass cls = cha.lookupClass(t);
if (cls == null) {
return;
} else {
types.add(cls);
}
}
PointerKey result = heapModel.getFilteredPointerKeyForLocal(node,
instruction.getResult(),
new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])) );
PointerKey value = heapModel.getPointerKeyForLocal(node, instruction.getVal());
// TODO actually use the cast type
addNode(result);

View File

@ -330,10 +330,10 @@ public abstract class AbstractRootMethod extends SyntheticMethod {
return result;
}
public int addCheckcast(TypeReference type, int rv) {
public int addCheckcast(TypeReference[] types, int rv) {
int lv = nextLocal++;
statements.add(insts.CheckCastInstruction(lv, rv, type));
statements.add(insts.CheckCastInstruction(lv, rv, types));
return lv;
}

View File

@ -16,11 +16,13 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.analysis.reflection.JavaTypeContext;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
@ -350,5 +352,37 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> imple
protected NodeManager<CGNode> getNodeManager() {
return nodeManager;
}
public void summarizeByPackage() {
Map<String, Integer> packages = HashMapFactory.make();
for(CGNode n : this) {
String nm = n.getMethod().getDeclaringClass().getName().toString() + "/" + n.getMethod().getName() + "/" + n.getContext().getClass().toString();
if (n.getContext() instanceof ReceiverInstanceContext) {
nm = nm + "/" + ((ReceiverInstanceContext)n.getContext()).getReceiver().getConcreteType().getName();
} else if (n.getContext() instanceof JavaTypeContext) {
nm = nm + "/" + ((JavaTypeContext)n.getContext()).getType().getTypeReference().getName();
}
do {
if (packages.containsKey(nm)) {
packages.put(nm, 1 + packages.get(nm));
} else {
packages.put(nm, 1);
}
if (nm.indexOf('/') < 0) {
break;
}
nm = nm.substring(0, nm.lastIndexOf('/'));
} while (true);
}
System.err.println("dump of CG");
for(Map.Entry<String, Integer> e : packages.entrySet()) {
System.err.println(e.getValue().intValue() + " " + e.getKey());
}
}
}

View File

@ -72,6 +72,75 @@ public interface FilteredPointerKey extends PointerKey {
}
}
public class MultipleClassesFilter implements TypeFilter {
private final IClass[] concreteType;
public MultipleClassesFilter(IClass[] concreteType) {
this.concreteType = concreteType;
}
@Override
public String toString() {
return "SingleClassFilter: " + 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;
}
public boolean addFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R) {
IntSet f = bits(system);
return (f == null) ? false : L.addAllInIntersection(R, f);
}
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));
}
}
public class SingleInstanceFilter implements TypeFilter {
private final InstanceKey concreteType;

View File

@ -378,23 +378,25 @@ public class PointerAnalysisImpl extends AbstractPointerAnalysis {
PointerKey rhs = pointerKeys.getPointerKeyForLocal(node, instruction.getVal());
OrdinalSet<InstanceKey> rhsSet = getPointsToSet(rhs);
MutableSparseIntSet S = MutableSparseIntSet.makeEmpty();
IClass klass = getCallGraph().getClassHierarchy().lookupClass(instruction.getDeclaredResultType());
if (klass == null) {
// could not find the type. conservatively assume Object
return rhsSet;
} else {
if (klass.isInterface()) {
for (Iterator it = rhsSet.iterator(); it.hasNext();) {
InstanceKey ik = (InstanceKey) it.next();
if (getCallGraph().getClassHierarchy().implementsInterface(ik.getConcreteType(), klass)) {
S.add(getInstanceKeyMapping().getMappedIndex(ik));
}
}
for (TypeReference t : instruction.getDeclaredResultTypes()) {
IClass klass = getCallGraph().getClassHierarchy().lookupClass(t);
if (klass == null) {
// could not find the type. conservatively assume Object
return rhsSet;
} else {
for (Iterator it = rhsSet.iterator(); it.hasNext();) {
InstanceKey ik = (InstanceKey) it.next();
if (getCallGraph().getClassHierarchy().isSubclassOf(ik.getConcreteType(), klass)) {
S.add(getInstanceKeyMapping().getMappedIndex(ik));
if (klass.isInterface()) {
for (Iterator it = rhsSet.iterator(); it.hasNext();) {
InstanceKey ik = (InstanceKey) it.next();
if (getCallGraph().getClassHierarchy().implementsInterface(ik.getConcreteType(), klass)) {
S.add(getInstanceKeyMapping().getMappedIndex(ik));
}
}
} else {
for (Iterator it = rhsSet.iterator(); it.hasNext();) {
InstanceKey ik = (InstanceKey) it.next();
if (getCallGraph().getClassHierarchy().isSubclassOf(ik.getConcreteType(), klass)) {
S.add(getInstanceKeyMapping().getMappedIndex(ik));
}
}
}
}

View File

@ -113,11 +113,13 @@ public class ReflectionHandler {
for (Statement st : casts) {
SSACheckCastInstruction c = (SSACheckCastInstruction) ((NormalStatement) st).getInstruction();
TypeReference type = c.getDeclaredResultType();
IClass klass = cha.lookupClass(type);
if (klass != null) {
if (contextInterpreter.recordFactoryType(returnStatement.getNode(), klass)) {
result.add(returnStatement.getNode());
for (TypeReference type : c.getDeclaredResultTypes()) {
IClass klass = cha.lookupClass(type);
if (klass != null) {
if (contextInterpreter.recordFactoryType(returnStatement.getNode(), klass)) {
result.add(returnStatement.getNode());
}
}
}
}

View File

@ -739,23 +739,24 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
*/
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
IClass cls = getClassHierarchy().lookupClass(instruction.getDeclaredResultType());
PointerKey result = null;
if (cls == null) {
Warnings.add(CheckcastFailure.create(instruction.getDeclaredResultType()));
// we failed to find the type.
// conservatively it would make sense to ignore the filter and be
// conservative, assuming
// java.lang.Object.
// however, this breaks the invariants downstream that assume every
// variable is
// strongly typed ... we can't have bad types flowing around.
// since things are broken anyway, just give up.
// result = getPointerKeyForLocal(node, instruction.getResult());
return;
} else {
result = getFilteredPointerKeyForLocal(instruction.getResult(), new FilteredPointerKey.SingleClassFilter(cls));
boolean isRoot = false;
Set<IClass> types = HashSetFactory.make();
for(TypeReference t : instruction.getDeclaredResultTypes()) {
IClass cls = getClassHierarchy().lookupClass(t);
if (cls == null) {
Warnings.add(CheckcastFailure.create(t));
return;
} else {
if (isRootType(cls)) {
isRoot = true;
}
types.add(cls);
}
}
PointerKey result = getFilteredPointerKeyForLocal(instruction.getResult(), new FilteredPointerKey.MultipleClassesFilter(types.toArray(new IClass[ types.size() ])));
PointerKey value = getPointerKeyForLocal(instruction.getVal());
if (hasNoInterestingUses(instruction.getDef())) {
@ -764,23 +765,27 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
if (contentsAreInvariant(symbolTable, du, instruction.getVal())) {
system.recordImplicitPointsToSet(value);
InstanceKey[] ik = getInvariantContents(instruction.getVal());
if (cls.isInterface()) {
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
if (getClassHierarchy().implementsInterface(ik[i].getConcreteType(), cls)) {
system.newConstraint(result, ik[i]);
for(TypeReference t : instruction.getDeclaredResultTypes()) {
IClass cls = getClassHierarchy().lookupClass(t);
if (cls.isInterface()) {
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
if (getClassHierarchy().implementsInterface(ik[i].getConcreteType(), cls)) {
system.newConstraint(result, ik[i]);
}
}
}
} else {
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
if (getClassHierarchy().isSubclassOf(ik[i].getConcreteType(), cls)) {
system.newConstraint(result, ik[i]);
} else {
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
if (getClassHierarchy().isSubclassOf(ik[i].getConcreteType(), cls)) {
system.newConstraint(result, ik[i]);
}
}
}
}
} else {
if (isRootType(cls)) {
if (isRoot) {
system.newConstraint(result, assignOperator, value);
} else {
system.newConstraint(result, getBuilder().filterOperator, value);

View File

@ -55,6 +55,8 @@ public class StandardSolver extends AbstractPointsToSolver {
}
getBuilder().addConstraintsFromNewNodes();
// getBuilder().callGraph.summarizeByPackage();
if (DEBUG) {
System.err.println("handling reflection");
}