WALA/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphB...

1261 lines
45 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.cast.ipa.callgraph;
import java.io.UTFDataFormatException;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter;
import com.ibm.wala.cast.ipa.callgraph.AstCallGraph.AstCGNode;
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey;
import com.ibm.wala.cast.ir.ssa.AstAssertInstruction;
import com.ibm.wala.cast.ir.ssa.AstEchoInstruction;
import com.ibm.wala.cast.ir.ssa.AstGlobalRead;
import com.ibm.wala.cast.ir.ssa.AstGlobalWrite;
import com.ibm.wala.cast.ir.ssa.AstIRFactory;
import com.ibm.wala.cast.ir.ssa.AstInstructionVisitor;
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess;
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access;
import com.ibm.wala.cast.ir.ssa.AstLexicalRead;
import com.ibm.wala.cast.ir.ssa.AstLexicalWrite;
import com.ibm.wala.cast.ir.ssa.EachElementGetInstruction;
import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction;
import com.ibm.wala.cast.ir.translator.AstTranslator;
import com.ibm.wala.cast.loader.AstMethod;
import com.ibm.wala.cast.loader.AstMethod.LexicalInformation;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.fixpoint.IntSetVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysisImpl;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.PointsToMap;
import com.ibm.wala.ipa.callgraph.propagation.PointsToSetVariable;
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.PropagationSystem;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultSSAInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.modref.ArrayLengthKey;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IRView;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetAction;
import com.ibm.wala.util.intset.IntSetUtil;
import com.ibm.wala.util.intset.MutableIntSet;
import com.ibm.wala.util.intset.MutableMapping;
import com.ibm.wala.util.strings.Atom;
public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCallGraphBuilder {
public static final boolean DEBUG_TYPE_INFERENCE = false;
public static final boolean DEBUG_PROPERTIES = false;
// /////////////////////////////////////////////////////////////////////////
//
// language specialization interface
//
// /////////////////////////////////////////////////////////////////////////
/**
* should we maintain an object catalog for each instance key, storing the
* names of all known properties of the instance key? required to handle
* {@link EachElementGetInstruction}s.
*
* @see AstConstraintVisitor#visitPut(SSAPutInstruction)
* @see AstConstraintVisitor#visitEachElementGet(EachElementGetInstruction)
*/
protected abstract boolean useObjectCatalog();
/**
* each language can specify whether a particular field name should be stored
* in object catalogs or not. By default, always return false.
*/
protected boolean isUncataloguedField(IClass type, String fieldName) {
return false;
}
// /////////////////////////////////////////////////////////////////////////
//
// overall control
//
// /////////////////////////////////////////////////////////////////////////
public abstract GlobalObjectKey getGlobalObject(Atom language);
protected AstSSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, IAnalysisCacheView cache,
PointerKeyFactory pointerKeyFactory) {
super(cha, options, cache, pointerKeyFactory);
}
public SSAContextInterpreter makeDefaultContextInterpreters(SSAContextInterpreter appContextInterpreter, AnalysisOptions options,
IClassHierarchy cha) {
SSAContextInterpreter c = new DefaultSSAInterpreter(options, getAnalysisCache());
c = new DelegatingSSAContextInterpreter(new AstContextInsensitiveSSAContextInterpreter(options, getAnalysisCache()), c);
c = new DelegatingSSAContextInterpreter(ReflectionContextInterpreter.createReflectionContextInterpreter(cha, options,
getAnalysisCache()), c);
if (appContextInterpreter == null)
return c;
else
return new DelegatingSSAContextInterpreter(appContextInterpreter, c);
}
// /////////////////////////////////////////////////////////////////////////
//
// specialized pointer analysis
//
// /////////////////////////////////////////////////////////////////////////
@Override
protected PropagationSystem makeSystem(AnalysisOptions options) {
return new PropagationSystem(callGraph, pointerKeyFactory, instanceKeyFactory) {
@Override
public PointerAnalysis<InstanceKey> makePointerAnalysis(PropagationCallGraphBuilder builder) {
return new AstPointerAnalysisImpl(builder, cg, pointsToMap, instanceKeys, pointerKeyFactory, instanceKeyFactory);
}
};
}
public static class AstPointerAnalysisImpl extends PointerAnalysisImpl {
public AstPointerAnalysisImpl(PropagationCallGraphBuilder builder, CallGraph cg, PointsToMap pointsToMap,
MutableMapping<InstanceKey> instanceKeys, PointerKeyFactory pointerKeys, InstanceKeyFactory iKeyFactory) {
super(builder, cg, pointsToMap, instanceKeys, pointerKeys, iKeyFactory);
}
@Override
protected HeapModel makeHeapModel() {
class Model extends HModel implements AstHeapModel {
@Override
public PointerKey getPointerKeyForArrayLength(InstanceKey I) {
return new ArrayLengthKey(I);
}
@Override
public Iterator<PointerKey> getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) {
return ((AstPointerKeyFactory)pointerKeys).getPointerKeysForReflectedFieldRead(I, F);
}
@Override
public Iterator<PointerKey> getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) {
return ((AstPointerKeyFactory)pointerKeys).getPointerKeysForReflectedFieldWrite(I, F);
}
@Override
public PointerKey getPointerKeyForObjectCatalog(InstanceKey I) {
return ((AstPointerKeyFactory)pointerKeys).getPointerKeyForObjectCatalog(I);
}
}
return new Model();
}
@Override
protected ImplicitPointsToSetVisitor makeImplicitPointsToVisitor(LocalPointerKey lpk) {
return new AstImplicitPointsToSetVisitor(this, lpk);
}
public static class AstImplicitPointsToSetVisitor extends ImplicitPointsToSetVisitor implements AstInstructionVisitor {
public AstImplicitPointsToSetVisitor(AstPointerAnalysisImpl analysis, LocalPointerKey lpk) {
super(analysis, lpk);
}
@Override
public void visitAstLexicalRead(AstLexicalRead instruction) {
}
@Override
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
}
@Override
public void visitAstGlobalRead(AstGlobalRead instruction) {
pointsToSet = analysis.computeImplicitPointsToSetAtGet(node, instruction.getDeclaredField(), -1, true);
}
@Override
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
}
@Override
public void visitAssert(AstAssertInstruction instruction) {
}
@Override
public void visitEachElementGet(EachElementGetInstruction inst) {
}
@Override
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
}
@Override
public void visitIsDefined(AstIsDefinedInstruction inst) {
}
@Override
public void visitEcho(AstEchoInstruction inst) {
}
}
}
// /////////////////////////////////////////////////////////////////////////
//
// top-level node constraint generation
//
// /////////////////////////////////////////////////////////////////////////
@Override
protected ExplicitCallGraph createEmptyCallGraph(IClassHierarchy cha, AnalysisOptions options) {
return new AstCallGraph(cha, options, getAnalysisCache());
}
public static class AstInterestingVisitor extends InterestingVisitor implements AstInstructionVisitor {
public AstInterestingVisitor(int vn) {
super(vn);
}
@Override
public void visitAstLexicalRead(AstLexicalRead instruction) {
bingo = true;
}
@Override
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
bingo = true;
}
@Override
public void visitAstGlobalRead(AstGlobalRead instruction) {
bingo = true;
}
@Override
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
bingo = true;
}
@Override
public void visitAssert(AstAssertInstruction instruction) {
bingo = true;
}
@Override
public void visitEachElementGet(EachElementGetInstruction inst) {
bingo = true;
}
@Override
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
}
@Override
public void visitIsDefined(AstIsDefinedInstruction inst) {
}
@Override
public void visitEcho(AstEchoInstruction inst) {
}
}
@Override
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
return new AstInterestingVisitor(vn);
}
@Override
public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) {
if (node.getMethod() instanceof AstMethod) {
// uses in nested functions are interesting
IntSet uses = ((AstIRFactory<?>.AstIR) node.getIR()).lexicalInfo().getAllExposedUses();
if (uses.contains(vn)) {
return false;
}
}
return super.hasNoInterestingUses(node, vn, du);
}
// /////////////////////////////////////////////////////////////////////////
//
// IR visitor specialization for Ast-specific IR types
//
// /////////////////////////////////////////////////////////////////////////
@Override
public ConstraintVisitor makeVisitor(CGNode node) {
return new AstConstraintVisitor(this, node);
}
protected static class AstConstraintVisitor extends ConstraintVisitor implements AstInstructionVisitor {
public AstConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
super(builder, node);
}
@Override
protected AstSSAPropagationCallGraphBuilder getBuilder() {
return (AstSSAPropagationCallGraphBuilder) builder;
}
public PointerKey getPointerKeyForObjectCatalog(InstanceKey I) {
return ((AstPointerKeyFactory) getBuilder().getPointerKeyFactory()).getPointerKeyForObjectCatalog(I);
}
public Iterator<PointerKey> getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) {
return ((AstPointerKeyFactory) getBuilder().getPointerKeyFactory()).getPointerKeysForReflectedFieldRead(I, F);
}
public Iterator<PointerKey> getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) {
return ((AstPointerKeyFactory) getBuilder().getPointerKeyFactory()).getPointerKeysForReflectedFieldWrite(I, F);
}
private static void visitLexical(AstLexicalAccess instruction, final LexicalOperator op) {
op.doLexicalPointerKeys(false);
// I have no idea what the code below does, but commenting it out doesn't
// break any regression tests. --MS
// if (! checkLexicalInstruction(instruction)) {
// system.newSideEffect(op, getPointerKeyForLocal(1));
// }
}
@Override
public void visitAstLexicalRead(AstLexicalRead instruction) {
visitLexical(instruction, new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) {
@Override
protected void action(PointerKey lexicalKey, int vn) {
PointerKey lval = getPointerKeyForLocal(vn);
if (lexicalKey instanceof LocalPointerKey) {
CGNode lnode = ((LocalPointerKey) lexicalKey).getNode();
int lvn = ((LocalPointerKey) lexicalKey).getValueNumber();
IRView lir = getBuilder().getCFAContextInterpreter().getIRView(lnode);
SymbolTable lsymtab = lir.getSymbolTable();
DefUse ldu = getBuilder().getCFAContextInterpreter().getDU(lnode);
// DefUse ldu = getAnalysisCache().getDefUse(lir);
if (contentsAreInvariant(lsymtab, ldu, lvn)) {
InstanceKey[] ik = getInvariantContents(lsymtab, ldu, lnode, lvn);
system.recordImplicitPointsToSet(lexicalKey);
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
system.newConstraint(lval, ik[i]);
}
return;
}
}
system.newConstraint(lval, assignOperator, lexicalKey);
}
});
}
@Override
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
visitLexical(instruction, new LexicalOperator((AstCGNode) node, instruction.getAccesses(), false) {
@Override
protected void action(PointerKey lexicalKey, int vn) {
PointerKey rval = getPointerKeyForLocal(vn);
if (contentsAreInvariant(symbolTable, du, vn)) {
InstanceKey[] ik = getInvariantContents(vn);
system.recordImplicitPointsToSet(rval);
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
system.newConstraint(lexicalKey, ik[i]);
}
} else {
system.newConstraint(lexicalKey, assignOperator, rval);
}
}
});
}
@Override
public void visitAstGlobalRead(AstGlobalRead instruction) {
visitGetInternal(instruction.getDef(), -1, true, instruction.getDeclaredField());
}
@Override
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
visitPutInternal(instruction.getVal(), -1, true, instruction.getDeclaredField());
}
@Override
public void visitPut(SSAPutInstruction inst) {
super.visitPut(inst);
if (inst.isStatic() || !getBuilder().useObjectCatalog())
return;
// update the object catalog corresponding to the base pointer, adding the
// name of the field as a property
SymbolTable symtab = ir.getSymbolTable();
int objVn = inst.getRef();
String fieldName = null;
try {
fieldName = inst.getDeclaredField().getName().toUnicodeString();
} catch (UTFDataFormatException e) {
Assertions.UNREACHABLE();
}
final PointerKey objKey = getPointerKeyForLocal(objVn);
final InstanceKey[] fieldNameKeys = new InstanceKey[] { getInstanceKeyForConstant(fieldName) };
assert fieldNameKeys.length == 1;
if (contentsAreInvariant(symtab, du, objVn)) {
system.recordImplicitPointsToSet(objKey);
final InstanceKey[] objKeys = getInvariantContents(objVn);
for (int i = 0; i < objKeys.length; i++) {
if (!getBuilder().isUncataloguedField(objKeys[i].getConcreteType(), fieldName)) {
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[i]);
if (objCatalog != null) {
system.newConstraint(objCatalog, fieldNameKeys[0]);
}
}
}
} else {
final String hack = fieldName;
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
final IntSetVariable<?> objects = rhs;
if (objects.getValue() != null) {
objects.getValue().foreach(new IntSetAction() {
@Override
public void act(int optr) {
InstanceKey object = system.getInstanceKey(optr);
if (!getBuilder().isUncataloguedField(object.getConcreteType(), hack)) {
PointerKey cat = getPointerKeyForObjectCatalog(object);
if (cat != null) {
system.newConstraint(cat, fieldNameKeys[0]);
}
}
}
});
}
return NOT_CHANGED;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public String toString() {
return "field name record: " + objKey;
}
}, objKey);
}
}
@Override
public void visitAssert(AstAssertInstruction instruction) {
}
@Override
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
}
@Override
public void visitEachElementGet(EachElementGetInstruction inst) {
int lval = inst.getDef(0);
final PointerKey lk = getPointerKeyForLocal(lval);
int rval = inst.getUse(0);
final PointerKey rk = getPointerKeyForLocal(rval);
if (contentsAreInvariant(symbolTable, du, rval)) {
InstanceKey objects[] = getInvariantContents(rval);
for (int i = 0; i < objects.length; i++) {
PointerKey catalog = getPointerKeyForObjectCatalog(objects[i]);
system.newConstraint(lk, assignOperator, catalog);
}
}
else {
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
final IntSetVariable<?> objects = rhs;
if (objects.getValue() != null) {
objects.getValue().foreach(new IntSetAction() {
@Override
public void act(int optr) {
InstanceKey object = system.getInstanceKey(optr);
PointerKey objCatalog = getPointerKeyForObjectCatalog(object);
if (objCatalog != null) {
system.newConstraint(lk, assignOperator, objCatalog);
}
}
});
}
return NOT_CHANGED;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public String toString() {
return "get catalog op" + rk;
}
}, rk);
}
}
@Override
public void visitIsDefined(AstIsDefinedInstruction inst) {
}
@Override
public void visitEcho(AstEchoInstruction inst) {
}
// /////////////////////////////////////////////////////////////////////////
//
// lexical scoping handling
//
// /////////////////////////////////////////////////////////////////////////
private abstract class LexicalOperator extends UnaryOperator<PointsToSetVariable> {
/**
* node in which lexical accesses are performed
*/
private final AstCGNode node;
/**
* the lexical accesses to be handled
*/
private final Access[] accesses;
/**
* are all the lexical accesses loads? if false, they are all stores
*/
private final boolean isLoad;
private LexicalOperator(AstCGNode node, Access[] accesses, boolean isLoad) {
this.node = node;
this.isLoad = isLoad;
this.accesses = accesses;
}
/**
* perform the necessary {@link #action(PointerKey, int)}s for the
* accesses. For each access, we determine the possible {@link CGNode}s
* corresponding to its definer (see
* {@link AstConstraintVisitor#getLexicalDefiners(CGNode, String)}). Handle
* using
* {@link AstConstraintVisitor#handleRootLexicalReference(String, String, CGNode)}
* .
*/
private void doLexicalPointerKeys(boolean funargsOnly) {
for (int i = 0; i < accesses.length; i++) {
final String name = accesses[i].variableName;
final String definer = accesses[i].variableDefiner;
final int vn = accesses[i].valueNumber;
if (AstTranslator.DEBUG_LEXICAL)
System.err.println(("looking up lexical parent " + definer));
Set<CGNode> creators = getLexicalDefiners(node, Pair.make(name, definer));
System.err.println("definers " + creators.size());
for (CGNode n : creators) {
PointerKey funargKey = handleRootLexicalReference(name, definer, n);
action(funargKey, vn);
}
}
}
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
doLexicalPointerKeys(true);
return NOT_CHANGED;
}
abstract protected void action(PointerKey lexicalKey, int vn);
@Override
public String toString() {
return "lexical op";
}
@Override
public boolean equals(Object o) {
if (!(o instanceof LexicalOperator)) {
return false;
} else {
LexicalOperator other = (LexicalOperator) o;
if (isLoad != other.isLoad) {
return false;
} else if (!node.equals(other.node)) {
return false;
} else if (accesses.length != other.accesses.length) {
return false;
} else {
for (int i = 0; i < accesses.length; i++) {
if (!accesses[i].equals(other.accesses[i])) {
return false;
}
}
for (int i = 0; i < accesses.length; i++) {
if (!accesses[i].equals(other.accesses[i])) {
return false;
}
}
return true;
}
}
}
@Override
public int hashCode() {
return node.hashCode() * accesses[0].hashCode() * accesses.length;
}
}
private Set<CGNode> getLexicalDefiners(final CGNode opNode, final Pair<String, String> definer) {
if (definer == null) {
return Collections.singleton(getBuilder().getCallGraph().getFakeRootNode());
} else if (getBuilder().sameMethod(opNode, definer.snd)) {
// lexical access to a variable declared in opNode itself
return Collections.singleton(opNode);
} else {
final Set<CGNode> result = HashSetFactory.make();
PointerKey F = getBuilder().getPointerKeyForLocal(opNode, 1);
IRView ir = getBuilder().getCFAContextInterpreter().getIRView(opNode);
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode);
if (contentsAreInvariant(symtab, du, 1)) {
system.recordImplicitPointsToSet(F);
final InstanceKey[] functionKeys = getInvariantContents(symtab, du, opNode, 1);
for (int f = 0; f < functionKeys.length; f++) {
system.findOrCreateIndexForInstanceKey(functionKeys[f]);
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) functionKeys[f];
Iterator<CGNode> x = K.getFunargNodes(definer);
while (x.hasNext()) {
result.add(x.next());
}
}
} else {
PointsToSetVariable FV = system.findOrCreatePointsToSet(F);
if (FV.getValue() != null) {
FV.getValue().foreach(new IntSetAction() {
@Override
public void act(int ptr) {
InstanceKey iKey = system.getInstanceKey(ptr);
if (iKey instanceof ScopeMappingInstanceKey) {
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey;
Iterator<CGNode> x = K.getFunargNodes(definer);
while (x.hasNext()) {
result.add(x.next());
}
} else {
Assertions.UNREACHABLE("unexpected instance key " + iKey);
}
}
});
}
}
return result;
}
}
private Set<PointerKey> discoveredUpwardFunargs = HashSetFactory.make();
/**
* add constraints that assign the final value of name in definingNode to
* the upward funarg (lhs), modeling adding of the state to the closure
*/
private void addUpwardFunargConstraints(PointerKey lhs, String name, String definer, CGNode definingNode) {
discoveredUpwardFunargs.add(lhs);
LexicalInformation LI = ((AstIRFactory<?>.AstIR) definingNode.getIR()).lexicalInfo();
Pair<String, String>[] names = LI.getExposedNames();
for (int i = 0; i < names.length; i++) {
if (name.equals(names[i].fst) && definer.equals(names[i].snd)) {
int vn = LI.getExitExposedUses()[i];
if (vn > 0) {
IRView ir = getBuilder().getCFAContextInterpreter().getIRView(definingNode);
DefUse du = getBuilder().getCFAContextInterpreter().getDU(definingNode);
SymbolTable st = ir.getSymbolTable();
PointerKey rhs = getBuilder().getPointerKeyForLocal(definingNode, vn);
if (contentsAreInvariant(st, du, vn)) {
system.recordImplicitPointsToSet(rhs);
final InstanceKey[] objs = getInvariantContents(st, du, definingNode, vn);
for (int f = 0; f < objs.length; f++) {
system.findOrCreateIndexForInstanceKey(objs[f]);
system.newConstraint(lhs, objs[f]);
}
} else {
system.newConstraint(lhs, assignOperator, rhs);
}
}
return;
}
}
Assertions.UNREACHABLE();
}
/**
* handle a lexical reference where we found no parent call graph node
* defining the name; it's either a global or an upward funarg
*/
private PointerKey handleRootLexicalReference(String name, String definer, final CGNode definingNode) {
// global variable
if (definer == null) {
return new AstGlobalPointerKey(name);
// upward funarg
} else {
class UpwardFunargPointerKey extends AstGlobalPointerKey {
UpwardFunargPointerKey(String name) {
super(name);
}
public CGNode getDefiningNode() {
return definingNode;
}
@Override
public boolean equals(Object x) {
return (x instanceof UpwardFunargPointerKey)
&& super.equals(x)
&& (definingNode == null ? definingNode == ((UpwardFunargPointerKey) x).getDefiningNode() : definingNode
.equals(((UpwardFunargPointerKey) x).getDefiningNode()));
}
@Override
public int hashCode() {
return super.hashCode() * ((definingNode == null) ? 17 : definingNode.hashCode());
}
@Override
public String toString() {
return "[upward:" + getName() + ":" + definingNode + "]";
}
}
PointerKey result = new UpwardFunargPointerKey(name);
if (!discoveredUpwardFunargs.contains(result) && definingNode != null) {
addUpwardFunargConstraints(result, name, definer, definingNode);
}
return result;
}
}
// /////////////////////////////////////////////////////////////////////////
//
// property manipulation handling
//
// /////////////////////////////////////////////////////////////////////////
protected interface ReflectedFieldAction {
void action(AbstractFieldPointerKey fieldKey);
void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp);
}
private void newFieldOperation(CGNode opNode, final int objVn, final int fieldsVn, final boolean isLoadOperation,
final ReflectedFieldAction action) {
IRView ir = getBuilder().getCFAContextInterpreter().getIRView(opNode);
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode);
PointerKey objKey = getBuilder().getPointerKeyForLocal(opNode, objVn);
final PointerKey fieldKey = getBuilder().getPointerKeyForLocal(opNode, fieldsVn);
// log field access
if (DEBUG_PROPERTIES) {
if (isLoadOperation)
System.err.print(("adding read of " + objKey + "." + fieldKey + ":"));
else
System.err.print(("adding write of " + objKey + "." + fieldKey + ":"));
if (contentsAreInvariant(symtab, du, objVn)) {
System.err.print(" constant obj:");
InstanceKey[] x = getInvariantContents(symtab, du, opNode, objVn);
for (int i = 0; i < x.length; i++) {
System.err.print((x[i].toString() + " "));
}
} else {
System.err.print((" obj:" + system.findOrCreatePointsToSet(objKey)));
}
if (contentsAreInvariant(symtab, du, fieldsVn)) {
System.err.print(" constant prop:");
InstanceKey[] x = getInvariantContents(symtab, du, opNode, fieldsVn);
for (int i = 0; i < x.length; i++) {
System.err.print((x[i].toString() + " "));
}
} else {
System.err.print((" props:" + system.findOrCreatePointsToSet(fieldKey)));
}
System.err.print("\n");
}
// make sure instance keys get mapped for PointerAnalysisImpl
if (contentsAreInvariant(symtab, du, objVn)) {
InstanceKey[] x = getInvariantContents(symtab, du, opNode, objVn);
for (int i = 0; i < x.length; i++) {
system.findOrCreateIndexForInstanceKey(x[i]);
}
}
if (contentsAreInvariant(symtab, du, fieldsVn)) {
InstanceKey[] x = getInvariantContents(symtab, du, opNode, fieldsVn);
for (int i = 0; i < x.length; i++) {
system.findOrCreateIndexForInstanceKey(x[i]);
}
}
// process field access
if (contentsAreInvariant(symtab, du, objVn)) {
system.recordImplicitPointsToSet(objKey);
final InstanceKey[] objKeys = getInvariantContents(symtab, du, opNode, objVn);
if (contentsAreInvariant(symtab, du, fieldsVn)) {
system.recordImplicitPointsToSet(fieldKey);
InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objKeys, fieldsKeys);
} else {
newFieldOperationOnlyObjectConstant(isLoadOperation, action, fieldKey, objKeys);
}
} else {
if (contentsAreInvariant(symtab, du, fieldsVn)) {
system.recordImplicitPointsToSet(fieldKey);
final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn);
newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys);
} else {
newFieldFullOperation(isLoadOperation, action, objKey, fieldKey);
}
}
if (DEBUG_PROPERTIES) {
System.err.println("finished\n");
}
}
protected void newFieldOperationFieldConstant(CGNode opNode, final boolean isLoadOperation, final ReflectedFieldAction action,
final int objVn, final InstanceKey[] fieldsKeys) {
IRView ir = getBuilder().getCFAContextInterpreter().getIRView(opNode);
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode);
PointerKey objKey = getBuilder().getPointerKeyForLocal(opNode, objVn);
if (contentsAreInvariant(symtab, du, objVn)) {
system.recordImplicitPointsToSet(objKey);
InstanceKey[] objectKeys = getInvariantContents(symtab, du, opNode, objVn);
newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objectKeys, fieldsKeys);
} else {
newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys);
}
}
protected void newFieldFullOperation(final boolean isLoadOperation, final ReflectedFieldAction action, PointerKey objKey,
final PointerKey fieldKey) {
system.newSideEffect(new AbstractOperator<PointsToSetVariable>() {
private final MutableIntSet doneReceiver = IntSetUtil.make();
private final MutableIntSet doneField = IntSetUtil.make();
@Override
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
final IntSetVariable<?> receivers = rhs[0];
final IntSetVariable<?> fields = rhs[1];
if (receivers.getValue() != null && fields.getValue() != null) {
receivers.getValue().foreach(new IntSetAction() {
@Override
public void act(final int rptr) {
final InstanceKey receiver = system.getInstanceKey(rptr);
if (!isLoadOperation) {
PointerKey cat = getPointerKeyForObjectCatalog(receiver);
if (cat != null) {
system.newConstraint(cat, assignOperator, fieldKey);
}
}
fields.getValue().foreach(new IntSetAction() {
@Override
public void act(int fptr) {
if (!doneField.contains(fptr) || !doneReceiver.contains(rptr)) {
InstanceKey field = system.getInstanceKey(fptr);
for (Iterator<PointerKey> keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(receiver, field)
: getPointerKeysForReflectedFieldWrite(receiver, field); keys.hasNext();) {
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, false, false);
action.action(key);
}
}
}
});
}
});
doneReceiver.addAll(receivers.getValue());
doneField.addAll(fields.getValue());
}
return NOT_CHANGED;
}
@Override
public String toString() {
return "field op";
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
}, objKey, fieldKey);
}
protected void newFieldOperationOnlyFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action,
final PointerKey objKey, final InstanceKey[] fieldsKeys) {
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
final IntSetVariable<?> objects = rhs;
if (objects.getValue() != null) {
objects.getValue().foreach(new IntSetAction() {
@Override
public void act(int optr) {
InstanceKey object = system.getInstanceKey(optr);
PointerKey objCatalog = getPointerKeyForObjectCatalog(object);
for (int f = 0; f < fieldsKeys.length; f++) {
if (isLoadOperation) {
for (Iterator<PointerKey> keys = getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]); keys.hasNext();) {
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, true, false);
action.action(key);
}
} else {
if (objCatalog != null) {
system.newConstraint(objCatalog, fieldsKeys[f]);
}
for (Iterator<PointerKey> keys = getPointerKeysForReflectedFieldWrite(object, fieldsKeys[f]); keys.hasNext();) {
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, true, false);
action.action(key);
}
}
}
}
});
}
return NOT_CHANGED;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public String toString() {
return "field op" + objKey;
}
}, objKey);
}
protected void newFieldOperationOnlyObjectConstant(final boolean isLoadOperation, final ReflectedFieldAction action,
final PointerKey fieldKey, final InstanceKey[] objKeys) {
if (!isLoadOperation) {
for (int o = 0; o < objKeys.length; o++) {
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
if (objCatalog != null) {
system.newConstraint(objCatalog, assignOperator, fieldKey);
}
}
}
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
final IntSetVariable<?> fields = rhs;
if (fields.getValue() != null) {
fields.getValue().foreach(new IntSetAction() {
@Override
public void act(int fptr) {
InstanceKey field = system.getInstanceKey(fptr);
for (int o = 0; o < objKeys.length; o++) {
for (Iterator<PointerKey> keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(objKeys[o], field)
: getPointerKeysForReflectedFieldWrite(objKeys[o], field); keys.hasNext();) {
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, false, true);
action.action(key);
}
}
}
});
}
return NOT_CHANGED;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public String toString() {
return "field op" + fieldKey;
}
}, fieldKey);
}
protected void newFieldOperationObjectAndFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action,
final InstanceKey[] objKeys, InstanceKey[] fieldsKeys) {
for (int o = 0; o < objKeys.length; o++) {
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
for (int f = 0; f < fieldsKeys.length; f++) {
if (isLoadOperation) {
for (Iterator<PointerKey> keys = getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, true, true);
action.action(key);
}
} else {
if (objCatalog != null) {
system.newConstraint(objCatalog, fieldsKeys[f]);
}
for (Iterator<PointerKey> keys = getPointerKeysForReflectedFieldWrite(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, true, true);
action.action(key);
}
}
}
}
}
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
IRView ir = getBuilder().getCFAContextInterpreter().getIRView(opNode);
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode);
PointerKey rhsKey = getBuilder().getPointerKeyForLocal(opNode, rhsVn);
if (contentsAreInvariant(symtab, du, rhsVn)) {
system.recordImplicitPointsToSet(rhsKey);
newFieldWrite(opNode, objVn, fieldsVn, getInvariantContents(symtab, du, opNode, rhsVn));
} else {
newFieldWrite(opNode, objVn, fieldsVn, rhsKey);
}
}
private final class ConstantWriter implements ReflectedFieldAction {
private final InstanceKey[] rhsFixedValues;
private ConstantWriter(InstanceKey[] rhsFixedValues) {
this.rhsFixedValues = rhsFixedValues;
}
@Override
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp));
for (int i = 0; i < rhsFixedValues.length; i++) {
System.err.println(("writing " + rhsFixedValues[i]));
}
}
@Override
public void action(AbstractFieldPointerKey fieldKey) {
if (!representsNullType(fieldKey.getInstanceKey())) {
for (int i = 0; i < rhsFixedValues.length; i++) {
system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]);
system.newConstraint(fieldKey, rhsFixedValues[i]);
}
}
}
}
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
newFieldOperation(opNode, objVn, fieldsVn, false, new ConstantWriter(rhsFixedValues));
}
public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final InstanceKey[] rhsValues) {
newFieldOperationFieldConstant(opNode, false, new ConstantWriter(rhsValues), objVn, fieldKeys);
}
private final class NormalWriter implements ReflectedFieldAction {
private final PointerKey rhs;
private NormalWriter(PointerKey rhs) {
this.rhs = rhs;
}
@Override
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp));
}
@Override
public void action(AbstractFieldPointerKey fieldKey) {
if (!representsNullType(fieldKey.getInstanceKey())) {
system.newConstraint(fieldKey, assignOperator, rhs);
}
}
}
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
newFieldOperation(opNode, objVn, fieldsVn, false, new NormalWriter(rhs));
}
public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final PointerKey rhs) {
newFieldOperationFieldConstant(opNode, false, new NormalWriter(rhs), objVn, fieldKeys);
}
protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, int lhsVn) {
newFieldRead(opNode, objVn, fieldsVn, getBuilder().getPointerKeyForLocal(opNode, lhsVn));
}
protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, final PointerKey lhs) {
newFieldOperation(opNode, objVn, fieldsVn, true, new ReflectedFieldAction() {
@Override
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
System.err.println(("read " + lhs + " from " + fieldKey + " " + constObj + ", " + constProp));
}
@Override
public void action(AbstractFieldPointerKey fieldKey) {
if (!representsNullType(fieldKey.getInstanceKey())) {
system.newConstraint(lhs, assignOperator, fieldKey);
AbstractFieldPointerKey unknown = getBuilder().fieldKeyForUnknownWrites(fieldKey);
if (unknown != null) {
system.newConstraint(lhs, assignOperator, unknown);
}
}
}
});
}
}
/**
* If the given fieldKey represents a concrete field, return the corresponding field key that
* represents all writes to unknown fields that could potentially alias fieldKey
*/
protected abstract AbstractFieldPointerKey fieldKeyForUnknownWrites(AbstractFieldPointerKey fieldKey);
/**
*
* Is definingMethod the same as the method represented by opNode? We need this since the names for
* methods in some languages don't map in the straightforward way to the CGNode
*/
protected abstract boolean sameMethod(final CGNode opNode, final String definingMethod);
}