com.ibm.wala.cast.js.ipa.callgraph.RecursionBoundContextSelector 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.js Show documentation
Show all versions of com.ibm.wala.cast.js Show documentation
T. J. Watson Libraries for Analysis
/*
* Copyright (c) 2013 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.js.ipa.callgraph;
import com.ibm.wala.analysis.reflection.InstanceKeyWithNode;
import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions.JavaScriptConstructor;
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.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleInstanceFilter;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallString;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallStringContext;
import com.ibm.wala.util.intset.IntSet;
/**
* A context selector that attempts to detect recursion beyond some depth in a base selector. If
* such recursion is detected, the base selector's context is replaced with {@link
* Everywhere#EVERYWHERE}.
*/
public class RecursionBoundContextSelector implements ContextSelector {
private final ContextSelector base;
private final int recursionBound;
/**
* the highest parameter index that we'll check . this is a HACK. ideally, given a context, we'd
* have some way to know all the {@link ContextKey}s that it knows about.
*
* @see ContextKey#PARAMETERS
*/
private static final int MAX_INTERESTING_PARAM = 5;
/**
* @param recursionBound bound on recursion depth, with the top level of the context returned by
* the base selector being depth 0. The {@link Everywhere#EVERYWHERE} context is returned if
* the base context exceeds this bound.
*/
public RecursionBoundContextSelector(ContextSelector base, int recursionBound) {
this.base = base;
this.recursionBound = recursionBound;
}
@Override
public Context getCalleeTarget(
CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) {
Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters);
final boolean exceedsRecursionBound = exceedsRecursionBound(baseContext, 0);
if (!exceedsRecursionBound) {
return baseContext;
} else if (callee instanceof JavaScriptConstructor) {
// for constructors, we want to keep some basic context sensitivity to
// avoid horrible imprecision
return new CallStringContext(new CallString(site, caller.getMethod()));
} else {
// TODO somehow k-limit more smartly?
return Everywhere.EVERYWHERE;
}
}
private boolean exceedsRecursionBound(Context baseContext, int curLevel) {
if (curLevel > recursionBound) {
return true;
}
// we just do a case analysis here. we might have to add cases later to
// account for new types of context / recursion.
CGNode callerNode = (CGNode) baseContext.get(ContextKey.CALLER);
if (callerNode != null && exceedsRecursionBound(callerNode.getContext(), curLevel + 1)) {
return true;
}
for (int i = 0; i < MAX_INTERESTING_PARAM; i++) {
FilteredPointerKey.SingleInstanceFilter filter =
(SingleInstanceFilter) baseContext.get(ContextKey.PARAMETERS[i]);
if (filter != null) {
InstanceKey ik = filter.getInstance();
if (ik instanceof ScopeMappingInstanceKey) {
ik = ((ScopeMappingInstanceKey) ik).getBase();
}
if (ik instanceof InstanceKeyWithNode) {
if (exceedsRecursionBound(
((InstanceKeyWithNode) ik).getNode().getContext(), curLevel + 1)) {
return true;
}
}
}
}
return false;
}
@Override
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return base.getRelevantParameters(caller, site);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy