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

1156 lines
36 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.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.ibm.wala.analysis.reflection.FactoryBypassInterpreter;
import com.ibm.wala.analysis.typeInference.TypeInference;
import com.ibm.wala.cast.analysis.typeInference.AstTypeInference;
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.*;
import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR;
import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access;
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.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.fixedpoint.impl.AbstractOperator;
import com.ibm.wala.fixedpoint.impl.UnaryOperator;
import com.ibm.wala.fixpoint.IVariable;
import com.ibm.wala.fixpoint.IntSetVariable;
import com.ibm.wala.ipa.callgraph.*;
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
import com.ibm.wala.ipa.callgraph.propagation.*;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultSSAInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ssa.*;
import com.ibm.wala.ssa.SSACFG.BasicBlock;
import com.ibm.wala.util.Function;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.debug.Trace;
import com.ibm.wala.util.graph.traverse.NumberedDFSDiscoverTimeIterator;
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.warnings.WarningSet;
public abstract class AstSSAPropagationCallGraphBuilder
extends SSAPropagationCallGraphBuilder
{
public static final boolean DEBUG_TYPE_INFERENCE = false;
public static final boolean DEBUG_PROPERTIES = false;
/////////////////////////////////////////////////////////////////////////////
//
// language specialization interface
//
/////////////////////////////////////////////////////////////////////////////
protected abstract boolean useObjectCatalog();
/////////////////////////////////////////////////////////////////////////////
//
// overall control
//
/////////////////////////////////////////////////////////////////////////////
protected
AstSSAPropagationCallGraphBuilder(ClassHierarchy cha,
WarningSet warnings,
AnalysisOptions options,
PointerKeyFactory pointerKeyFactory)
{
super(cha, warnings, options, pointerKeyFactory, options.usePreTransitiveSolver());
}
public SSAContextInterpreter
makeDefaultContextInterpreters(SSAContextInterpreter appContextInterpreter,
AnalysisOptions options,
ClassHierarchy cha,
ReflectionSpecification reflect,
WarningSet warnings)
{
SSAContextInterpreter c = new DefaultSSAInterpreter(options, cha, warnings);
c = new DelegatingSSAContextInterpreter(new AstContextInsensitiveSSAContextInterpreter(options, cha), c);
c = new DelegatingSSAContextInterpreter(new FactoryBypassInterpreter(options, cha, reflect, warnings), c);
if (appContextInterpreter == null)
return c;
else
return new DelegatingSSAContextInterpreter(appContextInterpreter, c);
}
public PointerKey getPointerKeyForObjectCatalog(InstanceKey I) {
return ((AstPointerKeyFactory)pointerKeyFactory)
.getPointerKeyForObjectCatalog(I);
}
public Iterator
getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F)
{
return ((AstPointerKeyFactory)pointerKeyFactory)
.getPointerKeysForReflectedFieldRead(I, F);
}
public Iterator
getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F)
{
return ((AstPointerKeyFactory)pointerKeyFactory)
.getPointerKeysForReflectedFieldWrite(I, F);
}
/////////////////////////////////////////////////////////////////////////////
//
// specialized pointer analysis
//
/////////////////////////////////////////////////////////////////////////////
protected class AstPointerFlowGraph extends PointerFlowGraph {
protected class AstPointerFlowVisitor
extends InstructionVisitor
implements AstInstructionVisitor
{
protected AstPointerFlowVisitor(CGNode node, IR ir, BasicBlock bb) {
super(node, ir, bb);
}
public void visitAstLexicalRead(AstLexicalRead instruction) {
}
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
}
public void visitAstGlobalRead(AstGlobalRead instruction) {
}
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
}
public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) {
}
public void visitAssert(AstAssertInstruction instruction) {
}
public void visitEachElementGet(EachElementGetInstruction inst) {
}
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
}
}
protected AstPointerFlowGraph(PointerAnalysis pa, CallGraph cg) {
super(pa,cg);
}
protected InstructionVisitor makeInstructionVisitor(CGNode node, IR ir, BasicBlock bb) {
return new AstPointerFlowVisitor(node,ir, bb);
}
}
public PointerFlowGraphFactory getPointerFlowGraphFactory() {
return new PointerFlowGraphFactory() {
public PointerFlowGraph make(PointerAnalysis pa, CallGraph cg) {
return new AstPointerFlowGraph(pa,cg);
}
};
}
/////////////////////////////////////////////////////////////////////////////
//
// top-level node constraint generation
//
/////////////////////////////////////////////////////////////////////////////
protected ExplicitCallGraph createEmptyCallGraph(ClassHierarchy cha, AnalysisOptions options) {
return new AstCallGraph(cha, options, getWarnings());
}
protected TypeInference makeTypeInference(IR ir, ClassHierarchy cha) {
TypeInference ti = new AstTypeInference(ir, cha, false);
ti.solve();
if (DEBUG_TYPE_INFERENCE) {
Trace.println("IR of " + ir.getMethod());
Trace.println( ir );
Trace.println("TypeInference of " + ir.getMethod());
for(int i = 0; i < ir.getSymbolTable().getMaxValueNumber(); i++) {
if (ti.isUndefined(i)) {
Trace.println(" value " + i + " is undefined");
} else {
Trace.println(" value " + i + " has type " + ti.getType(i));
}
}
}
return ti;
}
protected class AstInterestingVisitor
extends InterestingVisitor
implements AstInstructionVisitor
{
protected AstInterestingVisitor(int vn) {
super(vn);
}
public void visitAstLexicalRead(AstLexicalRead instruction) {
bingo = true;
}
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
bingo = true;
}
public void visitAstGlobalRead(AstGlobalRead instruction) {
bingo = true;
}
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
bingo = true;
}
public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) {
bingo = true;
}
public void visitAssert(AstAssertInstruction instruction) {
bingo = true;
}
public void visitEachElementGet(EachElementGetInstruction inst) {
bingo = true;
}
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
}
}
protected InterestingVisitor makeInterestingVisitor(int vn) {
return new AstInterestingVisitor(vn);
}
/////////////////////////////////////////////////////////////////////////////
//
// lexical scoping handling
//
/////////////////////////////////////////////////////////////////////////////
private abstract class LexicalOperator extends UnaryOperator {
private final AstCGNode node;
private final Access[] accesses;
private final boolean isLoad;
private LexicalOperator(AstCGNode node,
Access[] accesses,
boolean isLoad)
{
this.node = node;
this.isLoad = isLoad;
this.accesses = accesses;
}
private void doLexicalPointerKeys() {
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)
Trace.println("looking up lexical parent " + definer);
for(Iterator DS = getLexicalDefiners(node, definer).iterator();
DS.hasNext(); )
{
final CGNode D = (CGNode) DS.next();
Iterator PS = new NumberedDFSDiscoverTimeIterator(callGraph, node) {
/**
*
*/
private static final long serialVersionUID = 4546217460630659884L;
protected void visitEdge(Object callee, Object caller) {
CGNode from = (CGNode) caller;
CGNode to = (CGNode) callee;
for(Iterator SS = from.getPossibleSites(to); SS.hasNext(); ) {
CallSiteReference site = (CallSiteReference)SS.next();
PointerKey V =
isLoad?
getLocalReadKey(from, site, name, definer, D):
getLocalWriteKey(from, site, name, definer, D);
if (V != null) {
action(V, vn);
}
}
}
protected Iterator getConnected(Object n) {
if (n.equals(D) )
return EmptyIterator.instance();
else
return G.getPredNodes(n);
}
};
while (PS.hasNext()) { PS.next(); }
}
}
}
public byte evaluate(IVariable lhs, IVariable rhs) {
doLexicalPointerKeys();
return NOT_CHANGED;
}
abstract void action(PointerKey lexicalKey, int vn);
public String toString() { return "lexical op"; }
public boolean equals(Object o) { return o==this; }
public int hashCode() { return System.identityHashCode(this); }
}
private Set getLexicalDefiners(final CGNode opNode, final String definer) {
if (definer == null) {
return Collections.singleton(callGraph.getFakeRootNode());
} else {
final Set result = new HashSet();
PointerKey F = getPointerKeyForLocal(opNode, 1);
IR ir = getCFAContextInterpreter().getIR(opNode, getWarnings());
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getOptions().getSSACache().findOrCreateDU(ir, opNode.getContext());
if (contentsAreInvariant(symtab, du, 1)) {
system.recordImplicitPointsToSet(F);
final InstanceKey[] functionKeys =
getInvariantContents(symtab, du, opNode, 1, this);
for(int f = 0; f < functionKeys.length; f++) {
system.findOrCreateIndexForInstanceKey( functionKeys[f] );
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey)functionKeys[f];
result.add( K.getDefiningNode( definer ) );
}
} else {
PointsToSetVariable FV = system.findOrCreatePointsToSet( F );
if (FV.getValue() != null) {
FV.getValue().foreach(new IntSetAction() {
public void act(int ptr) {
InstanceKey iKey = system.getInstanceKey(ptr);
if (iKey instanceof ScopeMappingInstanceKey) {
ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey;
result.add( K.getDefiningNode( definer ) );
} else {
Assertions.UNREACHABLE("unexpected instance key " + iKey);
}
}
});
}
}
return result;
}
}
private boolean isEqual(Object a, Object b) {
if (a == null) return b==null; else return a.equals(b);
}
private Set discoveredUpwardFunargs = new HashSet();
private void addUpwardFunargConstraints(PointerKey lhs,
String name,
String definer,
CGNode definingNode)
{
discoveredUpwardFunargs.add( lhs );
LexicalInformation LI = ((AstMethod)definingNode.getMethod()).lexicalInfo;
Pair[] 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) {
IR ir = getCFAContextInterpreter().getIR(definingNode, getWarnings());
DefUse du = getCFAContextInterpreter().getDU(definingNode, getWarnings());
SymbolTable st = ir.getSymbolTable();
PointerKey rhs = getPointerKeyForLocal(definingNode, vn);
if (contentsAreInvariant(st, du, vn)) {
system.recordImplicitPointsToSet(rhs);
final InstanceKey[] objs = getInvariantContents(st, du, definingNode, vn, this);
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();
}
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; }
public boolean equals(Object x) {
return
(x instanceof UpwardFunargPointerKey) &&
super.equals(x) &&
definingNode.equals(((UpwardFunargPointerKey)x).getDefiningNode());
}
public int hashCode() {
return super.hashCode()*definingNode.hashCode();
}
public String toString() {
return "[upward:" + getName() + ":" + definingNode + "]";
}
}
PointerKey result = new UpwardFunargPointerKey(name);
if (! discoveredUpwardFunargs.contains( result )) {
addUpwardFunargConstraints(result, name, definer, definingNode);
}
return result;
}
}
private PointerKey getLocalReadKey(CGNode n,
CallSiteReference callSite,
String name,
String definer,
CGNode definingNode)
{
IMethod M = n.getMethod();
if (n == callGraph.getFakeRootNode()) {
return handleRootLexicalReference(name, definer, definingNode);
}
else if (M instanceof AstMethod) {
AstIR ir = (AstIR)getCFAContextInterpreter().getIR(n, getWarnings());
int pc = callSite.getProgramCounter();
LexicalInformation L = ((AstMethod)M).lexicalInfo;
// some people have no lexical uses at all
if (L == null) {
return null;
}
AbstractLexicalInvoke I =
(AbstractLexicalInvoke) ir.getInstructions()[pc];
// find existing explicit lexical use
for(int i = I.getNumberOfParameters(); i < I.getNumberOfUses(); i++) {
Access A = I.getLexicalUse(i);
if (A.variableName.equals(name)&&isEqual(A.variableDefiner,definer)) {
return getPointerKeyForLocal(n, A.valueNumber);
}
}
// make new lexical use
int values[] = L.getExposedUses(pc);
Pair names[] = L.getExposedNames();
if (names != null && names.length > 0) {
for(int i = 0; i < names.length; i++) {
if (name.equals(names[i].fst) && isEqual(definer,names[i].snd)) {
if (values[i] == -1) return null;
I.addLexicalUse(new Access(name, definer, values[i]));
if (SSAConversion.DEBUG_UNDO)
Trace.println("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses()-1) + " at inst " + pc);
SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses()-1);
return getPointerKeyForLocal(n, values[i]);
}
}
}
return null;
} else {
return null;
}
}
private PointerKey getLocalWriteKey(CGNode n,
CallSiteReference callSite,
String name,
String definer,
CGNode definingNode)
{
IMethod M = n.getMethod();
if (n == callGraph.getFakeRootNode()) {
return handleRootLexicalReference(name, definer, definingNode);
}
else if (M instanceof AstMethod) {
AstMethod AstM = (AstMethod)M;
LexicalInformation L = AstM.lexicalInfo;
// some people have no lexical uses at all
if (L == null) return null;
AstIR ir = (AstIR)getCFAContextInterpreter().getIR(n, getWarnings());
int pc = callSite.getProgramCounter();
AbstractLexicalInvoke I =
(AbstractLexicalInvoke) ir.getInstructions()[pc];
// find existing explicit lexical def
for(int i = 2; i < I.getNumberOfDefs(); i++) {
Access A = I.getLexicalDef(i);
if (A.variableName.equals(name)&&isEqual(A.variableDefiner,definer)) {
return getPointerKeyForLocal(n, A.valueNumber);
}
}
// make new lexical def
int values[] = L.getExposedUses(pc);
Pair names[] = L.getExposedNames();
if (names != null && names.length > 0) {
for(int i = 0; i < names.length; i++) {
if (name.equals(names[i].fst) && isEqual(definer,names[i].snd)) {
if (values[i] == -1) return null;
// if values[i] was altered by copy propagation, we must undo
// that to ensure we do not bash the wrong value number in the
// the next steps.
SSAConversion.undoCopyPropagation(ir, pc, -i - 1);
// possibly new instruction due to renames, so get it again
I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
I.addLexicalDef(new Access(name, definer, values[i]));
if (SSAConversion.DEBUG_UNDO)
Trace.println("new def of " + values[i] + " at inst " + pc + ": " + I);
// new def has broken SSA form for values[i], so fix for that value
MutableIntSet vs = IntSetUtil.make();
vs.add( values[i] );
SSAConversion.convert(AstM, ir, getOptions().getSSAOptions());
// now redo analysis
// TODO: only values[i] uses need to be re-done.
getOptions().getSSACache().invalidateDU(M, n.getContext());
// addConstraintsFromChangedNode(n);
markChanged( n );
// get SSA-renamed def from call site instruction
return getLocalWriteKey(n, callSite, name, definer, definingNode);
}
}
}
return null;
} else {
return null;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// property manipulation handling
//
/////////////////////////////////////////////////////////////////////////////
private interface ReflectedFieldAction {
void action(PointerKey fieldKey);
void dump(PointerKey fieldKey, boolean constObj, boolean constProp);
}
private void newFieldOperation(CGNode opNode, final int objVn, final int fieldsVn, final boolean isLoadOperation, final ReflectedFieldAction action) {
IR ir = getCFAContextInterpreter().getIR(opNode, getWarnings());
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getCFAContextInterpreter().getDU(opNode, getWarnings());
PointerKey objKey = getPointerKeyForLocal(opNode, objVn);
final PointerKey fieldKey = getPointerKeyForLocal(opNode, fieldsVn);
// log field access
if (DEBUG_PROPERTIES) {
if (isLoadOperation)
Trace.print("adding read of " + objKey + "." + fieldKey + ":");
else
Trace.print("adding write of " + objKey + "." + fieldKey + ":");
if (contentsAreInvariant(symtab, du, objVn)) {
Trace.print(" constant obj:");
InstanceKey[] x=getInvariantContents(symtab, du, opNode, objVn, this);
for(int i = 0 ; i < x.length; i++) {
Trace.print( x[i].toString() + " " );
}
} else {
Trace.print(" obj:" + system.findOrCreatePointsToSet(objKey));
}
if (contentsAreInvariant(symtab, du, fieldsVn)) {
Trace.print(" constant prop:");
InstanceKey[] x=getInvariantContents(symtab, du, opNode, fieldsVn, this);
for(int i = 0 ; i < x.length; i++) {
Trace.print( x[i].toString() + " " );
}
} else {
Trace.print(" props:" + system.findOrCreatePointsToSet(fieldKey));
}
Trace.print("\n");
}
// make sure instance keys get mapped for PointerAnalysisImpl
if (contentsAreInvariant(symtab, du, objVn)) {
InstanceKey[] x=getInvariantContents(symtab, du, opNode, objVn, this);
for(int i = 0; i < x.length; i++) {
system.findOrCreateIndexForInstanceKey(x[i]);
}
}
if (contentsAreInvariant(symtab, du, fieldsVn)) {
InstanceKey[] x=getInvariantContents(symtab, du, opNode, fieldsVn, this);
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, this);
if (contentsAreInvariant(symtab, du, fieldsVn)) {
system.recordImplicitPointsToSet(fieldKey);
InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn, this);
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 keys =
getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]);
keys.hasNext(); )
{
PointerKey key = (PointerKey)keys.next();
if (DEBUG_PROPERTIES) action.dump( key, true, true );
action.action( key );
}
} else {
system.newConstraint(objCatalog, fieldsKeys[f]);
for(Iterator keys =
getPointerKeysForReflectedFieldWrite(objKeys[o],fieldsKeys[f]);
keys.hasNext(); )
{
PointerKey key = (PointerKey)keys.next();
if (DEBUG_PROPERTIES) action.dump( key, true, true );
action.action( key );
}
}
}
}
} else {
if (! isLoadOperation) {
for(int o = 0; o < objKeys.length; o++) {
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]);
system.newConstraint(objCatalog, assignOperator, fieldKey);
}
}
system.newSideEffect(
new UnaryOperator() {
public byte evaluate(IVariable lhs, IVariable rhs) {
final IntSetVariable fields = (IntSetVariable) rhs;
if (fields.getValue() != null) {
fields.getValue().foreach(
new IntSetAction() {
public void act(int fptr) {
InstanceKey field = system.getInstanceKey(fptr);
for(int o = 0; o < objKeys.length; o++) {
for(Iterator keys =
isLoadOperation?
getPointerKeysForReflectedFieldRead(objKeys[o],field):
getPointerKeysForReflectedFieldWrite(objKeys[o],field);
keys.hasNext(); )
{
PointerKey key = (PointerKey)keys.next();
if (DEBUG_PROPERTIES) action.dump(key, false, true);
action.action( key );
}
}
}
}
);
}
return NOT_CHANGED;
}
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return o==this;
}
public String toString() {
return "field op" + objVn + ", " + fieldsVn;
}
},
fieldKey);
}
} else {
if (contentsAreInvariant(symtab, du, fieldsVn)) {
system.recordImplicitPointsToSet(fieldKey);
final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn, this);
system.newSideEffect(
new UnaryOperator() {
public byte evaluate(IVariable lhs, IVariable rhs) {
final IntSetVariable objects = (IntSetVariable) rhs;
if (objects.getValue() != null) {
objects.getValue().foreach(
new IntSetAction() {
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 keys =
getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]);
keys.hasNext(); )
{
PointerKey key = (PointerKey)keys.next();
if (DEBUG_PROPERTIES) action.dump(key, true, false);
action.action( key );
}
} else {
system.newConstraint(objCatalog, fieldsKeys[f]);
for(Iterator keys =
getPointerKeysForReflectedFieldWrite(object,fieldsKeys[f]);
keys.hasNext(); )
{
PointerKey key = (PointerKey)keys.next();
if (DEBUG_PROPERTIES) action.dump(key, true, false);
action.action( key );
}
}
}
}
}
);
}
return NOT_CHANGED;
}
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return o==this;
}
public String toString() {
return "field op" + objVn + ", " + fieldsVn;
}
},
objKey);
} else {
system.newSideEffect(
new AbstractOperator() {
public byte evaluate(IVariable lhs, final IVariable[] rhs) {
final IntSetVariable receivers = (IntSetVariable) rhs[0];
final IntSetVariable fields = (IntSetVariable) rhs[1];
if (receivers.getValue() != null && fields.getValue() != null) {
receivers.getValue().foreach(
new IntSetAction() {
public void act(int rptr) {
final InstanceKey receiver = system.getInstanceKey(rptr);
if (! isLoadOperation) {
PointerKey cat =
getPointerKeyForObjectCatalog(receiver);
system.newConstraint(cat, assignOperator, fieldKey);
}
fields.getValue().foreach(
new IntSetAction() {
public void act(int fptr) {
InstanceKey field = system.getInstanceKey(fptr);
for(Iterator keys =
isLoadOperation?
getPointerKeysForReflectedFieldRead(receiver, field):
getPointerKeysForReflectedFieldWrite(receiver, field);
keys.hasNext(); )
{
PointerKey key = (PointerKey)keys.next();
if (DEBUG_PROPERTIES)
action.dump(key, false, false);
action.action( key );
}
}
}
);
}
}
);
}
return NOT_CHANGED;
}
public String toString() { return "field op"; }
public boolean equals(Object o) { return o==this; }
public int hashCode() { return System.identityHashCode(this); }
},
objKey,
fieldKey);
}
}
if (DEBUG_PROPERTIES) {
Trace.println("finished\n");
}
}
protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
IR ir = getCFAContextInterpreter().getIR(opNode, getWarnings());
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getCFAContextInterpreter().getDU(opNode, getWarnings());
PointerKey rhsKey = getPointerKeyForLocal(opNode, rhsVn);
if (contentsAreInvariant(symtab, du, rhsVn)) {
system.recordImplicitPointsToSet(rhsKey);
newFieldWrite(opNode, objVn, fieldsVn, getInvariantContents(symtab, du, opNode, rhsVn, this));
} else {
newFieldWrite(opNode, objVn, fieldsVn, rhsKey);
}
}
protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
try {
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
public void dump(PointerKey fieldKey, boolean constObj, boolean constProp) {
Trace.println("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp);
for(int i = 0; i < rhsFixedValues.length; i++) {
Trace.println("writing " + rhsFixedValues[i]);
}
}
public void action(PointerKey fieldKey) {
for(int i = 0; i < rhsFixedValues.length; i++) {
system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]);
system.newConstraint(fieldKey, rhsFixedValues[i]);
}
}
});
} catch (RuntimeException e) {
System.err.println("error: " + e);
System.err.println( getCFAContextInterpreter().getIR(opNode, getWarnings()) );
throw e;
}
}
protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
public void dump(PointerKey fieldKey, boolean constObj, boolean constProp) {
Trace.println("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp);
}
public void action(PointerKey fieldKey) {
system.newConstraint(fieldKey, assignOperator, rhs);
}
});
}
protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, int lhsVn) {
newFieldRead(opNode, objVn, fieldsVn, getPointerKeyForLocal(opNode, lhsVn));
}
protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, final PointerKey lhs) {
newFieldOperation(opNode, objVn, fieldsVn, true, new ReflectedFieldAction() {
public void dump(PointerKey fieldKey, boolean constObj, boolean constProp) {
Trace.println("read " + lhs + " from " + fieldKey + " " + constObj + ", " + constProp);
}
public void action(PointerKey fieldKey) {
system.newConstraint(lhs, assignOperator, fieldKey);
}
});
}
/////////////////////////////////////////////////////////////////////////////
//
// IR visitor specialization for Ast-specific IR types
//
/////////////////////////////////////////////////////////////////////////////
protected class AstConstraintVisitor
extends ConstraintVisitor
implements AstInstructionVisitor
{
public AstConstraintVisitor(ExplicitCallGraph.ExplicitNode node, IR ir, ExplicitCallGraph callGraph, DefUse du) {
super(node, ir, callGraph, du);
}
public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) {
// no-op: exceptions handled elsewhere
// (see comment in SSAPropagationCallGraphBuilder)
}
private void visitLexical(final LexicalOperator op) {
final PointerKey function = getPointerKeyForLocal(node, 1);
if (contentsAreInvariant(symbolTable, du, 1)) {
op.doLexicalPointerKeys();
} else {
system.newSideEffect(op, function);
}
((AstCGNode)node).addCallback(new Function() {
public Object apply(Object ignore) {
op.doLexicalPointerKeys();
return null;
}
});
}
public void visitAstLexicalRead(AstLexicalRead instruction) {
visitLexical(new LexicalOperator((AstCGNode)node, instruction.getAccesses(), true) {
void action(PointerKey lexicalKey, int vn) {
PointerKey lval = getPointerKeyForLocal(node, vn);
if (lexicalKey instanceof LocalPointerKey) {
CGNode lnode = ((LocalPointerKey)lexicalKey).getNode();
int lvn = ((LocalPointerKey)lexicalKey).getValueNumber();
IR lir = getCFAContextInterpreter().getIR(lnode, getWarnings());
SymbolTable lsymtab = lir.getSymbolTable();
DefUse ldu = getOptions().getSSACache().findOrCreateDU(lir, lnode.getContext());
if (contentsAreInvariant(lsymtab, ldu, lvn)) {
InstanceKey[] ik = getInvariantContents(lsymtab, ldu, lnode, lvn, AstSSAPropagationCallGraphBuilder.this);
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);
}
});
}
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
visitLexical(new LexicalOperator((AstCGNode)node, instruction.getAccesses(), false) {
void action(PointerKey lexicalKey, int vn) {
PointerKey rval = getPointerKeyForLocal(node,vn);
if (contentsAreInvariant(symbolTable, du, vn)) {
InstanceKey[] ik = getInvariantContents(symbolTable, du, node, vn, AstSSAPropagationCallGraphBuilder.this);
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);
}
}
});
}
public void visitAstGlobalRead(AstGlobalRead instruction) {
visitGetInternal(instruction.getDef(),
-1,
true,
instruction.getDeclaredField());
}
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
visitPutInternal(instruction.getVal(),
-1,
true,
instruction.getDeclaredField());
}
public void visitPut(SSAPutInstruction inst) {
super.visitPut(inst);
if (inst.isStatic() || !useObjectCatalog()) return;
SymbolTable symtab = ir.getSymbolTable();
int objVn = inst.getRef();
String fieldName = inst.getDeclaredField().getName().toString();
int fieldNameVn = symtab.getConstant( fieldName );
final PointerKey objKey = getPointerKeyForLocal(node, objVn);
final InstanceKey[] fieldNameKeys =
getInvariantContents(symtab, du, node, fieldNameVn, AstSSAPropagationCallGraphBuilder.this);
Assertions._assert( fieldNameKeys.length == 1 );
if (contentsAreInvariant(symtab, du, objVn)) {
system.recordImplicitPointsToSet(objKey);
final InstanceKey[] objKeys =
getInvariantContents(symtab, du, node, objVn, AstSSAPropagationCallGraphBuilder.this);
for(int i = 0; i < objKeys.length; i++) {
PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[i]);
system.newConstraint(objCatalog, fieldNameKeys[0]);
}
} else {
system.newSideEffect(
new UnaryOperator() {
public byte evaluate(IVariable lhs, IVariable rhs) {
final IntSetVariable objects = (IntSetVariable) rhs;
if (objects.getValue() != null) {
objects.getValue().foreach(
new IntSetAction() {
public void act(int optr) {
InstanceKey object = system.getInstanceKey(optr);
PointerKey cat = getPointerKeyForObjectCatalog(object);
system.newConstraint(cat, fieldNameKeys[0]);
}
}
);
}
return NOT_CHANGED;
}
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return o==this;
}
public String toString() {
return "field name record: " + objKey;
}
},
objKey);
}
}
public void visitAssert(AstAssertInstruction instruction) {
}
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
}
public void visitEachElementGet(EachElementGetInstruction inst) {
int lval = inst.getDef(0);
final PointerKey lk = getPointerKeyForLocal(node, lval);
int rval = inst.getUse(0);
final PointerKey rk = getPointerKeyForLocal(node, rval);
if (contentsAreInvariant(symbolTable, du, rval)) {
InstanceKey objects[] = getInvariantContents(symbolTable, du, node, rval, AstSSAPropagationCallGraphBuilder.this);
for(int i = 0; i < objects.length; i++) {
PointerKey catalog = getPointerKeyForObjectCatalog(objects[i]);
system.newConstraint(lk, assignOperator, catalog);
}
}
else {
system.newSideEffect(
new UnaryOperator() {
public byte evaluate(IVariable lhs, IVariable rhs) {
final IntSetVariable objects = (IntSetVariable) rhs;
if (objects.getValue() != null) {
objects.getValue().foreach(
new IntSetAction() {
public void act(int optr) {
InstanceKey object = system.getInstanceKey(optr);
PointerKey objCatalog =
getPointerKeyForObjectCatalog(object);
system.newConstraint(lk, assignOperator, objCatalog);
}
}
);
}
return NOT_CHANGED;
}
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return o==this;
}
public String toString() {
return "get catalog op" + rk;
}
},
rk);
}
}
}
protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node,
IR ir,
DefUse du,
ExplicitCallGraph callGraph)
{
return new AstConstraintVisitor(node, ir, callGraph, du);
}
}