com.ibm.wala.cast.java.ipa.callgraph.AstJavaSSAPropagationCallGraphBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.ibm.wala.cast.java Show documentation
Show all versions of com.ibm.wala.cast.java Show documentation
T. J. Watson Libraries for Analysis
The newest version!
/*
* 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.java.ipa.callgraph;
import com.ibm.wala.analysis.typeInference.TypeInference;
import com.ibm.wala.cast.ipa.callgraph.AstSSAPropagationCallGraphBuilder;
import com.ibm.wala.cast.ipa.callgraph.GlobalObjectKey;
import com.ibm.wala.cast.java.analysis.typeInference.AstJavaTypeInference;
import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl.JavaClass;
import com.ibm.wala.cast.java.ssa.AstJavaInstructionVisitor;
import com.ibm.wala.cast.java.ssa.AstJavaInvokeInstruction;
import com.ibm.wala.cast.java.ssa.AstJavaNewEnclosingInstruction;
import com.ibm.wala.cast.java.ssa.EnclosingObjectReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.core.util.strings.Atom;
import com.ibm.wala.fixpoint.IntSetVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.PointsToSetVariable;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.util.debug.Assertions;
public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraphBuilder {
protected AstJavaSSAPropagationCallGraphBuilder(
IMethod fakeRootClass,
AnalysisOptions options,
IAnalysisCacheView cache,
PointerKeyFactory pointerKeyFactory) {
super(fakeRootClass, options, cache, pointerKeyFactory);
}
// ///////////////////////////////////////////////////////////////////////////
//
// language specialization interface
//
// ///////////////////////////////////////////////////////////////////////////
@Override
protected boolean useObjectCatalog() {
return false;
}
@Override
protected AbstractFieldPointerKey fieldKeyForUnknownWrites(AbstractFieldPointerKey fieldKey) {
assert false;
return null;
}
// ///////////////////////////////////////////////////////////////////////////
//
// enclosing object pointer flow support
//
// ///////////////////////////////////////////////////////////////////////////
public static class EnclosingObjectReferenceKey extends AbstractFieldPointerKey {
private final IClass outer;
public EnclosingObjectReferenceKey(InstanceKey inner, IClass outer) {
super(inner);
this.outer = outer;
}
@Override
public int hashCode() {
return getInstanceKey().hashCode() * outer.hashCode();
}
@Override
public boolean equals(Object o) {
return (o instanceof EnclosingObjectReferenceKey)
&& ((EnclosingObjectReferenceKey) o).outer.equals(outer)
&& ((EnclosingObjectReferenceKey) o).getInstanceKey().equals(getInstanceKey());
}
}
// ///////////////////////////////////////////////////////////////////////////
//
// top-level node constraint generation
//
// ///////////////////////////////////////////////////////////////////////////
protected TypeInference makeTypeInference(IR ir) {
TypeInference ti = new AstJavaTypeInference(ir, false);
if (DEBUG_TYPE_INFERENCE) {
System.err.println(("IR of " + ir.getMethod()));
System.err.println(ir);
System.err.println(("TypeInference of " + ir.getMethod()));
for (int i = 0; i <= ir.getSymbolTable().getMaxValueNumber(); i++) {
if (ti.isUndefined(i)) {
System.err.println((" value " + i + " is undefined"));
} else {
System.err.println((" value " + i + " has type " + ti.getType(i)));
}
}
}
return ti;
}
protected static class AstJavaInterestingVisitor extends AstInterestingVisitor
implements AstJavaInstructionVisitor {
protected AstJavaInterestingVisitor(int vn) {
super(vn);
}
@Override
public void visitEnclosingObjectReference(EnclosingObjectReference inst) {
Assertions.UNREACHABLE();
}
@Override
public void visitJavaInvoke(AstJavaInvokeInstruction instruction) {
bingo = true;
}
}
@Override
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
return new AstJavaInterestingVisitor(vn);
}
// ///////////////////////////////////////////////////////////////////////////
//
// specialized pointer analysis
//
// ///////////////////////////////////////////////////////////////////////////
protected static class AstJavaConstraintVisitor extends AstConstraintVisitor
implements AstJavaInstructionVisitor {
public AstJavaConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
super(builder, node);
}
/**
* For each of objKey's instance keys ik, adds the constraint lvalKey = EORK(ik,cls), where
* EORK(ik,cls) will be made equivalent to the actual enclosing class by the handleNew()
* function below.
*/
private void handleEnclosingObject(
final PointerKey lvalKey, final IClass cls, final PointerKey objKey) {
SymbolTable symtab = ir.getSymbolTable();
int objVal;
if (objKey instanceof LocalPointerKey) {
objVal = ((LocalPointerKey) objKey).getValueNumber();
} else {
objVal = 0;
}
if (objVal > 0 && contentsAreInvariant(symtab, du, objVal)) {
system.recordImplicitPointsToSet(objKey);
InstanceKey[] objs = getInvariantContents(objVal);
for (InstanceKey obj : objs) {
PointerKey enclosing = new EnclosingObjectReferenceKey(obj, cls);
system.newConstraint(lvalKey, assignOperator, enclosing);
}
} else {
system.newSideEffect(
new UnaryOperator<>() {
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
IntSetVariable> tv = rhs;
if (tv.getValue() != null) {
tv.getValue()
.foreach(
ptr -> {
InstanceKey iKey = system.getInstanceKey(ptr);
PointerKey enclosing = new EnclosingObjectReferenceKey(iKey, cls);
system.newConstraint(lvalKey, assignOperator, enclosing);
});
}
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 "enclosing objects of " + objKey;
}
},
objKey);
}
}
@Override
public void visitEnclosingObjectReference(EnclosingObjectReference inst) {
PointerKey lvalKey = getPointerKeyForLocal(inst.getDef());
PointerKey objKey = getPointerKeyForLocal(1);
IClass cls = getClassHierarchy().lookupClass(inst.getEnclosingType());
handleEnclosingObject(lvalKey, cls, objKey);
}
@Override
public void visitNew(SSANewInstruction instruction) {
super.visitNew(instruction);
InstanceKey iKey = getInstanceKeyForAllocation(instruction.getNewSite());
if (iKey != null) {
IClass klass = iKey.getConcreteType();
// in the case of a AstJavaNewEnclosingInstruction (a new instruction like outer.new Bla()),
// we may need to record the instance keys if the pointer key outer is invariant (and thus
// implicit)
InstanceKey enclosingInvariantKeys[] = null;
if (klass instanceof JavaClass) {
IClass enclosingClass =
((JavaClass) klass).getEnclosingClass(); // the immediate enclosing class.
if (enclosingClass != null) {
PointerKey objKey;
if (instruction instanceof AstJavaNewEnclosingInstruction) {
int enclosingVal = ((AstJavaNewEnclosingInstruction) instruction).getEnclosing();
SymbolTable symtab = ir.getSymbolTable();
// pk 'outer' is invariant, which means it's implicit, so can't add a constraint with
// the pointer key.
// we should just add constraints directly to the instance keys (below)
if (contentsAreInvariant(symtab, du, enclosingVal))
enclosingInvariantKeys = getInvariantContents(enclosingVal);
// what happens if objKey is implicit but the contents aren't invariant?! (it this
// possible?) big trouble!
objKey = getPointerKeyForLocal(enclosingVal);
} else objKey = getPointerKeyForLocal(1);
System.err.println(
("class is "
+ klass
+ ", enclosing is "
+ enclosingClass
+ ", method is "
+ node.getMethod()));
if (node.getMethod().isWalaSynthetic()) {
return;
}
IClass currentCls = enclosingClass;
PointerKey x = new EnclosingObjectReferenceKey(iKey, currentCls);
if (enclosingInvariantKeys != null)
for (InstanceKey obj : enclosingInvariantKeys) system.newConstraint(x, obj);
else system.newConstraint(x, assignOperator, objKey);
// If the immediate inclosing class is not a top-level class, we must make EORKs for all
// enclosing classes up to the top level.
// for instance, if we have "D d = c.new D()", and c is of type A$B$C, methods in D may
// reference variables and functions from
// A, B, and C. Therefore we must also make the links from EORK(allocsite of d,enc class
// B) and EORK(allocsite of d,en class A).
// We do this by getting the enclosing class of C and making a link from EORK(d,B) ->
// EORK(c,B), etc.
currentCls = ((JavaClass) currentCls).getEnclosingClass();
while (currentCls != null) {
x =
new EnclosingObjectReferenceKey(
iKey, currentCls); // make EORK(d,B), EORK(d,A), etc.
handleEnclosingObject(x, currentCls, objKey);
// objKey is the pointer key representing the immediate inner class.
// handleEnclosingObject finds x's instance keys and for each one "ik" links x to
// EORK(ik,currentCls)
// thus, for currentCls=B, it will find the allocation site of c and make a link from
// EORK(d,B) to EORK(c,B)
currentCls = ((JavaClass) currentCls).getEnclosingClass();
}
}
}
}
}
@Override
public void visitJavaInvoke(AstJavaInvokeInstruction instruction) {
visitInvokeInternal(instruction, new DefaultInvariantComputer());
}
}
@Override
public ConstraintVisitor makeVisitor(CGNode node) {
return new AstJavaConstraintVisitor(this, node);
}
@Override
protected boolean sameMethod(CGNode opNode, String definingMethod) {
MethodReference reference = opNode.getMethod().getReference();
String selector = reference.getSelector().toString();
String containingClass = reference.getDeclaringClass().getName().toString();
return definingMethod.equals(containingClass + '/' + selector);
}
@Override
public GlobalObjectKey getGlobalObject(Atom language) {
Assertions.UNREACHABLE();
return null;
}
}