1254 lines
45 KiB
Java
1254 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.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;
|
|
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.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.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.IR;
|
|
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;
|
|
|
|
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
|
|
//
|
|
// /////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
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(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 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 = ((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 {
|
|
|
|
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 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();
|
|
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);
|
|
}
|
|
});
|
|
}
|
|
|
|
@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);
|
|
|
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(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 boolean isEqual(Object a, Object b) {
|
|
if (a == null)
|
|
return b == null;
|
|
else
|
|
return a.equals(b);
|
|
}
|
|
|
|
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 = ((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();
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
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);
|
|
|
|
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) {
|
|
IR ir = getBuilder().getCFAContextInterpreter().getIR(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 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 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;
|
|
}
|
|
|
|
@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 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 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* 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);
|
|
|
|
|
|
}
|