WALA/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/SSAPropagationCallGraphBuil...

2233 lines
85 KiB
Java

/*******************************************************************************
* 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.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.ibm.wala.analysis.reflection.CloneInterpreter;
import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.cfg.IBasicBlock;
import com.ibm.wala.classLoader.ArrayClass;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod;
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod;
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder.ConstraintVisitor.InvariantComputer;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeBT.ConditionalBranchInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSAAbstractThrowInstruction;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
import com.ibm.wala.ssa.SSACFG;
import com.ibm.wala.ssa.SSACFG.BasicBlock;
import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock;
import com.ibm.wala.ssa.SSACheckCastInstruction;
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
import com.ibm.wala.ssa.SSAGetInstruction;
import com.ibm.wala.ssa.SSAInstanceofInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.SSALoadMetadataInstruction;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.ssa.SSAPiInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.ssa.SSAReturnInstruction;
import com.ibm.wala.ssa.SSAThrowInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.CancelRuntimeException;
import com.ibm.wala.util.MonitorUtil;
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.functions.VoidFunction;
import com.ibm.wala.util.intset.IntIterator;
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;
import com.ibm.wala.util.ref.ReferenceCleanser;
import com.ibm.wala.util.warnings.Warning;
import com.ibm.wala.util.warnings.Warnings;
/**
* This abstract base class provides the general algorithm for a call graph builder that relies on propagation through an iterative
* dataflow solver, and constraints generated by statements in SSA form.
*
* TODO: This implementation currently keeps all points to sets live ... even those for local variables that do not span
* interprocedural boundaries. This may be too space-inefficient .. we can consider recomputing local sets on demand.
*/
public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGraphBuilder implements HeapModel {
private final static boolean DEBUG = false;
private final static boolean DEBUG_MULTINEWARRAY = DEBUG | false;
/**
* Should we periodically clear out soft reference caches in an attempt to help the GC?
*/
public final static boolean PERIODIC_WIPE_SOFT_CACHES = true;
/**
* Interval which defines the period to clear soft reference caches
*/
public final static int WIPE_SOFT_CACHE_INTERVAL = 2500;
/**
* Counter for wiping soft caches
*/
private static int wipeCount = 0;
/**
* use type inference to avoid unnecessary filter constraints?
*/
// private final static boolean OPTIMIZE_WITH_TYPE_INFERENCE = true;
/**
* An optimization: if we can locally determine the final solution for a points-to set, then don't actually create the points-to
* set, but instead short circuit by propagating the final solution to all such uses.
*
* String constants are ALWAYS considered invariant, regardless of the value of this flag.
*
* However, if this flag is set, then the solver is more aggressive identifying invariants.
*
* Doesn't play well with pre-transitive solver; turning off for now.
*/
private final static boolean SHORT_CIRCUIT_INVARIANT_SETS = true;
/**
* An optimization: if we can locally determine that a particular pointer p has exactly one use, then we don't actually create the
* points-to-set for p, but instead short-circuit by propagating the final solution to the unique use.
*
* Doesn't play well with pre-transitive solver; turning off for now.
*/
protected final static boolean SHORT_CIRCUIT_SINGLE_USES = true;
/**
* Should we change calls to clone() to assignments?
*/
private final boolean clone2Assign = false;
/**
* Cache for efficiency
*/
private final static Selector cloneSelector = CloneInterpreter.CLONE.getSelector();
/**
* set of class whose clinits have already been processed
*/
private final Set<IClass> clinitVisited = HashSetFactory.make();
private IProgressMonitor monitor;
protected SSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
PointerKeyFactory pointerKeyFactory) {
super(cha, options, cache, pointerKeyFactory);
// this.usePreTransitiveSolver = options.usePreTransitiveSolver();
}
public SSAContextInterpreter getCFAContextInterpreter() {
return (SSAContextInterpreter) getContextInterpreter();
}
/**
* @param node
* @param x
* @param type
* @return the instance key that represents the exception of type _type_ thrown by a particular PEI.
* @throws IllegalArgumentException if ikFactory is null
*/
public static InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter x, TypeReference type, InstanceKeyFactory ikFactory) {
if (ikFactory == null) {
throw new IllegalArgumentException("ikFactory is null");
}
return ikFactory.getInstanceKeyForPEI(node, x, type);
}
/**
* Visit all instructions in a node, and add dataflow constraints induced by each statement in the SSA form.
* @throws CancelException
*
* @see com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder#addConstraintsFromNode(com.ibm.wala.ipa.callgraph.CGNode)
*/
@Override
protected boolean addConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException {
this.monitor = monitor;
if (haveAlreadyVisited(node)) {
return false;
} else {
markAlreadyVisited(node);
}
return unconditionallyAddConstraintsFromNode(node, monitor);
}
@Override
protected boolean unconditionallyAddConstraintsFromNode(CGNode node, IProgressMonitor monitor) throws CancelException {
this.monitor = monitor;
if (PERIODIC_WIPE_SOFT_CACHES) {
wipeCount++;
if (wipeCount >= WIPE_SOFT_CACHE_INTERVAL) {
wipeCount = 0;
ReferenceCleanser.clearSoftCaches();
}
}
if (DEBUG) {
System.err.println("\n\nAdd constraints from node " + node);
}
IR ir = getCFAContextInterpreter().getIR(node);
if (DEBUG) {
if (ir == null) {
System.err.println("\n No statements\n");
} else {
try {
System.err.println(ir.toString());
} catch (Error e) {
e.printStackTrace();
}
}
}
if (ir == null) {
return false;
}
addNodeInstructionConstraints(node, monitor);
DefUse du = getCFAContextInterpreter().getDU(node);
addNodePassthruExceptionConstraints(node, ir, du);
// conservatively assume something changed
return true;
}
/**
* @return a visitor to examine instructions in the ir
*/
protected ConstraintVisitor makeVisitor(CGNode node) {
return new ConstraintVisitor(this, node);
}
/**
* Add pointer flow constraints based on instructions in a given node
* @throws CancelException
*/
protected void addNodeInstructionConstraints(CGNode node, IProgressMonitor monitor) throws CancelException {
this.monitor = monitor;
ConstraintVisitor v = makeVisitor(node);
IR ir = v.ir;
ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg = ir.getControlFlowGraph();
for (Iterator<ISSABasicBlock> x = cfg.iterator(); x.hasNext();) {
BasicBlock b = (BasicBlock) x.next();
addBlockInstructionConstraints(node, cfg, b, v, monitor);
if (wasChanged(node)) {
return;
}
}
}
/**
* Add constraints for a particular basic block.
* @throws CancelException
*/
protected void addBlockInstructionConstraints(CGNode node, ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg, BasicBlock b,
ConstraintVisitor v, IProgressMonitor monitor) throws CancelException {
this.monitor = monitor;
v.setBasicBlock(b);
// visit each instruction in the basic block.
for (Iterator<SSAInstruction> it = b.iterator(); it.hasNext();) {
MonitorUtil.throwExceptionIfCanceled(monitor);
SSAInstruction s = it.next();
if (s != null) {
s.visit(v);
if (wasChanged(node)) {
return;
}
}
}
addPhiConstraints(node, cfg, b, v);
}
private void addPhiConstraints(CGNode node, ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg, BasicBlock b,
ConstraintVisitor v) {
// visit each phi instruction in each successor block
for (Iterator sbs = cfg.getSuccNodes(b); sbs.hasNext();) {
BasicBlock sb = (BasicBlock) sbs.next();
if (!sb.hasPhi()) {
continue;
}
int n = 0;
for (Iterator<? extends IBasicBlock> back = cfg.getPredNodes(sb); back.hasNext(); n++) {
if (back.next() == b) {
break;
}
}
assert n < cfg.getPredNodeCount(sb);
for (Iterator<? extends SSAInstruction> phis = sb.iteratePhis(); phis.hasNext();) {
SSAPhiInstruction phi = (SSAPhiInstruction) phis.next();
if (phi == null) {
continue;
}
PointerKey def = getPointerKeyForLocal(node, phi.getDef());
if (hasNoInterestingUses(node, phi.getDef(), v.du)) {
system.recordImplicitPointsToSet(def);
} else {
// the following test restricts the constraints to reachable
// paths, according to verification constraints
if (phi.getUse(n) > 0) {
PointerKey use = getPointerKeyForLocal(node, phi.getUse(n));
if (contentsAreInvariant(v.symbolTable, v.du, phi.getUse(n))) {
system.recordImplicitPointsToSet(use);
InstanceKey[] ik = getInvariantContents(v.symbolTable, v.du, node, phi.getUse(n), this);
for (int i = 0; i < ik.length; i++) {
system.newConstraint(def, ik[i]);
}
} else {
system.newConstraint(def, assignOperator, use);
}
}
}
}
}
}
/**
* Add constraints to represent the flow of exceptions to the exceptional return value for this node
*
* @param node
* @param ir
*/
protected void addNodePassthruExceptionConstraints(CGNode node, IR ir, DefUse du) {
// add constraints relating to thrown exceptions that reach the exit block.
List<ProgramCounter> peis = getIncomingPEIs(ir, ir.getExitBlock());
PointerKey exception = getPointerKeyForExceptionalReturnValue(node);
TypeReference throwableType = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getThrowableType();
IClass c = node.getClassHierarchy().lookupClass(throwableType);
addExceptionDefConstraints(ir, du, node, peis, exception, Collections.singleton(c));
}
/**
* Generate constraints which assign exception values into an exception pointer
*
* @param node governing node
* @param peis list of PEI instructions
* @param exceptionVar PointerKey representing a pointer to an exception value
* @param catchClasses the types "caught" by the exceptionVar
*/
private void addExceptionDefConstraints(IR ir, DefUse du, CGNode node, List<ProgramCounter> peis, PointerKey exceptionVar,
Set<IClass> catchClasses) {
if (DEBUG) {
System.err.println("Add exception def constraints for node " + node);
}
for (Iterator<ProgramCounter> it = peis.iterator(); it.hasNext();) {
ProgramCounter peiLoc = it.next();
if (DEBUG) {
System.err.println("peiLoc: " + peiLoc);
}
SSAInstruction pei = ir.getPEI(peiLoc);
if (DEBUG) {
System.err.println("Add exceptions from pei " + pei);
}
if (pei instanceof SSAAbstractInvokeInstruction) {
SSAAbstractInvokeInstruction s = (SSAAbstractInvokeInstruction) pei;
PointerKey e = getPointerKeyForLocal(node, s.getException());
if (!SHORT_CIRCUIT_SINGLE_USES || !hasUniqueCatchBlock(s, ir)) {
addAssignmentsForCatchPointerKey(exceptionVar, catchClasses, e);
}// else {
// System.err.println("SKIPPING ASSIGNMENTS TO " + exceptionVar + " FROM " +
// e);
// }
} else if (pei instanceof SSAAbstractThrowInstruction) {
SSAAbstractThrowInstruction s = (SSAAbstractThrowInstruction) pei;
PointerKey e = getPointerKeyForLocal(node, s.getException());
if (contentsAreInvariant(ir.getSymbolTable(), du, s.getException())) {
InstanceKey[] ik = getInvariantContents(ir.getSymbolTable(), du, node, s.getException(), this);
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
assignInstanceToCatch(exceptionVar, catchClasses, ik[i]);
}
} else {
addAssignmentsForCatchPointerKey(exceptionVar, catchClasses, e);
}
}
// Account for those exceptions for which we do not actually have a
// points-to set for
// the pei, but just instance keys
Collection<TypeReference> types = pei.getExceptionTypes();
if (types != null) {
for (Iterator<TypeReference> it2 = types.iterator(); it2.hasNext();) {
TypeReference type = it2.next();
if (type != null) {
InstanceKey ik = getInstanceKeyForPEI(node, peiLoc, type, instanceKeyFactory);
if (ik == null) {
continue;
}
assert ik instanceof ConcreteTypeKey : "uh oh: need to implement getCaughtException constraints for instance " + ik;
ConcreteTypeKey ck = (ConcreteTypeKey) ik;
IClass klass = ck.getType();
if (PropagationCallGraphBuilder.catches(catchClasses, klass, cha)) {
system.newConstraint(exceptionVar, getInstanceKeyForPEI(node, peiLoc, type, instanceKeyFactory));
}
}
}
}
}
}
/**
* @return true iff there's a unique catch block which catches all exceptions thrown by a certain call site.
*/
protected static boolean hasUniqueCatchBlock(SSAAbstractInvokeInstruction call, IR ir) {
ISSABasicBlock[] bb = ir.getBasicBlocksForCall(call.getCallSite());
if (bb.length == 1) {
Iterator it = ir.getControlFlowGraph().getExceptionalSuccessors(bb[0]).iterator();
// check that there's exactly one element in the iterator
if (it.hasNext()) {
it.next();
return (!it.hasNext());
}
}
return false;
}
/**
* precondition: hasUniqueCatchBlock(call,node,cg)
*
* @return the unique pointer key which catches the exceptions thrown by a call
* @throws IllegalArgumentException if ir == null
* @throws IllegalArgumentException if call == null
*/
public PointerKey getUniqueCatchKey(SSAAbstractInvokeInstruction call, IR ir, CGNode node) throws IllegalArgumentException,
IllegalArgumentException {
if (call == null) {
throw new IllegalArgumentException("call == null");
}
if (ir == null) {
throw new IllegalArgumentException("ir == null");
}
ISSABasicBlock[] bb = ir.getBasicBlocksForCall(call.getCallSite());
assert bb.length == 1;
SSACFG.BasicBlock cb = (BasicBlock) ir.getControlFlowGraph().getExceptionalSuccessors(bb[0]).iterator().next();
if (cb.isExitBlock()) {
return getPointerKeyForExceptionalReturnValue(node);
} else {
SSACFG.ExceptionHandlerBasicBlock ehbb = (ExceptionHandlerBasicBlock) cb;
SSAGetCaughtExceptionInstruction ci = ehbb.getCatchInstruction();
return getPointerKeyForLocal(node, ci.getDef());
}
}
/**
* @return a List of Instructions that may transfer control to bb via an exceptional edge
* @throws IllegalArgumentException if ir is null
*/
public static List<ProgramCounter> getIncomingPEIs(IR ir, ISSABasicBlock bb) {
if (ir == null) {
throw new IllegalArgumentException("ir is null");
}
if (DEBUG) {
System.err.println("getIncomingPEIs " + bb);
}
ControlFlowGraph<SSAInstruction, ISSABasicBlock> g = ir.getControlFlowGraph();
List<ProgramCounter> result = new ArrayList<ProgramCounter>(g.getPredNodeCount(bb));
for (Iterator it = g.getPredNodes(bb); it.hasNext();) {
BasicBlock pred = (BasicBlock) it.next();
if (DEBUG) {
System.err.println("pred: " + pred);
}
if (pred.isEntryBlock())
continue;
int index = pred.getLastInstructionIndex();
SSAInstruction pei = ir.getInstructions()[index];
// Note: pei might be null if pred is unreachable.
// TODO: consider pruning CFG for unreachable blocks.
if (pei != null && pei.isPEI()) {
if (DEBUG) {
System.err.println("PEI: " + pei + " index " + index + " PC " + g.getProgramCounter(index));
}
result.add(new ProgramCounter(g.getProgramCounter(index)));
}
}
return result;
}
/**
* A visitor that generates constraints based on statements in SSA form.
*/
protected static class ConstraintVisitor extends SSAInstruction.Visitor {
/**
* The governing call graph builder. This field is used instead of an inner class in order to allow more flexible reuse of this
* visitor in subclasses
*/
protected final SSAPropagationCallGraphBuilder builder;
/**
* The node whose statements we are currently traversing
*/
protected final CGNode node;
/**
* The governing call graph.
*/
private final ExplicitCallGraph callGraph;
/**
* The governing IR
*/
protected final IR ir;
/**
* The governing propagation system, into which constraints are added
*/
protected final PropagationSystem system;
/**
* The basic block currently being processed
*/
protected ISSABasicBlock basicBlock;
/**
* Governing symbol table
*/
protected final SymbolTable symbolTable;
/**
* Def-use information
*/
protected final DefUse du;
public ConstraintVisitor(SSAPropagationCallGraphBuilder builder, CGNode node) {
this.builder = builder;
this.node = node;
this.callGraph = builder.getCallGraph();
this.system = builder.getPropagationSystem();
this.ir = builder.getCFAContextInterpreter().getIR(node);
this.symbolTable = this.ir.getSymbolTable();
this.du = builder.getCFAContextInterpreter().getDU(node);
assert symbolTable != null;
}
protected SSAPropagationCallGraphBuilder getBuilder() {
return builder;
}
protected AnalysisOptions getOptions() {
return builder.options;
}
protected AnalysisCache getAnalysisCache() {
return builder.getAnalysisCache();
}
public PointerKey getPointerKeyForLocal(int valueNumber) {
return getBuilder().getPointerKeyForLocal(node, valueNumber);
}
public FilteredPointerKey getFilteredPointerKeyForLocal(int valueNumber, FilteredPointerKey.TypeFilter filter) {
return getBuilder().getFilteredPointerKeyForLocal(node, valueNumber, filter);
}
public PointerKey getPointerKeyForReturnValue() {
return getBuilder().getPointerKeyForReturnValue(node);
}
public PointerKey getPointerKeyForExceptionalReturnValue() {
return getBuilder().getPointerKeyForExceptionalReturnValue(node);
}
public PointerKey getPointerKeyForStaticField(IField f) {
return getBuilder().getPointerKeyForStaticField(f);
}
public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField f) {
return getBuilder().getPointerKeyForInstanceField(I, f);
}
public PointerKey getPointerKeyForArrayContents(InstanceKey I) {
return getBuilder().getPointerKeyForArrayContents(I);
}
public InstanceKey getInstanceKeyForAllocation(NewSiteReference allocation) {
return getBuilder().getInstanceKeyForAllocation(node, allocation);
}
public InstanceKey getInstanceKeyForMultiNewArray(NewSiteReference allocation, int dim) {
return getBuilder().getInstanceKeyForMultiNewArray(node, allocation, dim);
}
public <T> InstanceKey getInstanceKeyForConstant(T S) {
TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S);
return getBuilder().getInstanceKeyForConstant(type, S);
}
public InstanceKey getInstanceKeyForPEI(ProgramCounter instr, TypeReference type) {
return getBuilder().getInstanceKeyForPEI(node, instr, type);
}
public InstanceKey getInstanceKeyForClassObject(TypeReference type) {
return getBuilder().getInstanceKeyForClassObject(type);
}
public CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) {
return getBuilder().getTargetForCall(caller, site, recv, iKey);
}
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) {
return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber);
}
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber[]) {
return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber);
}
protected InstanceKey[] getInvariantContents(int valueNumber) {
return getInvariantContents(ir.getSymbolTable(), du, node, valueNumber);
}
protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber) {
return getBuilder().getInvariantContents(symbolTable, du, node, valueNumber, getBuilder());
}
protected IClassHierarchy getClassHierarchy() {
return getBuilder().getClassHierarchy();
}
protected boolean hasNoInterestingUses(int vn) {
return getBuilder().hasNoInterestingUses(node, vn, du);
}
protected boolean isRootType(IClass klass) {
return getBuilder().isRootType(klass);
}
/*
* @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitArrayLoad(com.ibm.wala.ssa.SSAArrayLoadInstruction)
*/
@Override
public void visitArrayLoad(SSAArrayLoadInstruction instruction) {
// skip arrays of primitive type
if (instruction.typeIsPrimitive()) {
return;
}
doVisitArrayLoad(instruction.getDef(), instruction.getArrayRef());
}
protected void doVisitArrayLoad(int def, int arrayRef) {
PointerKey result = getPointerKeyForLocal(def);
PointerKey arrayRefPtrKey = getPointerKeyForLocal(arrayRef);
if (hasNoInterestingUses(def)) {
system.recordImplicitPointsToSet(result);
} else {
if (contentsAreInvariant(symbolTable, du, arrayRef)) {
system.recordImplicitPointsToSet(arrayRefPtrKey);
InstanceKey[] ik = getInvariantContents(arrayRef);
for (int i = 0; i < ik.length; i++) {
if (!representsNullType(ik[i])) {
system.findOrCreateIndexForInstanceKey(ik[i]);
PointerKey p = getPointerKeyForArrayContents(ik[i]);
if (p == null) {
} else {
system.newConstraint(result, assignOperator, p);
}
}
}
} else {
assert !system.isUnified(result);
assert !system.isUnified(arrayRefPtrKey);
system.newSideEffect(getBuilder().new ArrayLoadOperator(system.findOrCreatePointsToSet(result)), arrayRefPtrKey);
}
}
}
/*
* @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitArrayStore(com.ibm.wala.ssa.SSAArrayStoreInstruction)
*/
public void doVisitArrayStore(int arrayRef, int value) {
// (requires the creation of assign constraints as
// the set points-to(a[]) grows.)
PointerKey valuePtrKey = getPointerKeyForLocal(value);
PointerKey arrayRefPtrKey = getPointerKeyForLocal(arrayRef);
// if (!supportFullPointerFlowGraph &&
// contentsAreInvariant(instruction.getArrayRef())) {
if (contentsAreInvariant(symbolTable, du, arrayRef)) {
system.recordImplicitPointsToSet(arrayRefPtrKey);
InstanceKey[] ik = getInvariantContents(arrayRef);
for (int i = 0; i < ik.length; i++) {
if (!representsNullType(ik[i])) {
system.findOrCreateIndexForInstanceKey(ik[i]);
PointerKey p = getPointerKeyForArrayContents(ik[i]);
IClass contents = ((ArrayClass) ik[i].getConcreteType()).getElementClass();
if (p == null) {
} else {
if (contentsAreInvariant(symbolTable, du, value)) {
system.recordImplicitPointsToSet(valuePtrKey);
InstanceKey[] vk = getInvariantContents(value);
for (int j = 0; j < vk.length; j++) {
system.findOrCreateIndexForInstanceKey(vk[j]);
if (vk[j].getConcreteType() != null) {
if (getClassHierarchy().isAssignableFrom(contents, vk[j].getConcreteType())) {
system.newConstraint(p, vk[j]);
}
}
}
} else {
if (isRootType(contents)) {
system.newConstraint(p, assignOperator, valuePtrKey);
} else {
system.newConstraint(p, getBuilder().filterOperator, valuePtrKey);
}
}
}
}
}
} else {
if (contentsAreInvariant(symbolTable, du, value)) {
system.recordImplicitPointsToSet(valuePtrKey);
InstanceKey[] ik = getInvariantContents(value);
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
assert !system.isUnified(arrayRefPtrKey);
system.newSideEffect(getBuilder().new InstanceArrayStoreOperator(ik[i]), arrayRefPtrKey);
}
} else {
system.newSideEffect(getBuilder().new ArrayStoreOperator(system.findOrCreatePointsToSet(valuePtrKey)), arrayRefPtrKey);
}
}
}
@Override
public void visitArrayStore(SSAArrayStoreInstruction instruction) {
// skip arrays of primitive type
if (instruction.typeIsPrimitive()) {
return;
}
doVisitArrayStore(instruction.getArrayRef(), instruction.getValue());
}
/*
* @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitCheckCast(com.ibm.wala.ssa.SSACheckCastInstruction)
*/
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
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())) {
system.recordImplicitPointsToSet(result);
} else {
if (contentsAreInvariant(symbolTable, du, instruction.getVal())) {
system.recordImplicitPointsToSet(value);
InstanceKey[] ik = getInvariantContents(instruction.getVal());
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 {
if (isRoot) {
system.newConstraint(result, assignOperator, value);
} else {
system.newConstraint(result, getBuilder().filterOperator, value);
}
}
}
}
/*
* @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitReturn(com.ibm.wala.ssa.SSAReturnInstruction)
*/
@Override
public void visitReturn(SSAReturnInstruction instruction) {
// skip returns of primitive type
if (instruction.returnsPrimitiveType() || instruction.returnsVoid()) {
return;
}
if (DEBUG) {
System.err.println("visitReturn: " + instruction);
}
PointerKey returnValue = getPointerKeyForReturnValue();
PointerKey result = getPointerKeyForLocal(instruction.getResult());
if (contentsAreInvariant(symbolTable, du, instruction.getResult())) {
system.recordImplicitPointsToSet(result);
InstanceKey[] ik = getInvariantContents(instruction.getResult());
for (int i = 0; i < ik.length; i++) {
if (DEBUG) {
System.err.println("invariant contents: " + returnValue + " " + ik[i]);
}
system.newConstraint(returnValue, ik[i]);
}
} else {
system.newConstraint(returnValue, assignOperator, result);
}
}
/*
* @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitGet(com.ibm.wala.ssa.SSAGetInstruction)
*/
@Override
public void visitGet(SSAGetInstruction instruction) {
visitGetInternal(instruction.getDef(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField());
}
protected void visitGetInternal(int lval, int ref, boolean isStatic, FieldReference field) {
if (DEBUG) {
System.err.println("visitGet " + field);
}
// skip getfields of primitive type (optimisation)
if (field.getFieldType().isPrimitiveType()) {
return;
}
PointerKey def = getPointerKeyForLocal(lval);
assert def != null;
IField f = getClassHierarchy().resolveField(field);
if (f == null && callGraph.getFakeRootNode().getMethod().getDeclaringClass().getReference().equals(field.getDeclaringClass())) {
f = callGraph.getFakeRootNode().getMethod().getDeclaringClass().getField(field.getName());
}
if (f == null) {
return;
}
if (hasNoInterestingUses(lval)) {
system.recordImplicitPointsToSet(def);
} else {
if (isStatic) {
PointerKey fKey = getPointerKeyForStaticField(f);
system.newConstraint(def, assignOperator, fKey);
IClass klass = getClassHierarchy().lookupClass(field.getDeclaringClass());
if (klass == null) {
} else {
// side effect of getstatic: may call class initializer
if (DEBUG) {
System.err.println("getstatic call class init " + klass);
}
processClassInitializer(klass);
}
} else {
PointerKey refKey = getPointerKeyForLocal(ref);
// if (!supportFullPointerFlowGraph &&
// contentsAreInvariant(ref)) {
if (contentsAreInvariant(symbolTable, du, ref)) {
system.recordImplicitPointsToSet(refKey);
InstanceKey[] ik = getInvariantContents(ref);
for (int i = 0; i < ik.length; i++) {
if (!representsNullType(ik[i])) {
system.findOrCreateIndexForInstanceKey(ik[i]);
PointerKey p = getPointerKeyForInstanceField(ik[i], f);
system.newConstraint(def, assignOperator, p);
}
}
} else {
system.newSideEffect(getBuilder().new GetFieldOperator(f, system.findOrCreatePointsToSet(def)), refKey);
}
}
}
}
/*
* @see com.ibm.wala.ssa.Instruction.Visitor#visitPut(com.ibm.wala.ssa.PutInstruction)
*/
@Override
public void visitPut(SSAPutInstruction instruction) {
visitPutInternal(instruction.getVal(), instruction.getRef(), instruction.isStatic(), instruction.getDeclaredField());
}
public void visitPutInternal(int rval, int ref, boolean isStatic, FieldReference field) {
if (DEBUG) {
System.err.println("visitPut " + field);
}
// skip putfields of primitive type
if (field.getFieldType().isPrimitiveType()) {
return;
}
IField f = getClassHierarchy().resolveField(field);
if (f == null) {
if (DEBUG) {
System.err.println("Could not resolve field " + field);
}
Warnings.add(FieldResolutionFailure.create(field));
return;
}
assert isStatic || !symbolTable.isStringConstant(ref) : "put to string constant shouldn't be allowed?";
if (isStatic) {
processPutStatic(rval, field, f);
} else {
processPutField(rval, ref, f);
}
}
private void processPutField(int rval, int ref, IField f) {
assert !f.getFieldTypeReference().isPrimitiveType();
PointerKey refKey = getPointerKeyForLocal(ref);
PointerKey rvalKey = getPointerKeyForLocal(rval);
// if (!supportFullPointerFlowGraph &&
// contentsAreInvariant(rval)) {
if (contentsAreInvariant(symbolTable, du, rval)) {
system.recordImplicitPointsToSet(rvalKey);
InstanceKey[] ik = getInvariantContents(rval);
if (contentsAreInvariant(symbolTable, du, ref)) {
system.recordImplicitPointsToSet(refKey);
InstanceKey[] refk = getInvariantContents(ref);
for (int j = 0; j < refk.length; j++) {
if (!representsNullType(refk[j])) {
system.findOrCreateIndexForInstanceKey(refk[j]);
PointerKey p = getPointerKeyForInstanceField(refk[j], f);
for (int i = 0; i < ik.length; i++) {
system.newConstraint(p, ik[i]);
}
}
}
} else {
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
system.newSideEffect(getBuilder().new InstancePutFieldOperator(f, ik[i]), refKey);
}
}
} else {
if (contentsAreInvariant(symbolTable, du, ref)) {
system.recordImplicitPointsToSet(refKey);
InstanceKey[] refk = getInvariantContents(ref);
for (int j = 0; j < refk.length; j++) {
if (!representsNullType(refk[j])) {
system.findOrCreateIndexForInstanceKey(refk[j]);
PointerKey p = getPointerKeyForInstanceField(refk[j], f);
system.newConstraint(p, assignOperator, rvalKey);
}
}
} else {
if (DEBUG) {
System.err.println("adding side effect " + f);
}
system.newSideEffect(getBuilder().new PutFieldOperator(f, system.findOrCreatePointsToSet(rvalKey)), refKey);
}
}
}
private void processPutStatic(int rval, FieldReference field, IField f) {
PointerKey fKey = getPointerKeyForStaticField(f);
PointerKey rvalKey = getPointerKeyForLocal(rval);
// if (!supportFullPointerFlowGraph &&
// contentsAreInvariant(rval)) {
if (contentsAreInvariant(symbolTable, du, rval)) {
system.recordImplicitPointsToSet(rvalKey);
InstanceKey[] ik = getInvariantContents(rval);
for (int i = 0; i < ik.length; i++) {
system.newConstraint(fKey, ik[i]);
}
} else {
system.newConstraint(fKey, assignOperator, rvalKey);
}
if (DEBUG) {
System.err.println("visitPut class init " + field.getDeclaringClass() + " " + field);
}
// side effect of putstatic: may call class initializer
IClass klass = getClassHierarchy().lookupClass(field.getDeclaringClass());
if (klass == null) {
Warnings.add(FieldResolutionFailure.create(field));
} else {
processClassInitializer(klass);
}
}
/*
* @see com.ibm.wala.ssa.Instruction.Visitor#visitInvoke(com.ibm.wala.ssa.InvokeInstruction)
*/
@Override
public void visitInvoke(SSAInvokeInstruction instruction) {
visitInvokeInternal(instruction, new DefaultInvariantComputer());
}
protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction, InvariantComputer invs) {
if (DEBUG) {
System.err.println("visitInvoke: " + instruction);
}
PointerKey uniqueCatch = null;
if (hasUniqueCatchBlock(instruction, ir)) {
uniqueCatch = getBuilder().getUniqueCatchKey(instruction, ir, node);
}
InstanceKey[][] invariantParameters = invs.computeInvariantParameters(instruction);
if (instruction.getCallSite().isStatic()) {
for (CGNode n : getBuilder().getTargetsForCall(node, instruction.getCallSite(), invariantParameters)) {
getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch);
if (DEBUG) {
System.err.println("visitInvoke class init " + n);
}
// side effect of invoke: may call class initializer
processClassInitializer(n.getMethod().getDeclaringClass());
}
} else {
// Add a side effect that will fire when we determine a value
// for a dispatch parameter. This side effect will create a new node
// and new constraints based on the new callee context.
IntSet params = getBuilder().getContextSelector().getRelevantParameters(node, instruction.getCallSite());
if (! params.contains(0)) {
params = IntSetUtil.makeMutableCopy(params);
((MutableIntSet)params).add(0);
}
final int vns[] = new int[ params.size() ];
params.foreach(new IntSetAction() {
private int i = 0;
public void act(int x) {
vns[i++] = instruction.getUse(x);
}
});
if (contentsAreInvariant(symbolTable, du, vns)) {
for(CGNode n : getBuilder().getTargetsForCall(node, instruction.getCallSite(), invariantParameters)) {
getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch);
// side effect of invoke: may call class initializer
processClassInitializer(n.getMethod().getDeclaringClass());
}
} else {
if (DEBUG) {
System.err.println("Add side effect, dispatch to " + instruction + " for " + params);
}
final List<PointerKey> pks = new ArrayList<PointerKey>(params.size());
params.foreach(new IntSetAction() {
public void act(int x) {
if (!contentsAreInvariant(symbolTable, du, instruction.getUse(x))) {
pks.add(getBuilder().getPointerKeyForLocal(node, instruction.getUse(x)));
}
}
});
DispatchOperator dispatchOperator = getBuilder().new DispatchOperator(instruction, node,
invariantParameters, uniqueCatch, params);
system.newSideEffect(dispatchOperator, pks.toArray(new PointerKey[pks.size()]));
}
}
}
/*
* @see com.ibm.wala.ssa.Instruction.Visitor#visitNew(com.ibm.wala.ssa.NewInstruction)
*/
@Override
public void visitNew(SSANewInstruction instruction) {
InstanceKey iKey = getInstanceKeyForAllocation(instruction.getNewSite());
if (iKey == null) {
// something went wrong. I hope someone raised a warning.
return;
}
PointerKey def = getPointerKeyForLocal(instruction.getDef());
IClass klass = iKey.getConcreteType();
if (DEBUG) {
System.err.println("visitNew: " + instruction + " " + iKey + " " + system.findOrCreateIndexForInstanceKey(iKey));
}
if (klass == null) {
if (DEBUG) {
System.err.println("Resolution failure: " + instruction);
}
return;
}
if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) {
system.newConstraint(def, iKey);
} else {
system.findOrCreateIndexForInstanceKey(iKey);
system.recordImplicitPointsToSet(def);
}
// side effect of new: may call class initializer
if (DEBUG) {
System.err.println("visitNew call clinit: " + klass);
}
processClassInitializer(klass);
// add instance keys and pointer keys for array contents
int dim = 0;
InstanceKey lastInstance = iKey;
while (klass != null && klass.isArrayClass()) {
klass = ((ArrayClass) klass).getElementClass();
// klass == null means it's a primitive
if (klass != null && klass.isArrayClass()) {
if (instruction.getNumberOfUses() <= (dim + 1)) {
break;
}
int sv = instruction.getUse(dim + 1);
if (ir.getSymbolTable().isIntegerConstant(sv)) {
Integer c = (Integer) ir.getSymbolTable().getConstantValue(sv);
if (c.intValue() == 0) {
break;
}
}
InstanceKey ik = getInstanceKeyForMultiNewArray(instruction.getNewSite(), dim);
PointerKey pk = getPointerKeyForArrayContents(lastInstance);
if (DEBUG_MULTINEWARRAY) {
System.err.println("multinewarray constraint: ");
System.err.println(" pk: " + pk);
System.err.println(" ik: " + system.findOrCreateIndexForInstanceKey(ik) + " concrete type " + ik.getConcreteType()
+ " is " + ik);
System.err.println(" klass:" + klass);
}
system.newConstraint(pk, ik);
lastInstance = ik;
dim++;
}
}
}
/*
* @see com.ibm.wala.ssa.Instruction.Visitor#visitThrow(com.ibm.wala.ssa.ThrowInstruction)
*/
@Override
public void visitThrow(SSAThrowInstruction instruction) {
// don't do anything: we handle exceptional edges
// in a separate pass
}
/*
* @see com.ibm.wala.ssa.Instruction.Visitor#visitGetCaughtException(com.ibm.wala.ssa.GetCaughtExceptionInstruction)
*/
@Override
public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) {
List<ProgramCounter> peis = getIncomingPEIs(ir, getBasicBlock());
PointerKey def = getPointerKeyForLocal(instruction.getDef());
// SJF: we don't optimize based on dead catch blocks yet ... it's a little
// tricky due interaction with the SINGLE_USE optimization which directly
// shoves exceptional return values from calls into exception vars.
// it may not be worth doing this.
// if (hasNoInterestingUses(instruction.getDef(), du)) {
// solver.recordImplicitPointsToSet(def);
// } else {
Set<IClass> types = getCaughtExceptionTypes(instruction, ir);
getBuilder().addExceptionDefConstraints(ir, du, node, peis, def, types);
// }
}
/**
* TODO: What is this doing? Document me!
*/
private int booleanConstantTest(SSAConditionalBranchInstruction c, int v) {
int result = 0;
// right for OPR_eq
if ((symbolTable.isZeroOrFalse(c.getUse(0)) && c.getUse(1) == v)
|| (symbolTable.isZeroOrFalse(c.getUse(1)) && c.getUse(0) == v)) {
result = -1;
} else if ((symbolTable.isOneOrTrue(c.getUse(0)) && c.getUse(1) == v)
|| (symbolTable.isOneOrTrue(c.getUse(1)) && c.getUse(0) == v)) {
result = 1;
}
if (c.getOperator() == ConditionalBranchInstruction.Operator.NE) {
result = -result;
}
return result;
}
private int nullConstantTest(SSAConditionalBranchInstruction c, int v) {
if ((symbolTable.isNullConstant(c.getUse(0)) && c.getUse(1) == v)
|| (symbolTable.isNullConstant(c.getUse(1)) && c.getUse(0) == v)) {
if (c.getOperator() == ConditionalBranchInstruction.Operator.EQ) {
return 1;
} else {
return -1;
}
} else {
return 0;
}
}
@Override
public void visitPhi(SSAPhiInstruction instruction) {
if (ir.getMethod() instanceof AbstractRootMethod) {
PointerKey dst = getPointerKeyForLocal(instruction.getDef());
if (hasNoInterestingUses(instruction.getDef())) {
system.recordImplicitPointsToSet(dst);
} else {
for (int i = 0; i < instruction.getNumberOfUses(); i++) {
PointerKey use = getPointerKeyForLocal(instruction.getUse(i));
if (contentsAreInvariant(symbolTable, du, instruction.getUse(i))) {
system.recordImplicitPointsToSet(use);
InstanceKey[] ik = getInvariantContents(instruction.getUse(i));
for (int j = 0; j < ik.length; j++) {
system.newConstraint(dst, ik[j]);
}
} else {
system.newConstraint(dst, assignOperator, use);
}
}
}
}
}
/*
* @see com.ibm.wala.ssa.SSAInstruction.Visitor#visitPi(com.ibm.wala.ssa.SSAPiInstruction)
*/
@Override
public void visitPi(SSAPiInstruction instruction) {
int dir;
if (hasNoInterestingUses(instruction.getDef())) {
PointerKey dst = getPointerKeyForLocal(instruction.getDef());
system.recordImplicitPointsToSet(dst);
} else {
ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg = ir.getControlFlowGraph();
if (com.ibm.wala.cfg.Util.endsWithConditionalBranch(cfg, getBasicBlock()) && cfg.getSuccNodeCount(getBasicBlock()) == 2) {
SSAConditionalBranchInstruction cond = (SSAConditionalBranchInstruction) com.ibm.wala.cfg.Util.getLastInstruction(cfg,
getBasicBlock());
SSAInstruction cause = instruction.getCause();
BasicBlock target = (BasicBlock) cfg.getNode(instruction.getSuccessor());
if ((cause instanceof SSAInstanceofInstruction)) {
int direction = booleanConstantTest(cond, cause.getDef());
if (direction != 0) {
TypeReference type = ((SSAInstanceofInstruction) cause).getCheckedType();
IClass cls = getClassHierarchy().lookupClass(type);
if (cls == null) {
PointerKey dst = getPointerKeyForLocal(instruction.getDef());
addPiAssignment(dst, instruction.getVal());
} else {
PointerKey dst = getFilteredPointerKeyForLocal(instruction.getDef(), new FilteredPointerKey.SingleClassFilter(cls));
PointerKey src = getPointerKeyForLocal(instruction.getVal());
if ((target == com.ibm.wala.cfg.Util.getTakenSuccessor(cfg, getBasicBlock()) && direction == 1)
|| (target == com.ibm.wala.cfg.Util.getNotTakenSuccessor(cfg, getBasicBlock()) && direction == -1)) {
system.newConstraint(dst, getBuilder().filterOperator, src);
} else {
system.newConstraint(dst, getBuilder().inverseFilterOperator, src);
}
}
}
} else if ((dir = nullConstantTest(cond, instruction.getVal())) != 0) {
if ((target == com.ibm.wala.cfg.Util.getTakenSuccessor(cfg, getBasicBlock()) && dir == -1)
|| (target == com.ibm.wala.cfg.Util.getNotTakenSuccessor(cfg, getBasicBlock()) && dir == 1)) {
PointerKey dst = getPointerKeyForLocal(instruction.getDef());
addPiAssignment(dst, instruction.getVal());
}
} else {
PointerKey dst = getPointerKeyForLocal(instruction.getDef());
addPiAssignment(dst, instruction.getVal());
}
} else {
PointerKey dst = getPointerKeyForLocal(instruction.getDef());
addPiAssignment(dst, instruction.getVal());
}
}
}
/**
* Add a constraint to the system indicating that the contents of local src flows to dst, with no special type filter.
*/
private void addPiAssignment(PointerKey dst, int src) {
PointerKey srcKey = getPointerKeyForLocal(src);
if (contentsAreInvariant(symbolTable, du, src)) {
system.recordImplicitPointsToSet(srcKey);
InstanceKey[] ik = getInvariantContents(src);
for (int j = 0; j < ik.length; j++) {
system.newConstraint(dst, ik[j]);
}
} else {
system.newConstraint(dst, assignOperator, srcKey);
}
}
public ISSABasicBlock getBasicBlock() {
return basicBlock;
}
/**
* The calling loop must call this in each iteration!
*/
public void setBasicBlock(ISSABasicBlock block) {
basicBlock = block;
}
protected interface InvariantComputer {
InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call);
}
public class DefaultInvariantComputer implements InvariantComputer {
/**
* Side effect: records invariant parameters as implicit points-to-sets.
*
* @return if non-null, then result[i] holds the set of instance keys which may be passed as the ith parameter. (which must be
* invariant)
*/
public InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) {
InstanceKey[][] constParams = null;
for (int i = 0; i < call.getNumberOfUses(); i++) {
// not sure how getUse(i) <= 0 .. dead code?
// TODO: investigate
if (call.getUse(i) > 0) {
if (contentsAreInvariant(symbolTable, du, call.getUse(i))) {
system.recordImplicitPointsToSet(getPointerKeyForLocal(call.getUse(i)));
if (constParams == null) {
constParams = new InstanceKey[call.getNumberOfUses()][];
}
constParams[i] = getInvariantContents(call.getUse(i));
for (int j = 0; j < constParams[i].length; j++) {
system.findOrCreateIndexForInstanceKey(constParams[i][j]);
}
}
}
}
return constParams;
}
}
@Override
public void visitLoadMetadata(SSALoadMetadataInstruction instruction) {
PointerKey def = getPointerKeyForLocal(instruction.getDef());
assert instruction.getType() == TypeReference.JavaLangClass;
InstanceKey iKey = getInstanceKeyForClassObject((TypeReference) instruction.getToken());
IClass klass = getClassHierarchy().lookupClass((TypeReference) instruction.getToken());
if (klass != null) {
processClassInitializer(klass);
}
if (!contentsAreInvariant(symbolTable, du, instruction.getDef())) {
system.newConstraint(def, iKey);
} else {
system.findOrCreateIndexForInstanceKey(iKey);
system.recordImplicitPointsToSet(def);
}
}
/**
* TODO: lift most of this logic to PropagationCallGraphBuilder
*
* Add a call to the class initializer from the root method.
*/
private void processClassInitializer(IClass klass) {
assert klass != null;
if (!getBuilder().getOptions().getHandleStaticInit()) {
return;
}
if (getBuilder().clinitVisited.contains(klass)) {
return;
}
getBuilder().clinitVisited.add(klass);
if (klass.getClassInitializer() != null) {
if (DEBUG) {
System.err.println("process class initializer for " + klass);
}
// add an invocation from the fake root method to the <clinit>
AbstractRootMethod fakeWorldClinitMethod = (AbstractRootMethod) callGraph.getFakeWorldClinitNode().getMethod();
MethodReference m = klass.getClassInitializer().getReference();
CallSiteReference site = CallSiteReference.make(1, m, IInvokeInstruction.Dispatch.STATIC);
IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(callGraph.getFakeRootNode(), site, null);
if (targetMethod != null) {
CGNode target = getTargetForCall(callGraph.getFakeRootNode(), site, null, null);
if (target != null && callGraph.getPredNodeCount(target) == 0) {
SSAAbstractInvokeInstruction s = fakeWorldClinitMethod.addInvocation(new int[0], site);
PointerKey uniqueCatch = getBuilder().getPointerKeyForExceptionalReturnValue(callGraph.getFakeRootNode());
getBuilder().processResolvedCall(callGraph.getFakeWorldClinitNode(), s, target, null, uniqueCatch);
}
}
}
IClass sc = klass.getSuperclass();
if (sc != null) {
processClassInitializer(sc);
}
}
}
/**
* Add constraints for a call site after we have computed a reachable target for the dispatch
*
* Side effect: add edge to the call graph.
*
* @param instruction
* @param constParams if non-null, then constParams[i] holds the set of instance keys that are passed as param i, or null if param
* i is not invariant
* @param uniqueCatchKey if non-null, then this is the unique PointerKey that catches all exceptions from this call site.
*/
@SuppressWarnings("deprecation")
private void processResolvedCall(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target,
InstanceKey[][] constParams, PointerKey uniqueCatchKey) {
if (DEBUG) {
System.err.println("processResolvedCall: " + caller + " ," + instruction + " , " + target);
}
if (DEBUG) {
System.err.println("addTarget: " + caller + " ," + instruction + " , " + target);
}
caller.addTarget(instruction.getCallSite(), target);
if (FakeRootMethod.isFakeRootMethod(caller.getMethod().getReference())) {
if (entrypointCallSites.contains(instruction.getCallSite())) {
callGraph.registerEntrypoint(target);
}
}
if (!haveAlreadyVisited(target)) {
markDiscovered(target);
}
processCallingConstraints(caller, instruction, target, constParams, uniqueCatchKey);
}
protected void processCallingConstraints(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target,
InstanceKey[][] constParams, PointerKey uniqueCatchKey) {
// TODO: i'd like to enable this optimization, but it's a little tricky
// to recover the implicit points-to sets with recursion. TODO: don't
// be lazy and code the recursive logic to enable this.
// if (hasNoInstructions(target)) {
// // record points-to sets for formals implicitly .. computed on
// // demand.
// // TODO: generalize this by using hasNoInterestingUses on parameters.
// // however .. have to be careful to cache results in that case ... don't
// // want
// // to recompute du each time we process a call to Object.<init> !
// for (int i = 0; i < instruction.getNumberOfUses(); i++) {
// // we rely on the invariant that the value number for the ith parameter
// // is i+1
// final int vn = i + 1;
// PointerKey formal = getPointerKeyForLocal(target, vn);
// if (target.getMethod().getParameterType(i).isReferenceType()) {
// system.recordImplicitPointsToSet(formal);
// }
// }
// } else {
// generate contraints from parameter passing
int nUses = instruction.getNumberOfParameters();
int nExpected = target.getMethod().getNumberOfParameters();
/*
* int nExpected = target.getMethod().getReference().getNumberOfParameters(); if (!target.getMethod().isStatic() &&
* !target.getMethod().isClinit()) { nExpected++; }
*/
if (nUses != nExpected) {
// some sort of unverifiable code mismatch. give up.
return;
}
// we're a little sloppy for now ... we don't filter calls to
// java.lang.Object.
// TODO: we need much more precise filters than cones in order to handle
// the various types of dispatch logic. We need a filter that expresses
// "the set of types s.t. x.foo resolves to y.foo."
for (int i = 0; i < instruction.getNumberOfParameters(); i++) {
if (target.getMethod().getParameterType(i).isReferenceType()) {
PointerKey formal = getTargetPointerKey(target, i);
if (constParams != null && constParams[i] != null) {
InstanceKey[] ik = constParams[i];
for (int j = 0; j < ik.length; j++) {
system.newConstraint(formal, ik[j]);
}
} else {
if (instruction.getUse(i) < 0) {
Assertions.UNREACHABLE("unexpected " + instruction + " in " + caller);
}
PointerKey actual = getPointerKeyForLocal(caller, instruction.getUse(i));
if (formal instanceof FilteredPointerKey) {
system.newConstraint(formal, filterOperator, actual);
} else {
system.newConstraint(formal, assignOperator, actual);
}
}
}
}
// generate contraints from return value.
if (instruction.hasDef() && instruction.getDeclaredResultType().isReferenceType()) {
PointerKey result = getPointerKeyForLocal(caller, instruction.getDef());
PointerKey ret = getPointerKeyForReturnValue(target);
system.newConstraint(result, assignOperator, ret);
}
// generate constraints from exception return value.
PointerKey e = getPointerKeyForLocal(caller, instruction.getException());
PointerKey er = getPointerKeyForExceptionalReturnValue(target);
if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) {
// e has exactly one use. so, represent e implicitly
system.newConstraint(uniqueCatchKey, assignOperator, er);
} else {
system.newConstraint(e, assignOperator, er);
}
// }
}
/**
* An operator to fire when we discover a potential new callee for a virtual or interface call site.
*
* This operator will create a new callee context and constraints if necessary.
*/
final class DispatchOperator extends AbstractOperator<PointsToSetVariable> implements IPointerOperator {
private final SSAAbstractInvokeInstruction call;
private final CGNode node;
private final InstanceKey[][] constParams;
private final PointerKey uniqueCatch;
/**
* relevant parameter indices for the registered {@link ContextSelector}
*
* @see ContextSelector#getRelevantParameters(CGNode, CallSiteReference)
*/
private final int[] dispatchIndices;
/**
* The set of instance keys that have already been processed.
* previousPtrs[i] contains the processed instance keys for parameter
* position dispatchIndices[i]
*/
final private MutableIntSet[] previousPtrs;
/**
* @param call
* @param node
* @param constParams if non-null, then constParams[i] holds the String constant that is passed as param i, or null if param i
* is not a String constant
*/
DispatchOperator(SSAAbstractInvokeInstruction call, CGNode node, InstanceKey[][] constParams,
PointerKey uniqueCatch, IntSet dispatchIndices) {
this.call = call;
this.node = node;
this.constParams = constParams;
this.uniqueCatch = uniqueCatch;
this.dispatchIndices = IntSetUtil.toArray(dispatchIndices);
// we better always be interested in the receiver
assert this.dispatchIndices[0] == 0;
previousPtrs = new MutableIntSet[dispatchIndices.size()];
for(int i = 0; i < previousPtrs.length; i++) {
previousPtrs[i] = IntSetUtil.getDefaultIntSetFactory().make();
}
}
/*
* @see com.ibm.wala.dataflow.fixpoint.UnaryOperator#evaluate(com.ibm.wala.dataflow.fixpoint.IVariable,
* com.ibm.wala.dataflow.fixpoint.IVariable)
*/
@Override
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
assert dispatchIndices.length >= rhs.length : "bad operator at " + call;
final MutableBoolean sideEffect = new MutableBoolean();
final MutableIntSet receiverVals;
if (constParams != null && constParams[0] != null) {
receiverVals = IntSetUtil.make();
for(InstanceKey ik : constParams[0]) {
receiverVals.add(system.getInstanceIndex(ik));
}
} else {
receiverVals = rhs[0].getValue();
}
if (receiverVals == null) {
// this constraint was put on the work list, probably by
// initialization,
// even though the right-hand-side is empty.
// TODO: be more careful about what goes on the worklist to
// avoid this.
if (DEBUG) {
System.err.println("EVAL dispatch with value null");
}
return NOT_CHANGED;
}
// we handle the parameter positions one by one, rather than enumerating
// the cartesian product of possibilities. this disallows
// context-sensitivity policies like true CPA, but is necessary for
// performance.
InstanceKey keys[] = new InstanceKey[constParams == null? dispatchIndices[dispatchIndices.length-1]+1: constParams.length];
// determine whether we're handling a new receiver; used later
// to check for redundancy
boolean newReceiver = !receiverVals.isSubset(previousPtrs[0]);
// keep separate rhsIndex, since it doesn't advance for constant
// parameters
int rhsIndex = (constParams != null && constParams[0] != null)? 0: 1;
// we start at index 1 since we need to handle the receiver specially; see
// below
for (int index = 1; index < dispatchIndices.length; index++) {
try {
MonitorUtil.throwExceptionIfCanceled(monitor);
} catch (CancelException e) {
throw new CancelRuntimeException(e);
}
int paramIndex = dispatchIndices[index];
assert keys[paramIndex] == null;
final MutableIntSet prevAtIndex = previousPtrs[index];
if (constParams != null && constParams[paramIndex] != null) {
// we have a constant parameter. only need to propagate again if we've never done it before or if we have a new receiver
if (newReceiver || prevAtIndex.isEmpty()) {
for(int i = 0; i < constParams[paramIndex].length; i++) {
keys[paramIndex] = constParams[paramIndex][i];
handleAllReceivers(receiverVals,keys, sideEffect);
int ii = system.instanceKeys.getMappedIndex(constParams[paramIndex][i]);
prevAtIndex.add(ii);
}
}
} else { // non-constant parameter
PointsToSetVariable v = rhs[rhsIndex];
if (v.getValue() != null) {
IntIterator ptrs = v.getValue().intIterator();
while (ptrs.hasNext()) {
int ptr = ptrs.next();
if (newReceiver || !prevAtIndex.contains(ptr)) {
keys[paramIndex] = system.getInstanceKey(ptr);
handleAllReceivers(receiverVals,keys, sideEffect);
prevAtIndex.add(ptr);
}
}
}
rhsIndex++;
}
keys[paramIndex] = null;
}
if (newReceiver && !sideEffect.b) {
// we have a new receiver value, and it wasn't propagated at all,
// so propagate it now
handleAllReceivers(receiverVals, keys, sideEffect);
previousPtrs[0].addAll(receiverVals);
}
byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0;
return (byte) (NOT_CHANGED | sideEffectMask);
}
private void handleAllReceivers(MutableIntSet receiverVals, InstanceKey[] keys, MutableBoolean sideEffect) {
assert keys[0] == null;
IntIterator receiverIter = receiverVals.intIterator();
while (receiverIter.hasNext()) {
final int rcvr = receiverIter.next();
keys[0] = system.getInstanceKey(rcvr);
if (clone2Assign) {
// for efficiency: assume that only call sites that reference
// clone() might dispatch to clone methods
if (call.getCallSite().getDeclaredTarget().getSelector().equals(cloneSelector)) {
IClass recv = (keys[0] != null) ? keys[0].getConcreteType() : null;
IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(node, call.getCallSite(), recv);
if (targetMethod != null && targetMethod.getReference().equals(CloneInterpreter.CLONE)) {
// treat this call to clone as an assignment
PointerKey result = getPointerKeyForLocal(node, call.getDef());
PointerKey receiver = getPointerKeyForLocal(node, call.getReceiver());
system.newConstraint(result, assignOperator, receiver);
return;
}
}
}
CGNode target = getTargetForCall(node, call.getCallSite(), keys[0].getConcreteType(), keys);
if (target == null) {
// This indicates an error; I sure hope getTargetForCall
// raised a warning about this!
if (DEBUG) {
System.err.println("Warning: null target for call " + call);
}
} else {
IntSet targets = getCallGraph().getPossibleTargetNumbers(node, call.getCallSite());
if (targets != null && targets.contains(target.getGraphNodeId())) {
// do nothing; we've previously discovered and handled this
// receiver for this call site.
} else {
// process the newly discovered target for this call
sideEffect.b = true;
processResolvedCall(node, call, target, constParams, uniqueCatch);
if (!haveAlreadyVisited(target)) {
markDiscovered(target);
}
}
}
}
keys[0] = null;
}
@Override
public String toString() {
return "Dispatch to " + call + " in node " + node;
}
@Override
public int hashCode() {
return node.hashCode() + 90289 * call.hashCode();
}
@Override
public boolean equals(Object o) {
// note that these are not necessarily canonical, since
// with synthetic factories we may regenerate constraints
// many times. TODO: change processing of synthetic factories
// so that we guarantee to insert each dispatch equation
// only once ... if this were true we could optimize this
// with reference equality
// instanceof is OK because this class is final
if (o instanceof DispatchOperator) {
DispatchOperator other = (DispatchOperator) o;
return node.equals(other.node) && call.equals(other.call) && Arrays.deepEquals(constParams, other.constParams);
} else {
return false;
}
}
/*
* @see com.ibm.wala.ipa.callgraph.propagation.IPointerOperator#isComplex()
*/
public boolean isComplex() {
return true;
}
}
protected void iterateCrossProduct(final CGNode caller, final CallSiteReference site, IntSet parameters, final InstanceKey[][] invariants, final VoidFunction<InstanceKey[]> f) {
final IR ir = caller.getIR();
final int params[] = IntSetUtil.toArray(parameters);
for (final SSAAbstractInvokeInstruction call : ir.getCalls(site)) {
final InstanceKey[] keys = new InstanceKey[call.getNumberOfParameters()];
new Object() {
private void rec(final int pi) {
if (pi == params.length) {
f.apply(keys);
} else {
final int p = params[pi];
int vn = call.getUse(p);
PointerKey var = getPointerKeyForLocal(caller, vn);
InstanceKey[] ik = invariants!=null? invariants[p]: null;
if (ik != null) {
if (ik.length > 0) {
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
keys[p] = ik[i];
rec(pi+1);
}
} else {
if (!site.isDispatch() || p != 0) {
keys[p] = null;
rec(pi+1);
}
}
} else {
IntSet s = system.findOrCreatePointsToSet(var).getValue();
if (s != null && !s.isEmpty()) {
s.foreach(new IntSetAction() {
public void act(int x) {
keys[p] = system.getInstanceKey(x);
rec(pi+1);
}
});
} else {
if (!site.isDispatch() || p != 0) {
keys[p] = null;
rec(pi+1);
}
}
}
}
}
}.rec(0);
}
}
protected Set<CGNode> getTargetsForCall(final CGNode caller, final CallSiteReference site, InstanceKey[][] invs) {
IntSet params = contextSelector.getRelevantParameters(caller, site);
if (!site.isStatic() && !params.contains(0)) {
params = IntSetUtil.makeMutableCopy(params);
((MutableIntSet)params).add(0);
}
final Set<CGNode> targets = HashSetFactory.make();
VoidFunction<InstanceKey[]> f = new VoidFunction<InstanceKey[]>() {
public void apply(InstanceKey[] v) {
IClass recv = null;
if (site.isDispatch()) {
recv = v[0].getConcreteType();
}
CGNode target = getTargetForCall(caller, site, recv, v);
if (target != null) {
targets.add(target);
}
}
};
iterateCrossProduct(caller, site, params, invs, f);
return targets;
}
public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) {
if (du == null) {
throw new IllegalArgumentException("du is null");
}
if (vn <= 0) {
throw new IllegalArgumentException("v is invalid: " + vn);
}
// todo: enhance this by solving a dead-code elimination
// problem.
InterestingVisitor v = makeInterestingVisitor(node, vn);
for (Iterator it = du.getUses(v.vn); it.hasNext();) {
SSAInstruction s = (SSAInstruction) it.next();
s.visit(v);
if (v.bingo) {
return false;
}
}
return true;
}
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
return new InterestingVisitor(vn);
}
/**
* sets bingo to true when it visits an interesting instruction
*/
protected static class InterestingVisitor extends SSAInstruction.Visitor {
protected final int vn;
protected InterestingVisitor(int vn) {
this.vn = vn;
}
protected boolean bingo = false;
@Override
public void visitArrayLoad(SSAArrayLoadInstruction instruction) {
if (!instruction.typeIsPrimitive() && instruction.getArrayRef() == vn) {
bingo = true;
}
}
@Override
public void visitArrayStore(SSAArrayStoreInstruction instruction) {
if (!instruction.typeIsPrimitive() && (instruction.getArrayRef() == vn || instruction.getValue() == vn)) {
bingo = true;
}
}
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
bingo = true;
}
@Override
public void visitGet(SSAGetInstruction instruction) {
FieldReference field = instruction.getDeclaredField();
if (!field.getFieldType().isPrimitiveType()) {
bingo = true;
}
}
@Override
public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) {
bingo = true;
}
@Override
public void visitInvoke(SSAInvokeInstruction instruction) {
bingo = true;
}
@Override
public void visitPhi(SSAPhiInstruction instruction) {
bingo = true;
}
@Override
public void visitPi(SSAPiInstruction instruction) {
bingo = true;
}
@Override
public void visitPut(SSAPutInstruction instruction) {
FieldReference field = instruction.getDeclaredField();
if (!field.getFieldType().isPrimitiveType()) {
bingo = true;
}
}
@Override
public void visitReturn(SSAReturnInstruction instruction) {
bingo = true;
}
@Override
public void visitThrow(SSAThrowInstruction instruction) {
bingo = true;
}
}
/**
* TODO: enhance this logic using type inference
*
* @param instruction
* @return true if we need to filter the receiver type to account for virtual dispatch
*/
@SuppressWarnings("unused")
private boolean needsFilterForReceiver(SSAAbstractInvokeInstruction instruction, CGNode target) {
FilteredPointerKey.TypeFilter f = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[0]);
if (f != null) {
// the context selects a particular concrete type for the receiver.
// we need to filter, unless the declared receiver type implies the
// concrete type (TODO: need to implement this optimization)
return true;
}
// don't need to filter for invokestatic
if (instruction.getCallSite().isStatic() || instruction.getCallSite().isSpecial()) {
return false;
}
MethodReference declaredTarget = instruction.getDeclaredTarget();
IMethod resolvedTarget = getClassHierarchy().resolveMethod(declaredTarget);
if (resolvedTarget == null) {
// there's some problem that will be flagged as a warning
return true;
}
return true;
}
private boolean isRootType(IClass klass) {
return klass.getClassHierarchy().isRootClass(klass);
}
@SuppressWarnings("unused")
private boolean isRootType(FilteredPointerKey.TypeFilter filter) {
if (filter instanceof FilteredPointerKey.SingleClassFilter) {
return isRootType(((FilteredPointerKey.SingleClassFilter) filter).getConcreteType());
} else {
return false;
}
}
/**
* TODO: enhance this logic using type inference TODO!!!: enhance filtering to consider concrete types, not just cones.
* precondition: needs Filter
*
* @param target
* @return an IClass which represents
*/
protected PointerKey getTargetPointerKey(CGNode target, int index) {
int vn;
if (target.getIR() != null) {
vn = target.getIR().getSymbolTable().getParameter(index);
} else {
vn = index+1;
}
FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[index]);
if (filter != null && !filter.isRootFilter()) {
return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, filter);
} else if (index == 0 && !target.getMethod().isStatic()) {
// the context does not select a particular concrete type for the
// receiver, so use the type of the method
IClass C = getReceiverClass(target.getMethod());
if (C.getClassHierarchy().getRootClass().equals(C)) {
return pointerKeyFactory.getPointerKeyForLocal(target, vn);
} else {
return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, new FilteredPointerKey.SingleClassFilter(C));
}
} else {
return pointerKeyFactory.getPointerKeyForLocal(target, vn);
}
}
/**
* @param method
* @return the receiver class for this method.
*/
private IClass getReceiverClass(IMethod method) {
TypeReference formalType = method.getParameterType(0);
IClass C = getClassHierarchy().lookupClass(formalType);
if (method.isStatic()) {
Assertions.UNREACHABLE("asked for receiver of static method " + method);
}
if (C == null) {
Assertions.UNREACHABLE("no class found for " + formalType + " recv of " + method);
}
return C;
}
/**
* A value is "invariant" if we can figure out the instances it can ever point to locally, without resorting to propagation.
*
* @param valueNumber
* @return true iff the contents of the local with this value number can be deduced locally, without propagation
*/
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) {
if (isConstantRef(symbolTable, valueNumber)) {
return true;
} else if (SHORT_CIRCUIT_INVARIANT_SETS) {
SSAInstruction def = du.getDef(valueNumber);
if (def instanceof SSANewInstruction) {
return true;
} else {
return false;
}
} else {
return false;
}
}
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumbers[]) {
for(int i = 0; i < valueNumbers.length; i++) {
if (! contentsAreInvariant(symbolTable, du, valueNumbers[i])) {
return false;
}
}
return true;
}
/**
* precondition:contentsAreInvariant(valueNumber)
*
* @param valueNumber
* @return the complete set of instances that the local with vn=valueNumber may point to.
*/
protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber, HeapModel hm) {
return getInvariantContents(symbolTable, du, node, valueNumber, hm, false);
}
protected InstanceKey[] getInvariantContents(SymbolTable symbolTable, DefUse du, CGNode node, int valueNumber, HeapModel hm,
boolean ensureIndexes) {
InstanceKey[] result;
if (isConstantRef(symbolTable, valueNumber)) {
Object x = symbolTable.getConstantValue(valueNumber);
if (x instanceof String) {
// this is always the case in Java. use strong typing in the call to getInstanceKeyForConstant.
String S = (String) x;
TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(S);
if (type == null) {
return new InstanceKey[0];
}
InstanceKey ik = hm.getInstanceKeyForConstant(type, S);
if (ik != null) {
result = new InstanceKey[] { ik };
} else {
result = new InstanceKey[0];
}
} else {
// some non-built in type (e.g. Integer). give up on strong typing.
// language-specific subclasses (e.g. Javascript) should override this method to get strong typing
// with generics if desired.
TypeReference type = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().getConstantType(x);
if (type == null) {
return new InstanceKey[0];
}
InstanceKey ik = hm.getInstanceKeyForConstant(type, x);
if (ik != null) {
result = new InstanceKey[] { ik };
} else {
result = new InstanceKey[0];
}
}
} else {
SSANewInstruction def = (SSANewInstruction) du.getDef(valueNumber);
InstanceKey iKey = hm.getInstanceKeyForAllocation(node, def.getNewSite());
result = (iKey == null) ? new InstanceKey[0] : new InstanceKey[] { iKey };
}
if (ensureIndexes) {
for (int i = 0; i < result.length; i++) {
system.findOrCreateIndexForInstanceKey(result[i]);
}
}
return result;
}
protected boolean isConstantRef(SymbolTable symbolTable, int valueNumber) {
if (valueNumber == -1) {
return false;
}
if (symbolTable.isConstant(valueNumber)) {
Object v = symbolTable.getConstantValue(valueNumber);
return (!(v instanceof Number));
} else {
return false;
}
}
/**
* @author sfink
*
* A warning for when we fail to resolve the type for a checkcast
*/
private static class CheckcastFailure extends Warning {
final TypeReference type;
CheckcastFailure(TypeReference type) {
super(Warning.SEVERE);
this.type = type;
}
@Override
public String getMsg() {
return getClass().toString() + " : " + type;
}
public static CheckcastFailure create(TypeReference type) {
return new CheckcastFailure(type);
}
}
/**
* @author sfink
*
* A warning for when we fail to resolve the type for a field
*/
private static class FieldResolutionFailure extends Warning {
final FieldReference field;
FieldResolutionFailure(FieldReference field) {
super(Warning.SEVERE);
this.field = field;
}
@Override
public String getMsg() {
return getClass().toString() + " : " + field;
}
public static FieldResolutionFailure create(FieldReference field) {
return new FieldResolutionFailure(field);
}
}
/*
* @see com.ibm.wala.ipa.callgraph.propagation.HeapModel#iteratePointerKeys()
*/
public Iterator<PointerKey> iteratePointerKeys() {
return system.iteratePointerKeys();
}
public static Set<IClass> getCaughtExceptionTypes(SSAGetCaughtExceptionInstruction instruction, IR ir) {
if (ir == null) {
throw new IllegalArgumentException("ir is null");
}
if (instruction == null) {
throw new IllegalArgumentException("instruction is null");
}
Iterator<TypeReference> exceptionTypes = ((ExceptionHandlerBasicBlock) ir.getControlFlowGraph().getNode(
instruction.getBasicBlockNumber())).getCaughtExceptionTypes();
HashSet<IClass> types = HashSetFactory.make(10);
for (; exceptionTypes.hasNext();) {
IClass c = ir.getMethod().getClassHierarchy().lookupClass(exceptionTypes.next());
if (c != null) {
types.add(c);
}
}
return types;
}
public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type) {
return getInstanceKeyForPEI(node, instr, type, instanceKeyFactory);
}
/*
* @see com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder#makeSolver()
*/
@Override
protected IPointsToSolver makeSolver() {
return new StandardSolver(system, this);
// return usePreTransitiveSolver ? (IPointsToSolver) new PreTransitiveSolver(system, this) : new StandardSolver(system, this);
// return true ? (IPointsToSolver)new PreTransitiveSolver(system,this) : new
// StandardSolver(system,this);
}
}