1256 lines
47 KiB
Java
1256 lines
47 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.AbstractLexicalInvoke;
|
|
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.AstIR;
|
|
import com.ibm.wala.cast.ir.ssa.AstInstructionVisitor;
|
|
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
|
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.ssa.SSAConversion;
|
|
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.IClass;
|
|
import com.ibm.wala.classLoader.IMethod;
|
|
import com.ibm.wala.fixpoint.AbstractOperator;
|
|
import com.ibm.wala.fixpoint.IntSetVariable;
|
|
import com.ibm.wala.fixpoint.UnaryOperator;
|
|
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.CallGraph;
|
|
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
|
|
import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey;
|
|
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.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.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.ssa.DefUse;
|
|
import com.ibm.wala.ssa.IR;
|
|
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
|
import com.ibm.wala.ssa.SSAPutInstruction;
|
|
import com.ibm.wala.ssa.SymbolTable;
|
|
import com.ibm.wala.util.collections.EmptyIterator;
|
|
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.functions.Function;
|
|
import com.ibm.wala.util.graph.traverse.NumberedDFSDiscoverTimeIterator;
|
|
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;
|
|
|
|
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();
|
|
|
|
protected boolean isUncataloguedField(IClass type, String fieldName) {
|
|
return false;
|
|
}
|
|
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// overall control
|
|
//
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
protected AstSSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache 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(new LexicalScopingSSAContextInterpreter(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
|
|
//
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
public void visitAstLexicalRead(AstLexicalRead instruction) {
|
|
|
|
}
|
|
|
|
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
|
|
|
|
}
|
|
|
|
public void visitAstGlobalRead(AstGlobalRead instruction) {
|
|
pointsToSet = analysis.computeImplicitPointsToSetAtGet(node, instruction.getDeclaredField(), -1, true);
|
|
}
|
|
|
|
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
|
|
|
|
}
|
|
|
|
public void visitAssert(AstAssertInstruction instruction) {
|
|
|
|
}
|
|
|
|
public void visitEachElementGet(EachElementGetInstruction inst) {
|
|
|
|
}
|
|
|
|
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
|
|
|
|
}
|
|
|
|
public void visitIsDefined(AstIsDefinedInstruction inst) {
|
|
|
|
}
|
|
|
|
public void visitEcho(AstEchoInstruction inst) {
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// top-level node constraint generation
|
|
//
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
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);
|
|
}
|
|
|
|
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 visitAssert(AstAssertInstruction instruction) {
|
|
bingo = true;
|
|
}
|
|
|
|
public void visitEachElementGet(EachElementGetInstruction inst) {
|
|
bingo = true;
|
|
}
|
|
|
|
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
|
|
|
|
}
|
|
|
|
public void visitIsDefined(AstIsDefinedInstruction inst) {
|
|
|
|
}
|
|
|
|
public void visitEcho(AstEchoInstruction inst) {
|
|
|
|
}
|
|
}
|
|
|
|
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
|
|
return new AstInterestingVisitor(vn);
|
|
}
|
|
|
|
public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) {
|
|
if (node.getMethod() instanceof AstMethod) {
|
|
IntSet uses = ((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
|
|
//
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node) {
|
|
return new AstConstraintVisitor(this, node);
|
|
}
|
|
|
|
protected static class AstConstraintVisitor extends ConstraintVisitor implements AstInstructionVisitor {
|
|
|
|
private final CallGraph cg;
|
|
|
|
public AstConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
|
|
super(builder, node);
|
|
this.cg = builder.callGraph;
|
|
}
|
|
|
|
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 void visitLexical(final LexicalOperator op) {
|
|
final PointerKey function = getPointerKeyForLocal(1);
|
|
if (contentsAreInvariant(symbolTable, du, 1)) {
|
|
op.doLexicalPointerKeys();
|
|
} else {
|
|
system.newSideEffect(op, function);
|
|
}
|
|
|
|
class LexicalScopingCallback implements Function<Object, Object> {
|
|
public Object apply(Object ignore) {
|
|
op.doLexicalPointerKeys();
|
|
return null;
|
|
}
|
|
|
|
private LexicalOperator getOperator() {
|
|
return op;
|
|
}
|
|
|
|
public int hashCode() {
|
|
return op.hashCode();
|
|
}
|
|
|
|
public boolean equals(Object o) {
|
|
return (o instanceof LexicalScopingCallback) && ((LexicalScopingCallback) o).getOperator().equals(op);
|
|
}
|
|
}
|
|
|
|
((AstCGNode) node).addCallback(new LexicalScopingCallback());
|
|
}
|
|
|
|
public void visitAstLexicalRead(AstLexicalRead instruction) {
|
|
visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) {
|
|
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();
|
|
IR lir = getBuilder().getCFAContextInterpreter().getIR(lnode);
|
|
SymbolTable lsymtab = lir.getSymbolTable();
|
|
DefUse ldu = getAnalysisCache().getSSACache().findOrCreateDU(lir, lnode.getContext());
|
|
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);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void visitAstLexicalWrite(AstLexicalWrite instruction) {
|
|
visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), false) {
|
|
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);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
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() || !getBuilder().useObjectCatalog())
|
|
return;
|
|
|
|
SymbolTable symtab = ir.getSymbolTable();
|
|
|
|
int objVn = inst.getRef();
|
|
String fieldName = null;
|
|
try {
|
|
fieldName = inst.getDeclaredField().getName().toUnicodeString();
|
|
} catch (UTFDataFormatException e) {
|
|
Assertions.UNREACHABLE();
|
|
}
|
|
int fieldNameVn = symtab.getConstant(fieldName);
|
|
|
|
final PointerKey objKey = getPointerKeyForLocal(objVn);
|
|
|
|
final InstanceKey[] fieldNameKeys = getInvariantContents(fieldNameVn);
|
|
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>() {
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable 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);
|
|
if (! getBuilder().isUncataloguedField(object.getConcreteType(), hack)) {
|
|
PointerKey cat = getPointerKeyForObjectCatalog(object);
|
|
if (cat != null) {
|
|
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(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>() {
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable 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);
|
|
if (objCatalog != null) {
|
|
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);
|
|
}
|
|
}
|
|
|
|
public void visitIsDefined(AstIsDefinedInstruction inst) {
|
|
|
|
}
|
|
|
|
public void visitEcho(AstEchoInstruction inst) {
|
|
|
|
}
|
|
|
|
protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction) {
|
|
super.visitInvokeInternal(instruction);
|
|
if (instruction instanceof AbstractLexicalInvoke) {
|
|
AbstractLexicalInvoke I = (AbstractLexicalInvoke) instruction;
|
|
for(int wi = 0; wi < I.getNumberOfDefs(); wi++) {
|
|
if (I.isLexicalDef(wi)) {
|
|
Access w = I.getLexicalDef(wi);
|
|
for(int ri = 0; ri < I.getNumberOfUses(); ri++) {
|
|
if (I.isLexicalUse(ri)) {
|
|
Access r = I.getLexicalUse(ri);
|
|
if (w.variableName.equals(r.variableName)) {
|
|
if (w.variableDefiner==null? r.variableDefiner==null: w.variableDefiner.equals(r.variableDefiner)) {
|
|
PointerKey rk = getBuilder().getPointerKeyForLocal(node, r.valueNumber);
|
|
PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber);
|
|
system.newConstraint(wk, assignOperator, rk);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// lexical scoping handling
|
|
//
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
private abstract class LexicalOperator extends UnaryOperator<PointsToSetVariable> {
|
|
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)
|
|
System.err.println(("looking up lexical parent " + definer));
|
|
|
|
for (Iterator<CGNode> DS = getLexicalDefiners(node, definer).iterator(); DS.hasNext();) {
|
|
final CGNode D = DS.next();
|
|
|
|
Iterator PS = new NumberedDFSDiscoverTimeIterator<CGNode>(getBuilder().getCallGraph(), node) {
|
|
/**
|
|
*
|
|
*/
|
|
private static final long serialVersionUID = 4546217460630659884L;
|
|
|
|
protected void visitEdge(CGNode callee, CGNode caller) {
|
|
CGNode from = (CGNode) caller;
|
|
CGNode to = (CGNode) callee;
|
|
|
|
for (Iterator SS = cg.getPossibleSites(from, 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<? extends CGNode> getConnected(CGNode n) {
|
|
if (n.equals(D))
|
|
return EmptyIterator.instance();
|
|
else
|
|
return G.getPredNodes(n);
|
|
}
|
|
};
|
|
|
|
while (PS.hasNext()) {
|
|
PS.next();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
|
doLexicalPointerKeys();
|
|
return NOT_CHANGED;
|
|
}
|
|
|
|
abstract protected void action(PointerKey lexicalKey, int vn);
|
|
|
|
public String toString() {
|
|
return "lexical op";
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
public int hashCode() {
|
|
return node.hashCode() * accesses[0].hashCode() * accesses.length;
|
|
}
|
|
}
|
|
|
|
private Set<CGNode> getLexicalDefiners(final CGNode opNode, final String definer) {
|
|
if (definer == null) {
|
|
return Collections.singleton(getBuilder().getCallGraph().getFakeRootNode());
|
|
|
|
} else {
|
|
final Set<CGNode> result = HashSetFactory.make();
|
|
PointerKey F = getBuilder().getPointerKeyForLocal(opNode, 1);
|
|
|
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode);
|
|
SymbolTable symtab = ir.getSymbolTable();
|
|
DefUse du = getAnalysisCache().getSSACache().findOrCreateDU(ir, opNode.getContext());
|
|
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];
|
|
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<PointerKey> discoveredUpwardFunargs = HashSetFactory.make();
|
|
|
|
private void addUpwardFunargConstraints(PointerKey lhs, String name, String definer, CGNode definingNode) {
|
|
discoveredUpwardFunargs.add(lhs);
|
|
|
|
LexicalInformation LI = ((AstIR) definingNode.getIR()).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 = getBuilder().getCFAContextInterpreter().getIR(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();
|
|
}
|
|
|
|
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 == null?
|
|
definingNode == ((UpwardFunargPointerKey) x).getDefiningNode():
|
|
definingNode.equals(((UpwardFunargPointerKey) x).getDefiningNode()));
|
|
}
|
|
|
|
public int hashCode() {
|
|
return super.hashCode() * ((definingNode == null)? 17: definingNode.hashCode());
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer, CGNode definingNode) {
|
|
IMethod M = n.getMethod();
|
|
if (n == getBuilder().getCallGraph().getFakeRootNode()) {
|
|
return handleRootLexicalReference(name, definer, definingNode);
|
|
}
|
|
|
|
else if (M instanceof AstMethod) {
|
|
AstIR ir = (AstIR) n.getIR();
|
|
int pc = callSite.getProgramCounter();
|
|
LexicalInformation L = ((AstIR) n.getIR()).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.getLastLexicalUse(); i++) {
|
|
Access A = I.getLexicalUse(i);
|
|
if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) {
|
|
return getBuilder().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)
|
|
System.err.println(("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses() - 1) + " at inst " + pc));
|
|
|
|
SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses() - 1);
|
|
|
|
((AstCallGraph.AstCGNode)n).setLexicallyMutatedIR(ir);
|
|
|
|
return getBuilder().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 == getBuilder().getCallGraph().getFakeRootNode()) {
|
|
return handleRootLexicalReference(name, definer, definingNode);
|
|
}
|
|
|
|
else if (M instanceof AstMethod) {
|
|
AstMethod AstM = (AstMethod) M;
|
|
AstIR ir = (AstIR) n.getIR();
|
|
LexicalInformation L = ir.lexicalInfo();
|
|
|
|
// some people have no lexical uses at all
|
|
if (L == null)
|
|
return null;
|
|
|
|
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 getBuilder().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;
|
|
|
|
// find calls that may be altered, and clear their caches
|
|
DefUse newDU = getAnalysisCache().getSSACache().findOrCreateDU(ir, n.getContext());
|
|
Iterator<SSAInstruction> insts = newDU.getUses(values[i]);
|
|
while(insts.hasNext()) {
|
|
SSAInstruction inst = insts.next();
|
|
if (inst instanceof SSAAbstractInvokeInstruction) {
|
|
System.err.println("clearing for " + inst);
|
|
CallSiteReference cs = ((SSAAbstractInvokeInstruction)inst).getCallSite();
|
|
((AstCallGraph.AstCGNode)n).clearMutatedCache(cs);
|
|
}
|
|
}
|
|
|
|
// 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];
|
|
|
|
// we assume that the callee might not necessarily write,
|
|
// so the call becomes like a phi node. hence it needs a
|
|
// read of the old value
|
|
ensureRead: {
|
|
for(int l = 0; l < I.getNumberOfUses(); l++) {
|
|
if (I.isLexicalUse(l)) {
|
|
Access r = I.getLexicalUse(l);
|
|
if (name.equals(r.variableName)) {
|
|
if (definer==null? r.variableDefiner == null: definer.equals(r.variableDefiner)) {
|
|
break ensureRead;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
I.addLexicalUse(new Access(name, definer, values[i]));
|
|
}
|
|
|
|
// add new lexical definition
|
|
I.addLexicalDef(new Access(name, definer, values[i]));
|
|
|
|
if (SSAConversion.DEBUG_UNDO)
|
|
System.err.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());
|
|
|
|
// force analysis to be redone
|
|
// TODO: only values[i] uses need to be re-done.
|
|
ir.lexicalInfo().handleAlteration();
|
|
((AstCallGraph.AstCGNode)n).setLexicallyMutatedIR(ir);
|
|
getAnalysisCache().getSSACache().invalidateDU(M, n.getContext());
|
|
getBuilder().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(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) {
|
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(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);
|
|
|
|
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();) {
|
|
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 keys = getPointerKeysForReflectedFieldWrite(objKeys[o], fieldsKeys[f]); keys.hasNext();) {
|
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) 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]);
|
|
if (objCatalog != null) {
|
|
system.newConstraint(objCatalog, assignOperator, fieldKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable 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();) {
|
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) 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);
|
|
|
|
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable 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();) {
|
|
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 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;
|
|
}
|
|
|
|
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<PointsToSetVariable>() {
|
|
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] 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);
|
|
if (cat != null) {
|
|
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();) {
|
|
AbstractFieldPointerKey key = (AbstractFieldPointerKey) 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) {
|
|
System.err.println("finished\n");
|
|
}
|
|
}
|
|
|
|
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
|
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(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);
|
|
}
|
|
}
|
|
|
|
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
|
|
try {
|
|
|
|
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
|
|
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]));
|
|
}
|
|
}
|
|
|
|
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]);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
} catch (RuntimeException e) {
|
|
System.err.println("error: " + e);
|
|
System.err.println(getBuilder().getCFAContextInterpreter().getIR(opNode));
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
|
|
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
|
|
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
|
System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp));
|
|
}
|
|
|
|
public void action(AbstractFieldPointerKey fieldKey) {
|
|
if (!representsNullType(fieldKey.getInstanceKey())) {
|
|
system.newConstraint(fieldKey, assignOperator, rhs);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
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() {
|
|
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
|
System.err.println(("read " + lhs + " from " + fieldKey + " " + constObj + ", " + constProp));
|
|
}
|
|
|
|
public void action(AbstractFieldPointerKey fieldKey) {
|
|
if (!representsNullType(fieldKey.getInstanceKey())) {
|
|
system.newConstraint(lhs, assignOperator, fieldKey);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|