274 lines
8.6 KiB
Java
274 lines
8.6 KiB
Java
/*******************************************************************************
|
|
* 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 static com.ibm.wala.types.TypeName.ArrayMask;
|
|
import static com.ibm.wala.types.TypeName.ElementMask;
|
|
import static com.ibm.wala.types.TypeName.PrimitiveMask;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashSet;
|
|
import java.util.Map;
|
|
|
|
import com.ibm.wala.analysis.typeInference.ConeType;
|
|
import com.ibm.wala.analysis.typeInference.TypeAbstraction;
|
|
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.classLoader.SyntheticMethod;
|
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
|
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
|
|
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
|
import com.ibm.wala.ssa.SSAInstructionFactory;
|
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
|
import com.ibm.wala.ssa.SSANewInstruction;
|
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
|
import com.ibm.wala.types.MethodReference;
|
|
import com.ibm.wala.types.TypeReference;
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
import com.ibm.wala.util.warnings.Warning;
|
|
|
|
/**
|
|
* An abstract superclass of various {@link SSAContextInterpreter}s that deal with reflection methods.
|
|
*/
|
|
public abstract class AbstractReflectionInterpreter implements SSAContextInterpreter {
|
|
|
|
protected static final boolean DEBUG = false;
|
|
|
|
protected final static int CONE_BOUND = 10;
|
|
|
|
protected int indexLocal = 100;
|
|
|
|
protected final Map<TypeReference, Integer> typeIndexMap = HashMapFactory.make();
|
|
|
|
/**
|
|
* Governing analysis options
|
|
*/
|
|
protected AnalysisOptions options;
|
|
|
|
/**
|
|
* cache of analysis information
|
|
*/
|
|
protected IAnalysisCacheView cache;
|
|
|
|
|
|
protected int getLocalForType(TypeReference T) {
|
|
Integer I = typeIndexMap.get(T);
|
|
if (I == null) {
|
|
typeIndexMap.put(T, I = Integer.valueOf(indexLocal += 2));
|
|
}
|
|
return I.intValue();
|
|
}
|
|
|
|
protected int getExceptionsForType(TypeReference T) {
|
|
return getLocalForType(T) + 1;
|
|
}
|
|
|
|
protected int getCallSiteForType(TypeReference T) {
|
|
return getLocalForType(T);
|
|
}
|
|
|
|
protected int getNewSiteForType(TypeReference T) {
|
|
return getLocalForType(T) + 1;
|
|
}
|
|
|
|
/**
|
|
* @param type
|
|
* @return a TypeAbstraction object representing this type. We just use ConeTypes by default, since we don't propagate
|
|
* information allowing us to distinguish between points and cones yet.
|
|
*/
|
|
protected TypeAbstraction typeRef2TypeAbstraction(IClassHierarchy cha, TypeReference type) {
|
|
IClass klass = cha.lookupClass(type);
|
|
if (klass != null) {
|
|
return new ConeType(klass);
|
|
}
|
|
Assertions.UNREACHABLE(type.toString());
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* A warning when we expect excessive pollution from a factory method
|
|
*/
|
|
protected static class ManySubtypesWarning extends Warning {
|
|
|
|
final int nImplementors;
|
|
|
|
final TypeAbstraction T;
|
|
|
|
ManySubtypesWarning(TypeAbstraction T, int nImplementors) {
|
|
super(Warning.MODERATE);
|
|
this.T = T;
|
|
this.nImplementors = nImplementors;
|
|
}
|
|
|
|
@Override
|
|
public String getMsg() {
|
|
return getClass().toString() + " : " + T + " " + nImplementors;
|
|
}
|
|
|
|
public static ManySubtypesWarning create(TypeAbstraction T, int n) {
|
|
return new ManySubtypesWarning(T, n);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A warning when we fail to find subtypes for a factory method
|
|
*/
|
|
protected static class NoSubtypesWarning extends Warning {
|
|
|
|
final TypeAbstraction T;
|
|
|
|
NoSubtypesWarning(TypeAbstraction T) {
|
|
super(Warning.SEVERE);
|
|
this.T = T;
|
|
}
|
|
|
|
@Override
|
|
public String getMsg() {
|
|
return getClass().toString() + " : " + T;
|
|
}
|
|
|
|
public static NoSubtypesWarning create(TypeAbstraction T) {
|
|
return new NoSubtypesWarning(T);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A warning when we find flow of a factory allocation to a cast to {@link Serializable}
|
|
*/
|
|
protected static class IgnoreSerializableWarning extends Warning {
|
|
|
|
final private static IgnoreSerializableWarning instance = new IgnoreSerializableWarning();
|
|
|
|
@Override
|
|
public String getMsg() {
|
|
return getClass().toString();
|
|
}
|
|
|
|
public static IgnoreSerializableWarning create() {
|
|
return instance;
|
|
}
|
|
}
|
|
|
|
protected class SpecializedMethod extends SyntheticMethod {
|
|
|
|
/**
|
|
* Set of types that we have already inserted an allocation for.
|
|
*/
|
|
protected final HashSet<TypeReference> typesAllocated = HashSetFactory.make(5);
|
|
|
|
/**
|
|
* List of synthetic allocation statements we model for this specialized instance
|
|
*/
|
|
final protected ArrayList<SSAInstruction> allocations = new ArrayList<>();
|
|
|
|
/**
|
|
* List of synthetic invoke instructions we model for this specialized instance.
|
|
*/
|
|
final protected ArrayList<SSAInstruction> calls = new ArrayList<>();
|
|
|
|
/**
|
|
* List of all instructions
|
|
*/
|
|
protected final ArrayList<SSAInstruction> allInstructions = new ArrayList<>();
|
|
|
|
private final SSAInstructionFactory insts = declaringClass.getClassLoader().getInstructionFactory();
|
|
|
|
public SpecializedMethod(MethodReference method, IClass declaringClass, boolean isStatic, boolean isFactory) {
|
|
super(method, declaringClass, isStatic, isFactory);
|
|
}
|
|
|
|
public SpecializedMethod(IMethod method, IClass declaringClass, boolean isStatic, boolean isFactory) {
|
|
super(method, declaringClass, isStatic, isFactory);
|
|
}
|
|
|
|
/**
|
|
* @param T type allocated by the instruction.
|
|
*/
|
|
protected void addInstruction(final TypeReference T, SSAInstruction instr, boolean isAllocation) {
|
|
if (isAllocation) {
|
|
if (typesAllocated.contains(T)) {
|
|
return;
|
|
} else {
|
|
typesAllocated.add(T);
|
|
}
|
|
}
|
|
|
|
allInstructions.add(instr);
|
|
if (isAllocation) {
|
|
allocations.add(instr);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param t type of object to allocate
|
|
* @return value number of the newly allocated object
|
|
*/
|
|
protected int addStatementsForConcreteSimpleType(final TypeReference t) {
|
|
// assert we haven't allocated this type already.
|
|
assert !typesAllocated.contains(t);
|
|
if (DEBUG) {
|
|
System.err.println(("addStatementsForConcreteType: " + t));
|
|
}
|
|
NewSiteReference ref = NewSiteReference.make(getNewSiteForType(t), t);
|
|
int alloc = getLocalForType(t);
|
|
|
|
if (t.isArrayType()) {
|
|
// for now, just allocate an array of size 1 in each dimension.
|
|
int dims = 0;
|
|
int dim = t.getDerivedMask();
|
|
if ((dim&ElementMask) == PrimitiveMask) {
|
|
dim >>= 2;
|
|
}
|
|
while ((dim&ElementMask) == ArrayMask) {
|
|
dims++;
|
|
dim >>=2;
|
|
}
|
|
|
|
int[] extents = new int[dims];
|
|
Arrays.fill(extents, 1);
|
|
SSANewInstruction a = insts.NewInstruction(allInstructions.size(), alloc, ref, extents);
|
|
addInstruction(t, a, true);
|
|
} else {
|
|
SSANewInstruction a = insts.NewInstruction(allInstructions.size(), alloc, ref);
|
|
addInstruction(t, a, true);
|
|
addCtorInvokeInstruction(t, alloc);
|
|
}
|
|
|
|
SSAReturnInstruction r = insts.ReturnInstruction(allInstructions.size(), alloc, false);
|
|
addInstruction(t, r, false);
|
|
return alloc;
|
|
}
|
|
|
|
/**
|
|
* Add an instruction to invoke the default constructor on the object of value number alloc of type t.
|
|
*/
|
|
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 = insts.InvokeInstruction(allInstructions.size(), params, exc, site, null);
|
|
calls.add(s);
|
|
allInstructions.add(s);
|
|
}
|
|
}
|
|
}
|