2007-02-02 17:20:09 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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;
|
2015-04-06 01:19:56 +00:00
|
|
|
import com.ibm.wala.cast.ipa.callgraph.GlobalObjectKey;
|
2007-02-02 17:20:09 +00:00
|
|
|
import com.ibm.wala.cast.java.analysis.typeInference.AstJavaTypeInference;
|
2007-02-07 18:51:19 +00:00
|
|
|
import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl.JavaClass;
|
2007-02-08 19:07:47 +00:00
|
|
|
import com.ibm.wala.cast.java.ssa.AstJavaInstructionVisitor;
|
|
|
|
import com.ibm.wala.cast.java.ssa.AstJavaInvokeInstruction;
|
2008-02-18 15:17:16 +00:00
|
|
|
import com.ibm.wala.cast.java.ssa.AstJavaNewEnclosingInstruction;
|
2007-02-08 19:07:47 +00:00
|
|
|
import com.ibm.wala.cast.java.ssa.EnclosingObjectReference;
|
|
|
|
import com.ibm.wala.classLoader.IClass;
|
2007-02-09 18:19:13 +00:00
|
|
|
import com.ibm.wala.fixpoint.IntSetVariable;
|
2011-01-17 21:43:18 +00:00
|
|
|
import com.ibm.wala.fixpoint.UnaryOperator;
|
2007-02-08 19:07:47 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
|
|
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
2017-02-03 01:33:27 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
|
2007-06-15 14:01:32 +00:00
|
|
|
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;
|
2007-08-31 23:51:15 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointsToSetVariable;
|
2007-06-01 03:37:03 +00:00
|
|
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
2007-02-08 19:07:47 +00:00
|
|
|
import com.ibm.wala.ssa.IR;
|
|
|
|
import com.ibm.wala.ssa.SSANewInstruction;
|
|
|
|
import com.ibm.wala.ssa.SymbolTable;
|
2013-04-30 03:34:40 +00:00
|
|
|
import com.ibm.wala.types.MethodReference;
|
2007-02-07 18:51:19 +00:00
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
2015-04-06 01:19:56 +00:00
|
|
|
import com.ibm.wala.util.strings.Atom;
|
2007-02-02 17:20:09 +00:00
|
|
|
|
|
|
|
public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraphBuilder {
|
|
|
|
|
2017-02-03 01:33:27 +00:00
|
|
|
protected AstJavaSSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, IAnalysisCacheView cache,
|
2007-04-12 14:54:43 +00:00
|
|
|
PointerKeyFactory pointerKeyFactory) {
|
2007-07-20 15:20:06 +00:00
|
|
|
super(cha, options, cache, pointerKeyFactory);
|
2007-02-02 17:20:09 +00:00
|
|
|
}
|
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:20:09 +00:00
|
|
|
//
|
|
|
|
// language specialization interface
|
|
|
|
//
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:20:09 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:20:09 +00:00
|
|
|
protected boolean useObjectCatalog() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-15 07:01:38 +00:00
|
|
|
@Override
|
|
|
|
protected AbstractFieldPointerKey fieldKeyForUnknownWrites(AbstractFieldPointerKey fieldKey) {
|
|
|
|
assert false;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-07 18:51:19 +00:00
|
|
|
//
|
|
|
|
// enclosing object pointer flow support
|
|
|
|
//
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-07 18:51:19 +00:00
|
|
|
|
2007-06-01 03:37:03 +00:00
|
|
|
public static class EnclosingObjectReferenceKey extends AbstractFieldPointerKey {
|
2007-02-07 18:51:19 +00:00
|
|
|
private final IClass outer;
|
|
|
|
|
2007-08-07 13:47:16 +00:00
|
|
|
public EnclosingObjectReferenceKey(InstanceKey inner, IClass outer) {
|
2007-02-07 18:51:19 +00:00
|
|
|
super(inner);
|
|
|
|
this.outer = outer;
|
|
|
|
}
|
2007-04-12 14:54:43 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-07 18:51:19 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return getInstanceKey().hashCode() * outer.hashCode();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-07 18:51:19 +00:00
|
|
|
public boolean equals(Object o) {
|
2007-04-12 14:54:43 +00:00
|
|
|
return (o instanceof EnclosingObjectReferenceKey) && ((EnclosingObjectReferenceKey) o).outer.equals(outer)
|
|
|
|
&& ((EnclosingObjectReferenceKey) o).getInstanceKey().equals(getInstanceKey());
|
2007-02-07 18:51:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:20:09 +00:00
|
|
|
//
|
|
|
|
// top-level node constraint generation
|
|
|
|
//
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:20:09 +00:00
|
|
|
|
2017-07-28 20:33:41 +00:00
|
|
|
protected TypeInference makeTypeInference(IR ir) {
|
|
|
|
TypeInference ti = new AstJavaTypeInference(ir, false);
|
2007-02-02 17:20:09 +00:00
|
|
|
|
|
|
|
if (DEBUG_TYPE_INFERENCE) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("IR of " + ir.getMethod()));
|
|
|
|
System.err.println(ir);
|
|
|
|
System.err.println(("TypeInference of " + ir.getMethod()));
|
2007-08-22 15:33:46 +00:00
|
|
|
for (int i = 0; i <= ir.getSymbolTable().getMaxValueNumber(); i++) {
|
2007-04-12 14:54:43 +00:00
|
|
|
if (ti.isUndefined(i)) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((" value " + i + " is undefined"));
|
2007-04-12 14:54:43 +00:00
|
|
|
} else {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((" value " + i + " has type " + ti.getType(i)));
|
2007-04-12 14:54:43 +00:00
|
|
|
}
|
2007-02-02 17:20:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ti;
|
|
|
|
}
|
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
protected class AstJavaInterestingVisitor extends AstInterestingVisitor implements AstJavaInstructionVisitor {
|
2007-02-02 17:20:09 +00:00
|
|
|
protected AstJavaInterestingVisitor(int vn) {
|
|
|
|
super(vn);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-07 18:51:19 +00:00
|
|
|
public void visitEnclosingObjectReference(EnclosingObjectReference inst) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:20:09 +00:00
|
|
|
public void visitJavaInvoke(AstJavaInvokeInstruction instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:37:03 +00:00
|
|
|
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
|
2007-02-02 17:20:09 +00:00
|
|
|
return new AstJavaInterestingVisitor(vn);
|
|
|
|
}
|
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:20:09 +00:00
|
|
|
//
|
|
|
|
// specialized pointer analysis
|
|
|
|
//
|
2007-04-12 14:54:43 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:20:09 +00:00
|
|
|
|
2007-06-01 03:37:03 +00:00
|
|
|
protected static class AstJavaConstraintVisitor extends AstConstraintVisitor implements AstJavaInstructionVisitor {
|
2007-02-02 17:20:09 +00:00
|
|
|
|
2007-06-01 03:37:03 +00:00
|
|
|
public AstJavaConstraintVisitor(
|
|
|
|
AstSSAPropagationCallGraphBuilder builder,
|
2011-04-27 13:58:56 +00:00
|
|
|
CGNode node)
|
2007-06-01 03:37:03 +00:00
|
|
|
{
|
|
|
|
super(builder, node);
|
2007-02-02 17:20:09 +00:00
|
|
|
}
|
2007-02-07 18:51:19 +00:00
|
|
|
|
2008-02-18 15:17:16 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
* @param lvalKey
|
|
|
|
* @param cls
|
|
|
|
* @param objKey
|
|
|
|
*/
|
2007-04-12 14:54:43 +00:00
|
|
|
private void handleEnclosingObject(final PointerKey lvalKey, final IClass cls, final PointerKey objKey) {
|
2007-02-07 18:51:19 +00:00
|
|
|
SymbolTable symtab = ir.getSymbolTable();
|
2007-02-09 18:19:13 +00:00
|
|
|
int objVal;
|
|
|
|
if (objKey instanceof LocalPointerKey) {
|
2007-04-12 14:54:43 +00:00
|
|
|
objVal = ((LocalPointerKey) objKey).getValueNumber();
|
2007-02-09 18:19:13 +00:00
|
|
|
} else {
|
2007-04-12 14:54:43 +00:00
|
|
|
objVal = 0;
|
2007-02-09 18:19:13 +00:00
|
|
|
}
|
2007-02-07 18:51:19 +00:00
|
|
|
|
2007-02-09 18:19:13 +00:00
|
|
|
if (objVal > 0 && contentsAreInvariant(symtab, du, objVal)) {
|
2007-02-07 18:51:19 +00:00
|
|
|
system.recordImplicitPointsToSet(objKey);
|
2007-04-12 14:54:43 +00:00
|
|
|
|
2007-06-01 03:37:03 +00:00
|
|
|
InstanceKey[] objs = getInvariantContents(objVal);
|
2007-04-12 14:54:43 +00:00
|
|
|
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey obj : objs) {
|
|
|
|
PointerKey enclosing = new EnclosingObjectReferenceKey(obj, cls);
|
2007-04-12 14:54:43 +00:00
|
|
|
system.newConstraint(lvalKey, assignOperator, enclosing);
|
|
|
|
}
|
|
|
|
|
2007-02-07 18:51:19 +00:00
|
|
|
} else {
|
2007-08-31 23:51:15 +00:00
|
|
|
system.newSideEffect(new UnaryOperator<PointsToSetVariable>() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-08-31 23:51:15 +00:00
|
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
IntSetVariable<?> tv = rhs;
|
2007-04-12 14:54:43 +00:00
|
|
|
if (tv.getValue() != null) {
|
2017-11-23 01:28:36 +00:00
|
|
|
tv.getValue().foreach(ptr -> {
|
|
|
|
InstanceKey iKey = system.getInstanceKey(ptr);
|
|
|
|
PointerKey enclosing = new EnclosingObjectReferenceKey(iKey, cls);
|
|
|
|
system.newConstraint(lvalKey, assignOperator, enclosing);
|
2007-04-12 14:54:43 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
return NOT_CHANGED;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-12 14:54:43 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return System.identityHashCode(this);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-12 14:54:43 +00:00
|
|
|
public boolean equals(Object o) {
|
|
|
|
return o == this;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-12 14:54:43 +00:00
|
|
|
public String toString() {
|
|
|
|
return "enclosing objects of " + objKey;
|
|
|
|
}
|
|
|
|
}, objKey);
|
2007-02-07 18:51:19 +00:00
|
|
|
}
|
2007-02-09 18:19:13 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-09 18:19:13 +00:00
|
|
|
public void visitEnclosingObjectReference(EnclosingObjectReference inst) {
|
2007-06-01 03:37:03 +00:00
|
|
|
PointerKey lvalKey = getPointerKeyForLocal(inst.getDef());
|
|
|
|
PointerKey objKey = getPointerKeyForLocal(1);
|
|
|
|
IClass cls = getClassHierarchy().lookupClass(inst.getEnclosingType());
|
2007-02-09 18:19:13 +00:00
|
|
|
handleEnclosingObject(lvalKey, cls, objKey);
|
|
|
|
}
|
2007-02-07 18:51:19 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-07 18:51:19 +00:00
|
|
|
public void visitNew(SSANewInstruction instruction) {
|
|
|
|
super.visitNew(instruction);
|
2007-06-01 03:37:03 +00:00
|
|
|
InstanceKey iKey = getInstanceKeyForAllocation(instruction.getNewSite());
|
2007-02-07 18:51:19 +00:00
|
|
|
|
|
|
|
if (iKey != null) {
|
2007-04-12 14:54:43 +00:00
|
|
|
IClass klass = iKey.getConcreteType();
|
2007-02-07 18:51:19 +00:00
|
|
|
|
2008-02-18 15:17:16 +00:00
|
|
|
// 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;
|
|
|
|
|
2007-02-07 18:51:19 +00:00
|
|
|
if (klass instanceof JavaClass) {
|
2008-02-18 15:17:16 +00:00
|
|
|
IClass enclosingClass = ((JavaClass) klass).getEnclosingClass(); // the immediate enclosing class.
|
2007-04-12 14:54:43 +00:00
|
|
|
if (enclosingClass != null) {
|
|
|
|
IClass currentCls = node.getMethod().getDeclaringClass();
|
2008-02-18 15:17:16 +00:00
|
|
|
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);
|
2007-04-12 14:54:43 +00:00
|
|
|
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("class is " + klass + ", enclosing is " + enclosingClass + ", method is " + node.getMethod()));
|
2007-04-12 14:54:43 +00:00
|
|
|
|
|
|
|
if (node.getMethod().isSynthetic()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-18 15:17:16 +00:00
|
|
|
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)
|
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
currentCls = ((JavaClass) currentCls).getEnclosingClass();
|
|
|
|
}
|
2008-02-18 15:17:16 +00:00
|
|
|
|
2007-04-12 14:54:43 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-07 18:51:19 +00:00
|
|
|
}
|
|
|
|
}
|
2007-04-12 14:54:43 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:20:09 +00:00
|
|
|
public void visitJavaInvoke(AstJavaInvokeInstruction instruction) {
|
2012-03-01 02:45:51 +00:00
|
|
|
visitInvokeInternal(instruction, new DefaultInvariantComputer());
|
2007-02-02 17:20:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2015-04-06 01:19:56 +00:00
|
|
|
public ConstraintVisitor makeVisitor(CGNode node) {
|
2007-06-01 03:37:03 +00:00
|
|
|
return new AstJavaConstraintVisitor(this, node);
|
2007-02-02 17:20:09 +00:00
|
|
|
}
|
2013-04-30 03:34:40 +00:00
|
|
|
|
|
|
|
@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);
|
|
|
|
}
|
2015-04-06 01:19:56 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public GlobalObjectKey getGlobalObject(Atom language) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
return null;
|
|
|
|
}
|
2007-02-02 17:20:09 +00:00
|
|
|
}
|