more reflection support

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@2673 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
sjfink 2008-03-04 19:48:51 +00:00
parent 3085b16ae6
commit 660f3a6707
11 changed files with 222 additions and 97 deletions

View File

@ -30,31 +30,13 @@ class ClassNewInstanceContextSelector implements ContextSelector {
public ClassNewInstanceContextSelector() {
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
if (mayUnderstand(caller, site, callee, receiver)) {
if (callee.getReference().equals(ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF) && isTypeConstant(receiver)) {
IClass c = (IClass) ((ConstantKey) receiver).getValue();
return new JavaTypeContext(new PointType(c));
}
return null;
}
/**
* This object may understand a dispatch to Class.newInstance() when the class is a class constant.
*/
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (targetMethod.getReference().equals(ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF) && isTypeConstant(instance)) {
return true;
}
return false;
}
private boolean isTypeConstant(InstanceKey instance) {
if (instance instanceof ConstantKey) {

View File

@ -46,38 +46,5 @@ class FactoryContextSelector implements ContextSelector {
}
return null;
}
/*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#mayUnderstand(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
*/
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (targetMethod == null) {
throw new IllegalArgumentException("targetMethod is null");
}
if (targetMethod.isSynthetic()) {
SyntheticMethod s = (SyntheticMethod) targetMethod;
if (s.isFactoryMethod()) {
return true;
}
}
return false;
}
/*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getBoundOnNumberOfTargets(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod)
*/
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference site, IMethod callee) {
if (callee == null) {
throw new IllegalArgumentException("callee is null");
}
if (callee.isSynthetic()) {
SyntheticMethod s = (SyntheticMethod) callee;
if (s.isFactoryMethod()) {
return 1;
}
}
return -1;
}
}

View File

@ -35,14 +35,6 @@ class ForNameContextSelector implements ContextSelector {
public ForNameContextSelector() {
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
/**
* If the {@link CallSiteReference} invokes Class.forName(s) and s is a string constant, return a
* {@link JavaTypeContext} representing the type named by s, if we can resolve it in the {@link IClassHierarchy}.

View File

@ -0,0 +1,123 @@
/*******************************************************************************
* Copyright (c) 2008 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.analysis.reflection;
import java.util.ArrayList;
import java.util.Iterator;
import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.cfg.InducedCFG;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.summaries.SyntheticIR;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSALoadClassInstruction;
import com.ibm.wala.ssa.SSAOptions;
import com.ibm.wala.ssa.SSAReturnInstruction;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.debug.Assertions;
/**
* {@link SSAContextInterpreter} specialized to interpret Object.getClass() in a {@link JavaTypeContext}
*
* @author sjfink
*/
public class GetClassContextInterpeter implements SSAContextInterpreter {
public IR getIR(CGNode node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
if (Assertions.verifyAssertions) {
Assertions._assert(understands(node));
}
IR result = makeIR(node.getMethod(), (JavaTypeContext) node.getContext());
return result;
}
public int getNumberOfStatements(CGNode node) {
if (Assertions.verifyAssertions) {
Assertions._assert(understands(node));
}
return getIR(node).getInstructions().length;
}
public boolean understands(CGNode node) {
if (node == null) {
throw new IllegalArgumentException("node is null");
}
if (!(node.getContext() instanceof JavaTypeContext)) {
return false;
}
return node.getMethod().getReference().equals(GetClassContextSelector.GET_CLASS);
}
public Iterator<NewSiteReference> iterateNewSites(CGNode node) {
return EmptyIterator.instance();
}
public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
return EmptyIterator.instance();
}
private SSAInstruction[] makeStatements(JavaTypeContext context) {
ArrayList<SSAInstruction> statements = new ArrayList<SSAInstruction>();
int nextLocal = 2;
int retValue = nextLocal++;
TypeReference tr = context.getType().getTypeReference();
if (tr != null) {
SSALoadClassInstruction l = new SSALoadClassInstruction(retValue, tr);
statements.add(l);
SSAReturnInstruction R = new SSAReturnInstruction(retValue, false);
statements.add(R);
}
SSAInstruction[] result = new SSAInstruction[statements.size()];
Iterator<SSAInstruction> it = statements.iterator();
for (int i = 0; i < result.length; i++) {
result[i] = it.next();
}
return result;
}
private IR makeIR(IMethod method, JavaTypeContext context) {
SSAInstruction instrs[] = makeStatements(context);
return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null);
}
public boolean recordFactoryType(CGNode node, IClass klass) {
return false;
}
public Iterator<FieldReference> iterateFieldsRead(CGNode node) {
return EmptyIterator.instance();
}
public Iterator<FieldReference> iterateFieldsWritten(CGNode node) {
return EmptyIterator.instance();
}
public ControlFlowGraph<ISSABasicBlock> getCFG(CGNode N) {
return getIR(N).getControlFlowGraph();
}
public DefUse getDU(CGNode node) {
return new DefUse(getIR(node));
}
}

View File

@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (c) 2008 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.analysis.reflection;
import com.ibm.wala.analysis.typeInference.PointType;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
/**
* A {@link ContextSelector} to intercept calls to Object.getClass()
*
* @author sjfink
*/
class GetClassContextSelector implements ContextSelector {
public final static MethodReference GET_CLASS = MethodReference.findOrCreate(TypeReference.JavaLangObject, "getClass", "()Ljava/lang/Class;");
public GetClassContextSelector() {
}
/**
*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode,
* com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod,
* com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
if (callee.getReference().equals(GET_CLASS)) {
return new JavaTypeContext(new PointType(receiver.getConcreteType()));
}
return null;
}
}

View File

@ -41,14 +41,6 @@ class JavaLangClassContextSelector implements ContextSelector {
public JavaLangClassContextSelector() {
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
/**
* If the {@link CallSiteReference} invokes a method we understand and c is a type constant, return a
* {@link JavaTypeContext} representing the type named by s, if we can resolve it in the {@link IClassHierarchy}.
@ -73,7 +65,7 @@ class JavaLangClassContextSelector implements ContextSelector {
/**
* This object may understand a dispatch to Class.getContructor when the receiver is a type constant.
*/
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (targetMethod.getReference().equals(JavaLangClassContextInterpreter.GET_CONSTRUCTOR) && getTypeConstant(instance) != null) {
return true;
}

View File

@ -32,10 +32,10 @@ public class ReflectionContextInterpreter extends DelegatingSSAContextInterprete
private ReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
ReflectionSpecification userSpec) {
super(new ReflectiveInvocationInterpreter(), new DelegatingSSAContextInterpreter(
new JavaLangClassContextInterpreter(), new DelegatingSSAContextInterpreter(new DelegatingSSAContextInterpreter(
new ForNameContextInterpreter(), new ClassNewInstanceContextInterpreter(cha)), new FactoryBypassInterpreter(options,
cache, userSpec))));
super(new ReflectiveInvocationInterpreter(), new DelegatingSSAContextInterpreter(new DelegatingSSAContextInterpreter(
new GetClassContextInterpeter(), new JavaLangClassContextInterpreter()), new DelegatingSSAContextInterpreter(
new DelegatingSSAContextInterpreter(new ForNameContextInterpreter(), new ClassNewInstanceContextInterpreter(cha)),
new FactoryBypassInterpreter(options, cache, userSpec))));
}
}

View File

@ -29,7 +29,7 @@ public class ReflectionContextSelector extends DelegatingContextSelector {
*/
private ReflectionContextSelector() {
super(new ReflectiveInvocationSelector(), new DelegatingContextSelector(new JavaLangClassContextSelector(),
new DelegatingContextSelector(new DelegatingContextSelector(new ForNameContextSelector(),
new ClassNewInstanceContextSelector()), new FactoryContextSelector())));
new DelegatingContextSelector(new DelegatingContextSelector(new DelegatingContextSelector(new ForNameContextSelector(),
new GetClassContextSelector()), new ClassNewInstanceContextSelector()), new FactoryContextSelector())));
}
}

View File

@ -37,14 +37,6 @@ class ReflectiveInvocationSelector implements ContextSelector {
public ReflectiveInvocationSelector() {
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
/**
* Creates a callee target based on the following criteria:
* <ol>
@ -113,7 +105,7 @@ class ReflectiveInvocationSelector implements ContextSelector {
/**
* This object may understand a dispatch to Constructor.newInstance().
*/
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (instance instanceof ConstantKey) {
if (targetMethod.getReference().equals(ReflectiveInvocationInterpreter.METHOD_INVOKE) || isConstructorConstant(instance)
&& targetMethod.getReference().equals(ReflectiveInvocationInterpreter.CTOR_NEW_INSTANCE)) {

View File

@ -409,6 +409,7 @@ public class PDG implements NumberedGraph<Statement> {
if (Assertions.verifyAssertions && dOptions.isIgnoreExceptions()) {
Assertions._assert(!s.getKind().equals(Kind.EXC_RET_CALLER));
}
ValueNumberCarrier a = (ValueNumberCarrier) s;
for (Iterator<SSAInstruction> it2 = DU.getUses(a.getValueNumber()); it2.hasNext();) {
SSAInstruction use = it2.next();

View File

@ -27,6 +27,8 @@ import com.ibm.wala.ipa.slicer.Slicer.DataDependenceOptions;
import com.ibm.wala.ipa.slicer.Statement.Kind;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
@ -337,6 +339,10 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
// a virtual dispatch is just like a cast. No flow.
return EmptyIterator.instance();
}
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(pac.getNode())) {
// don't track flow for reflection
return EmptyIterator.instance();
}
// data dependence predecessors
for (Iterator<? extends CGNode> it = cg.getPredNodes(N.getNode()); it.hasNext();) {
@ -356,11 +362,11 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
}
}
}
// if (!cOptions.equals(ControlDependenceOptions.NONE)) {
// Statement s = new MethodEntryStatement(N.getNode());
// addNode(s);
// result.add(s);
// }
// if (!cOptions.equals(ControlDependenceOptions.NONE)) {
// Statement s = new MethodEntryStatement(N.getNode());
// addNode(s);
// result.add(s);
// }
return result.iterator();
}
case HEAP_PARAM_CALLEE: {
@ -383,11 +389,11 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
}
}
}
// if (!cOptions.equals(ControlDependenceOptions.NONE)) {
// Statement s = new MethodEntryStatement(N.getNode());
// addNode(s);
// result.add(s);
// }
// if (!cOptions.equals(ControlDependenceOptions.NONE)) {
// Statement s = new MethodEntryStatement(N.getNode());
// addNode(s);
// result.add(s);
// }
return result.iterator();
}
case METHOD_ENTRY:
@ -420,6 +426,9 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
}
public Iterator<? extends Statement> getSuccNodes(Statement N) {
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(N.getNode())) {
return EmptyIterator.instance();
}
addPDGStatementNodes(N.getNode());
switch (N.getKind()) {
case NORMAL:
@ -463,7 +472,6 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
// SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) ir.getInstructions()[i];
Statement s = new ExceptionalReturnCaller(caller, i);
addNode(s);
result.add(s);
@ -485,7 +493,6 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
IntSet indices = ir.getCallInstructionIndices(site);
for (IntIterator ii = indices.intIterator(); ii.hasNext();) {
int i = ii.next();
// SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) ir.getInstructions()[i];
Statement s = new NormalReturnCaller(caller, i);
addNode(s);
result.add(s);
@ -529,6 +536,10 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
// a virtual dispatch is just like a cast.
continue;
}
if (dOptions.isTerminateAtCast() && isUninformativeForReflection(t)) {
// don't track reflection into reflective invokes
continue;
}
if (call.getUse(i) == pac.getValueNumber()) {
Statement s = new ParamCallee(t, i + 1);
addNode(s);
@ -560,6 +571,23 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
}
}
/**
* Should we cut off flow into node t when processing reflection?
*/
private boolean isUninformativeForReflection(CGNode t) {
if (t.getMethod().getDeclaringClass().getReference().equals(TypeReference.JavaLangReflectMethod)) {
return true;
}
if (t.getMethod().getDeclaringClass().getReference().equals(TypeReference.JavaLangReflectConstructor)) {
return true;
}
if (t.getMethod().getSelector().equals(MethodReference.equalsSelector)) {
Assertions.UNREACHABLE();
return true;
}
return false;
}
public boolean hasEdge(Statement src, Statement dst) {
addPDGStatementNodes(src.getNode());
addPDGStatementNodes(dst.getNode());
@ -728,7 +756,7 @@ public class SDG extends AbstractNumberedGraph<Statement> implements ISDG {
public DataDependenceOptions getDOptions() {
return dOptions;
}
public CallGraph getCallGraph() {
return cg;
}