From d1974d8b5440960984b53e5f96b5488bb2264b4b Mon Sep 17 00:00:00 2001 From: msridhar1 Date: Fri, 17 Feb 2012 20:26:14 +0000 Subject: [PATCH] new context selector that just checks for recursion instead of bounding it git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4509 f5eafffb-2e1d-0410-98e4-8ec43c5233c4 --- .../cast/js/rhino/test/HTMLCGBuilder.java | 4 +- .../RecursionCheckContextSelector.java | 111 ++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/RecursionCheckContextSelector.java diff --git a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/rhino/test/HTMLCGBuilder.java b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/rhino/test/HTMLCGBuilder.java index 360d590e3..c01adcd46 100644 --- a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/rhino/test/HTMLCGBuilder.java +++ b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/rhino/test/HTMLCGBuilder.java @@ -16,6 +16,7 @@ import com.ibm.wala.cast.js.ipa.callgraph.ForInContextSelector; import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionDotCallTargetSelector; import com.ibm.wala.cast.js.ipa.callgraph.RecursionBoundContextSelector; +import com.ibm.wala.cast.js.ipa.callgraph.RecursionCheckContextSelector; import com.ibm.wala.cast.js.ipa.callgraph.correlations.extraction.CorrelatedPairExtractorFactory; import com.ibm.wala.cast.js.test.JSCallGraphBuilderUtil; import com.ibm.wala.cast.js.test.JSCallGraphBuilderUtil.CGBuilderType; @@ -92,7 +93,8 @@ public class HTMLCGBuilder { // the code below belongs somewhere else!!! // the bound of 4 is what is needed to pass our current framework tests if (AstTranslator.NEW_LEXICAL) { - builder.setContextSelector(new RecursionBoundContextSelector(builder.getContextSelector(), 4)); +// builder.setContextSelector(new RecursionBoundContextSelector(builder.getContextSelector(), 4)); + builder.setContextSelector(new RecursionCheckContextSelector(builder.getContextSelector())); } ProgressMaster master = ProgressMaster.make(new NullProgressMonitor()); if (timeout > 0) { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/RecursionCheckContextSelector.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/RecursionCheckContextSelector.java new file mode 100644 index 000000000..a1403043a --- /dev/null +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/RecursionCheckContextSelector.java @@ -0,0 +1,111 @@ +package com.ibm.wala.cast.js.ipa.callgraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; + +import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; +import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey; +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.util.collections.Pair; +import com.ibm.wala.util.intset.IntSet; + +/** + * 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 boolean recursiveContext(Context baseContext, IMethod callee) { + LinkedList>> worklist = new LinkedList>>(); + 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 boolean updateForNode(Context baseContext, Collection curEncountered, LinkedList>> worklist, CGNode callerNode) { + final IMethod method = callerNode.getMethod(); + 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); + } + + +}