support for Constructor.newInstance()
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@2600 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
6fd7472393
commit
75bfab8605
|
@ -17,6 +17,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import com.ibm.wala.analysis.typeInference.ConeType;
|
import com.ibm.wala.analysis.typeInference.ConeType;
|
||||||
import com.ibm.wala.analysis.typeInference.TypeAbstraction;
|
import com.ibm.wala.analysis.typeInference.TypeAbstraction;
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
import com.ibm.wala.classLoader.IClass;
|
import com.ibm.wala.classLoader.IClass;
|
||||||
import com.ibm.wala.classLoader.IMethod;
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
import com.ibm.wala.classLoader.NewSiteReference;
|
import com.ibm.wala.classLoader.NewSiteReference;
|
||||||
|
@ -26,7 +27,9 @@ import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||||
import com.ibm.wala.ipa.callgraph.ReflectionSpecification;
|
import com.ibm.wala.ipa.callgraph.ReflectionSpecification;
|
||||||
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||||
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
import com.ibm.wala.ssa.SSAInstruction;
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
import com.ibm.wala.ssa.SSANewInstruction;
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
import com.ibm.wala.ssa.SSAReturnInstruction;
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
import com.ibm.wala.types.MethodReference;
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
@ -108,9 +111,7 @@ public abstract class AbstractReflectionInterpreter implements SSAContextInterpr
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author sfink
|
* A warning when we expect excessive pollution from a factory method
|
||||||
*
|
|
||||||
* A waring when we expect excessive pollution from a factory method
|
|
||||||
*/
|
*/
|
||||||
protected static class ManySubtypesWarning extends Warning {
|
protected static class ManySubtypesWarning extends Warning {
|
||||||
|
|
||||||
|
@ -135,8 +136,6 @@ public abstract class AbstractReflectionInterpreter implements SSAContextInterpr
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author sfink
|
|
||||||
*
|
|
||||||
* A warning when we fail to find subtypes for a factory method
|
* A warning when we fail to find subtypes for a factory method
|
||||||
*/
|
*/
|
||||||
protected static class NoSubtypesWarning extends Warning {
|
protected static class NoSubtypesWarning extends Warning {
|
||||||
|
@ -239,9 +238,25 @@ public abstract class AbstractReflectionInterpreter implements SSAContextInterpr
|
||||||
Trace.println("Added allocation: " + a);
|
Trace.println("Added allocation: " + a);
|
||||||
}
|
}
|
||||||
addInstruction(T, a, true);
|
addInstruction(T, a, true);
|
||||||
|
|
||||||
|
if (!T.isArrayType()) {
|
||||||
|
addCtorInvokeInstruction(T, alloc);
|
||||||
|
}
|
||||||
SSAReturnInstruction r = new SSAReturnInstruction(alloc, false);
|
SSAReturnInstruction r = new SSAReturnInstruction(alloc, false);
|
||||||
addInstruction(T, r, false);
|
addInstruction(T, r, false);
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void addCtorInvokeInstruction(final TypeReference T, int alloc) {
|
||||||
|
MethodReference init = MethodReference.findOrCreate(T, MethodReference.initAtom, MethodReference.defaultInitDesc);
|
||||||
|
CallSiteReference site = CallSiteReference.make(getCallSiteForType(T), init, IInvokeInstruction.Dispatch.SPECIAL);
|
||||||
|
int[] params = new int[1];
|
||||||
|
params[0] = alloc;
|
||||||
|
int exc = getExceptionsForType(T);
|
||||||
|
SSAInvokeInstruction s = new SSAInvokeInstruction(params, exc, site);
|
||||||
|
calls.add(s);
|
||||||
|
allInstructions.add(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,7 +46,7 @@ import com.ibm.wala.util.strings.Atom;
|
||||||
*
|
*
|
||||||
* @author pistoia
|
* @author pistoia
|
||||||
*/
|
*/
|
||||||
public class NewInstanceContextInterpreter extends AbstractReflectionInterpreter {
|
public class ClassNewInstanceContextInterpreter extends AbstractReflectionInterpreter {
|
||||||
|
|
||||||
public final static Atom newInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance");
|
public final static Atom newInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance");
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public class NewInstanceContextInterpreter extends AbstractReflectionInterpreter
|
||||||
|
|
||||||
private final IClassHierarchy cha;
|
private final IClassHierarchy cha;
|
||||||
|
|
||||||
public NewInstanceContextInterpreter(IClassHierarchy cha) {
|
public ClassNewInstanceContextInterpreter(IClassHierarchy cha) {
|
||||||
this.cha = cha;
|
this.cha = cha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,8 @@ public class NewInstanceContextInterpreter extends AbstractReflectionInterpreter
|
||||||
if (tr != null) {
|
if (tr != null) {
|
||||||
SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false);
|
SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false);
|
||||||
IClass klass = cha.lookupClass(tr);
|
IClass klass = cha.lookupClass(tr);
|
||||||
if (hasPublicDefaultCtor(klass)) {
|
IMethod publicDefaultCtor = getPublicDefaultCtor(klass);
|
||||||
|
if (publicDefaultCtor != null) {
|
||||||
m.addStatementsForConcreteSimpleType(tr);
|
m.addStatementsForConcreteSimpleType(tr);
|
||||||
} else if (klass.getMethod(defCtorSelector) == null) {
|
} else if (klass.getMethod(defCtorSelector) == null) {
|
||||||
TypeReference instantiationExceptionRef = TypeReference.findOrCreateClass(ClassLoaderReference.Primordial, "java/lang", "InstantiationException");
|
TypeReference instantiationExceptionRef = TypeReference.findOrCreateClass(ClassLoaderReference.Primordial, "java/lang", "InstantiationException");
|
||||||
|
@ -145,12 +146,12 @@ public class NewInstanceContextInterpreter extends AbstractReflectionInterpreter
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasPublicDefaultCtor(IClass klass) {
|
private IMethod getPublicDefaultCtor(IClass klass) {
|
||||||
IMethod ctorMethod = klass.getMethod(defCtorSelector);
|
IMethod ctorMethod = klass.getMethod(defCtorSelector);
|
||||||
if (ctorMethod != null && ctorMethod.isPublic()) {
|
if (ctorMethod != null && ctorMethod.isPublic()) {
|
||||||
return true;
|
return ctorMethod;
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean recordFactoryType(CGNode node, IClass klass) {
|
public boolean recordFactoryType(CGNode node, IClass klass) {
|
|
@ -25,9 +25,9 @@ import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
*
|
*
|
||||||
* @author pistoia
|
* @author pistoia
|
||||||
*/
|
*/
|
||||||
class NewInstanceContextSelector implements ContextSelector {
|
class ClassNewInstanceContextSelector implements ContextSelector {
|
||||||
|
|
||||||
public NewInstanceContextSelector() {
|
public ClassNewInstanceContextSelector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
|
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
|
||||||
|
@ -39,8 +39,9 @@ class NewInstanceContextSelector implements ContextSelector {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
|
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
|
||||||
if (mayUnderstand(caller, site, callee, receiver)) {
|
if (mayUnderstand(caller, site, callee, receiver)) {
|
||||||
return new JavaTypeContext(new PointType(receiver.getConcreteType()));
|
IClass c = (IClass) ((ConstantKey) receiver).getValue();
|
||||||
|
return new JavaTypeContext(new PointType(c));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +50,7 @@ class NewInstanceContextSelector implements ContextSelector {
|
||||||
* This object may understand a dispatch to Class.newInstance() when the class is a class constant.
|
* 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) {
|
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
|
||||||
if (targetMethod.getReference().equals(NewInstanceContextInterpreter.NEW_INSTANCE_REF) && isTypeConstant(instance)) {
|
if (targetMethod.getReference().equals(ClassNewInstanceContextInterpreter.NEW_INSTANCE_REF) && isTypeConstant(instance)) {
|
||||||
// IClass klass = getTypeConstant(instance);
|
// IClass klass = getTypeConstant(instance);
|
||||||
// if (hasPublicDefaultCtor(klass)) {
|
// if (hasPublicDefaultCtor(klass)) {
|
||||||
return true;
|
return true;
|
|
@ -0,0 +1,166 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
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.ConstantKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||||
|
import com.ibm.wala.ipa.summaries.SyntheticIR;
|
||||||
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.ConstantValue;
|
||||||
|
import com.ibm.wala.ssa.DefUse;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.ISSABasicBlock;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
|
import com.ibm.wala.types.Descriptor;
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.strings.Atom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link SSAContextInterpreter} specialized to interpret Constructor.newInstance in a {@link JavaTypeContext} which
|
||||||
|
* represents the point-type of the class object created by the call.
|
||||||
|
*
|
||||||
|
* @author pistoia
|
||||||
|
*/
|
||||||
|
public class ConstructorNewInstanceContextInterpreter extends AbstractReflectionInterpreter {
|
||||||
|
|
||||||
|
public final static Atom newInstanceAtom = Atom.findOrCreateUnicodeAtom("newInstance");
|
||||||
|
|
||||||
|
private final static Descriptor newInstanceDescriptor = Descriptor.findOrCreateUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
|
|
||||||
|
public final static MethodReference NEW_INSTANCE_REF = MethodReference.findOrCreate(TypeReference.JavaLangReflectConstructor,
|
||||||
|
newInstanceAtom, newInstanceDescriptor);
|
||||||
|
|
||||||
|
public IR getIR(CGNode node) {
|
||||||
|
if (node == null) {
|
||||||
|
throw new IllegalArgumentException("node is null");
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
ReceiverInstanceContext recv = (ReceiverInstanceContext)node.getContext();
|
||||||
|
ConstantKey c = (ConstantKey) recv.getReceiver();
|
||||||
|
IMethod m = (IMethod) c.getValue();
|
||||||
|
IR result = makeIR(node.getMethod(), m, recv);
|
||||||
|
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 ReceiverInstanceContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return node.getMethod().getReference().equals(NEW_INSTANCE_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<NewSiteReference> iterateNewSites(CGNode node) {
|
||||||
|
if (node == null) {
|
||||||
|
throw new IllegalArgumentException("node is null");
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
return getIR(node).iterateNewSites();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
return getIR(node).iterateCallSites();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IR makeIR(IMethod method, IMethod ctor, ReceiverInstanceContext context) {
|
||||||
|
SpecializedMethod m = new SpecializedMethod(method, method.getDeclaringClass(), method.isStatic(), false);
|
||||||
|
|
||||||
|
Map<Integer, ConstantValue> constants = HashMapFactory.make();
|
||||||
|
|
||||||
|
int nextLocal = method.getNumberOfParameters() + 1;
|
||||||
|
|
||||||
|
int nargs = ctor.getNumberOfParameters();
|
||||||
|
int args[] = new int[nargs];
|
||||||
|
int i = 0;
|
||||||
|
int pc = 0;
|
||||||
|
|
||||||
|
TypeReference allocatedType = ctor.getDeclaringClass().getReference();
|
||||||
|
m.addInstruction(allocatedType, new SSANewInstruction(args[i++] = nextLocal++, NewSiteReference.make(pc++, allocatedType)),
|
||||||
|
true);
|
||||||
|
|
||||||
|
for (int j = 1; j < nargs; j++) {
|
||||||
|
int indexConst = nextLocal++;
|
||||||
|
m.addInstruction(null, new SSAArrayLoadInstruction(args[i++] = nextLocal++, 2, indexConst, TypeReference.JavaLangObject),
|
||||||
|
false);
|
||||||
|
constants.put(new Integer(indexConst), new ConstantValue(j - 1));
|
||||||
|
pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exceptions = nextLocal++;
|
||||||
|
|
||||||
|
m.addInstruction(null, new SSAInvokeInstruction(args, exceptions, CallSiteReference.make(pc++, ctor.getReference(),
|
||||||
|
IInvokeInstruction.Dispatch.SPECIAL)), false);
|
||||||
|
|
||||||
|
m.addInstruction(null, new SSAReturnInstruction(args[0], false), false);
|
||||||
|
|
||||||
|
SSAInstruction[] instrs = new SSAInstruction[m.allInstructions.size()];
|
||||||
|
m.allInstructions.<SSAInstruction> toArray(instrs);
|
||||||
|
|
||||||
|
return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.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.ConstantKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ContextSelector} to intercept calls to Constructor.newInstance()
|
||||||
|
*
|
||||||
|
* @author pistoia
|
||||||
|
*/
|
||||||
|
class ConstructorNewInstanceContextSelector implements ContextSelector {
|
||||||
|
|
||||||
|
public ConstructorNewInstanceContextSelector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
|
||||||
|
if (mayUnderstand(caller, site, callee, receiver)) {
|
||||||
|
return new ReceiverInstanceContext(receiver);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object may understand a dispatch to Constructor.newInstance().
|
||||||
|
*/
|
||||||
|
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
|
||||||
|
if (targetMethod.getReference().equals(ConstructorNewInstanceContextInterpreter.NEW_INSTANCE_REF) && isConstructorConstant(instance)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isConstructorConstant(InstanceKey instance) {
|
||||||
|
if (instance instanceof ConstantKey) {
|
||||||
|
ConstantKey c = (ConstantKey) instance;
|
||||||
|
if (c.getConcreteType().getReference().equals(TypeReference.JavaLangReflectConstructor)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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 java.util.Map;
|
||||||
|
|
||||||
|
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.ConstantValue;
|
||||||
|
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.SSAOptions;
|
||||||
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAThrowInstruction;
|
||||||
|
import com.ibm.wala.types.Descriptor;
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.strings.Atom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link SSAContextInterpreter} specialized to interpret Class.forName in a {@link JavaTypeContext} which
|
||||||
|
* represents the point-type of the class object created by the call.
|
||||||
|
*
|
||||||
|
* @author pistoia
|
||||||
|
*/
|
||||||
|
public class GetConstructorContextInterpreter implements SSAContextInterpreter {
|
||||||
|
|
||||||
|
public final static Atom getConstructorAtom = Atom.findOrCreateUnicodeAtom("getConstructor");
|
||||||
|
|
||||||
|
private final static Descriptor getConstructorDescriptor = Descriptor.findOrCreateUTF8("([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;");
|
||||||
|
|
||||||
|
public final static MethodReference GET_CONSTRUCTOR_REF = MethodReference.findOrCreate(TypeReference.JavaLangClass, getConstructorAtom,
|
||||||
|
getConstructorDescriptor);
|
||||||
|
|
||||||
|
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(GET_CONSTRUCTOR_REF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<NewSiteReference> iterateNewSites(CGNode node) {
|
||||||
|
if (node == null) {
|
||||||
|
throw new IllegalArgumentException("node is null");
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
JavaTypeContext context = (JavaTypeContext) node.getContext();
|
||||||
|
TypeReference tr = context.getType().getTypeReference();
|
||||||
|
if (tr != null) {
|
||||||
|
return new NonNullSingletonIterator<NewSiteReference>(NewSiteReference.make(0, tr));
|
||||||
|
}
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SSAInstruction[] makeStatements(JavaTypeContext context, Map<Integer, ConstantValue> constants) {
|
||||||
|
ArrayList<SSAInstruction> statements = new ArrayList<SSAInstruction>();
|
||||||
|
int nextLocal = 2;
|
||||||
|
int retValue = nextLocal++;
|
||||||
|
IClass cls = context.getType().getType();
|
||||||
|
if (cls != null) {
|
||||||
|
for(Iterator methods = cls.getDeclaredMethods().iterator(); methods.hasNext(); ) {
|
||||||
|
IMethod m = (IMethod) methods.next();
|
||||||
|
if (m.isInit()) {
|
||||||
|
int c = nextLocal++;
|
||||||
|
constants.put(c, new ConstantValue(m));
|
||||||
|
SSAReturnInstruction R = new SSAReturnInstruction(c, false);
|
||||||
|
statements.add(R);
|
||||||
|
retValue++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SSAThrowInstruction t = new SSAThrowInstruction(retValue);
|
||||||
|
statements.add(t);
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
Map<Integer,ConstantValue> constants = HashMapFactory.make();
|
||||||
|
|
||||||
|
SSAInstruction instrs[] = makeStatements(context, constants);
|
||||||
|
return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.IClass;
|
||||||
|
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.ConstantKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ContextSelector} to intercept calls to Class.getConstructor() when the receiver is a type constant
|
||||||
|
*
|
||||||
|
* @author pistoia
|
||||||
|
*/
|
||||||
|
class GetConstructorContextSelector implements ContextSelector {
|
||||||
|
|
||||||
|
public GetConstructorContextSelector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the {@link CallSiteReference} invokes c.getConstructor() 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}.
|
||||||
|
*
|
||||||
|
* @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 (mayUnderstand(caller, site, callee, receiver)) {
|
||||||
|
return new JavaTypeContext(new PointType(getTypeConstant(receiver)));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IClass getTypeConstant(InstanceKey instance) {
|
||||||
|
if (instance instanceof ConstantKey) {
|
||||||
|
ConstantKey c = (ConstantKey)instance;
|
||||||
|
if (c.getValue() instanceof IClass) {
|
||||||
|
return (IClass)c.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
if (targetMethod.getReference().equals(GetConstructorContextInterpreter.GET_CONSTRUCTOR_REF) && getTypeConstant(instance) != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,18 +21,21 @@ import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||||
* {@link SSAContextInterpreter} to handle all reflection procession.
|
* {@link SSAContextInterpreter} to handle all reflection procession.
|
||||||
*
|
*
|
||||||
* @author sjfink
|
* @author sjfink
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ReflectionContextInterpreter extends DelegatingSSAContextInterpreter {
|
public class ReflectionContextInterpreter extends DelegatingSSAContextInterpreter {
|
||||||
|
|
||||||
public static ReflectionContextInterpreter createReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
|
public static ReflectionContextInterpreter createReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options,
|
||||||
ReflectionSpecification userSpec) {
|
AnalysisCache cache, ReflectionSpecification userSpec) {
|
||||||
return new ReflectionContextInterpreter(cha, options, cache, userSpec);
|
return new ReflectionContextInterpreter(cha, options, cache, userSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, ReflectionSpecification userSpec) {
|
private ReflectionContextInterpreter(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
|
||||||
super(new DelegatingSSAContextInterpreter(new ForNameContextInterpreter(), new NewInstanceContextInterpreter(cha)),
|
ReflectionSpecification userSpec) {
|
||||||
new FactoryBypassInterpreter(options, cache, userSpec));
|
super(new ConstructorNewInstanceContextInterpreter(), new DelegatingSSAContextInterpreter(
|
||||||
|
new GetConstructorContextInterpreter(), new DelegatingSSAContextInterpreter(new DelegatingSSAContextInterpreter(
|
||||||
|
new ForNameContextInterpreter(), new ClassNewInstanceContextInterpreter(cha)), new FactoryBypassInterpreter(options,
|
||||||
|
cache, userSpec))));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@ public class ReflectionContextSelector extends DelegatingContextSelector {
|
||||||
* First check "forName" logic, then factory logic.
|
* First check "forName" logic, then factory logic.
|
||||||
*/
|
*/
|
||||||
private ReflectionContextSelector(IClassHierarchy cha, MethodTargetSelector methodTargetSelector) {
|
private ReflectionContextSelector(IClassHierarchy cha, MethodTargetSelector methodTargetSelector) {
|
||||||
super(new DelegatingContextSelector(new ForNameContextSelector(), new NewInstanceContextSelector()),
|
super(new ConstructorNewInstanceContextSelector(),
|
||||||
new FactoryContextSelector(cha, methodTargetSelector));
|
new DelegatingContextSelector(new GetConstructorContextSelector(),
|
||||||
|
new DelegatingContextSelector(new DelegatingContextSelector(new ForNameContextSelector(), new ClassNewInstanceContextSelector()),
|
||||||
|
new FactoryContextSelector(cha, methodTargetSelector))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ public interface Language {
|
||||||
public TypeReference getConstantType(Object o) {
|
public TypeReference getConstantType(Object o) {
|
||||||
if (o instanceof String) {
|
if (o instanceof String) {
|
||||||
return TypeReference.JavaLangString;
|
return TypeReference.JavaLangString;
|
||||||
|
} else if (o instanceof IMethod) {
|
||||||
|
IMethod m = (IMethod) o;
|
||||||
|
return m.isInit() ? TypeReference.JavaLangReflectConstructor : TypeReference.JavaLangReflectMethod;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,13 +261,17 @@ public class ZeroXInstanceKeys implements InstanceKeyFactory {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new IllegalArgumentException("null type");
|
throw new IllegalArgumentException("null type");
|
||||||
}
|
}
|
||||||
if (disambiguateConstants()) {
|
if (disambiguateConstants() || isReflectiveType(type)) {
|
||||||
return new ConstantKey<T>(S, getClassHierarchy().lookupClass(type));
|
return new ConstantKey<T>(S, getClassHierarchy().lookupClass(type));
|
||||||
} else {
|
} else {
|
||||||
return classBased.getInstanceKeyForConstant(type, S);
|
return classBased.getInstanceKeyForConstant(type, S);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isReflectiveType(TypeReference type) {
|
||||||
|
return type.equals(TypeReference.JavaLangReflectConstructor);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory#getInstanceKeyForPEI(com.ibm.wala.ipa.callgraph.CGNode,
|
* @see com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory#getInstanceKeyForPEI(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
* com.ibm.wala.classLoader.ProgramCounter,
|
* com.ibm.wala.classLoader.ProgramCounter,
|
||||||
|
|
|
@ -25,7 +25,7 @@ import com.ibm.wala.util.shrike.Exceptions;
|
||||||
public class SSAArrayLoadInstruction extends SSAArrayReferenceInstruction {
|
public class SSAArrayLoadInstruction extends SSAArrayReferenceInstruction {
|
||||||
private final int result;
|
private final int result;
|
||||||
|
|
||||||
SSAArrayLoadInstruction(int result, int arrayref, int index, TypeReference elementType) {
|
public SSAArrayLoadInstruction(int result, int arrayref, int index, TypeReference elementType) {
|
||||||
super(arrayref, index, elementType);
|
super(arrayref, index, elementType);
|
||||||
this.result = result;
|
this.result = result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,6 +163,11 @@ public final class TypeReference {
|
||||||
|
|
||||||
public final static TypeReference JavaLangReflectConstructor = findOrCreate(ClassLoaderReference.Primordial,
|
public final static TypeReference JavaLangReflectConstructor = findOrCreate(ClassLoaderReference.Primordial,
|
||||||
JavaLangReflectConstructorName);
|
JavaLangReflectConstructorName);
|
||||||
|
|
||||||
|
private final static TypeName JavaLangReflectMethodName = TypeName.string2TypeName("Ljava/lang/reflect/Method");
|
||||||
|
|
||||||
|
public final static TypeReference JavaLangReflectMethod = findOrCreate(ClassLoaderReference.Primordial,
|
||||||
|
JavaLangReflectMethodName);
|
||||||
|
|
||||||
private final static TypeName JavaLangErrorName = TypeName.string2TypeName("Ljava/lang/Error");
|
private final static TypeName JavaLangErrorName = TypeName.string2TypeName("Ljava/lang/Error");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue