com.ibm.wala.cast.js.ipa.callgraph.RecursionCheckContextSelector 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.types.JavaScriptMethods;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
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.propagation.FilteredPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey.SingleInstanceFilter;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.intset.IntSet;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/**
* ensures that no contexts returned by a base context selector are recursive (assertion failure
* otherwise)
*/
public class RecursionCheckContextSelector implements ContextSelector {
private final ContextSelector base;
/**
* 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;
public RecursionCheckContextSelector(ContextSelector base) {
this.base = base;
}
@Override
public Context getCalleeTarget(
CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) {
Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters);
assert !recursiveContext(baseContext, callee);
return baseContext;
}
private static boolean recursiveContext(Context baseContext, IMethod callee) {
if (!recursionPossible(callee)) {
return false;
}
ArrayDeque>> worklist = new ArrayDeque<>();
worklist.push(Pair.make(baseContext, (Collection) Collections.singleton(callee)));
while (!worklist.isEmpty()) {
Pair> p = worklist.removeFirst();
Context curContext = p.fst;
Collection curEncountered = p.snd;
// 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) curContext.get(ContextKey.CALLER);
if (callerNode != null) {
if (!updateForNode(baseContext, curEncountered, worklist, callerNode)) {
System.err.println("callee " + callee);
return true;
}
}
for (int i = 0; i < MAX_INTERESTING_PARAM; i++) {
FilteredPointerKey.SingleInstanceFilter filter =
(SingleInstanceFilter) curContext.get(ContextKey.PARAMETERS[i]);
if (filter != null) {
InstanceKey ik = filter.getInstance();
if (ik instanceof ScopeMappingInstanceKey) {
ik = ((ScopeMappingInstanceKey) ik).getBase();
}
if (ik instanceof InstanceKeyWithNode) {
CGNode node = ((InstanceKeyWithNode) ik).getNode();
if (!updateForNode(baseContext, curEncountered, worklist, node)) {
System.err.println("callee " + callee);
return true;
}
}
}
}
}
return false;
}
private static boolean updateForNode(
Context baseContext,
Collection curEncountered,
ArrayDeque>> worklist,
CGNode callerNode) {
final IMethod method = callerNode.getMethod();
if (!recursionPossible(method)) {
assert !curEncountered.contains(method);
return true;
}
if (curEncountered.contains(method)) {
System.err.println("recursion in context on method " + method);
System.err.println("encountered methods: ");
for (IMethod m : curEncountered) {
System.err.println(" " + m);
}
System.err.println("context " + baseContext);
return false;
}
Collection newEncountered = new ArrayList<>(curEncountered);
newEncountered.add(method);
worklist.add(Pair.make(callerNode.getContext(), newEncountered));
return true;
}
@Override
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return base.getRelevantParameters(caller, site);
}
/** is it possible for m to be involved in a recursive cycle? */
private static boolean recursionPossible(IMethod m) {
// object or array constructors cannot be involved
if (m.getReference().getName().equals(JavaScriptMethods.ctorAtom)) {
TypeReference declaringClass = m.getReference().getDeclaringClass();
if (declaringClass.equals(JavaScriptTypes.Object)
|| declaringClass.equals(JavaScriptTypes.Array)) {
return false;
}
}
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy