add new analysis option JSAnalysisOptions.usePreciseLexical(), which allows for a less precise handling of lexical accesses

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4494 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
msridhar1 2012-02-17 20:22:30 +00:00
parent c861bfed80
commit 4037ef9b02
4 changed files with 107 additions and 46 deletions

View File

@ -2,7 +2,9 @@ package com.ibm.wala.cast.js.ipa.callgraph;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext;
/**
* call graph construction options specific to JavaScript.
@ -17,6 +19,18 @@ public class JSAnalysisOptions extends AnalysisOptions {
private boolean useLoadFileTargetSelector = true;
/**
* should the analysis employ additional context sensitivity for more precise handling of lexical accesses? if true, then:
*
* <ol>
* <li>Employ a {@link CallerSiteContext} for calls to constructors of functions that may perform a lexical access.</li>
* <li>Employ a {@link CallerSiteContext} for calls to functions that may perform a lexical access.</li>
* </ol>
*
* The above helps to avoid conflation of lexical variables associated with distinct {@link CGNode}s.
*/
private boolean usePreciseLexical = false;
public JSAnalysisOptions(AnalysisScope scope, Iterable<? extends Entrypoint> e) {
super(scope, e);
}
@ -39,4 +53,12 @@ public class JSAnalysisOptions extends AnalysisOptions {
public void setUseLoadFileTargetSelector(boolean useIt) {
this.useLoadFileTargetSelector = useIt;
}
public boolean usePreciseLexical() {
return usePreciseLexical;
}
public void setUsePreciseLexical(boolean usePreciseLexical) {
this.usePreciseLexical = usePreciseLexical;
}
}

View File

@ -38,29 +38,27 @@ public class JSZeroOrOneXCFABuilder extends JSCFABuilder {
ContextSelector appContextSelector, SSAContextInterpreter appContextInterpreter, int instancePolicy, boolean doOneCFA) {
super(cha, options, cache);
SSAContextInterpreter contextInterpreter = makeDefaultContextInterpreters(appContextInterpreter, options, cha);
if (options.handleCallApply()) {
contextInterpreter = new DelegatingSSAContextInterpreter(new JavaScriptFunctionApplyContextInterpreter(options, cache),
contextInterpreter);
}
setContextInterpreter(contextInterpreter);
SSAContextInterpreter contextInterpreter = setupSSAContextInterpreter(cha, options, cache, appContextInterpreter);
MethodTargetSelector targetSelector = new JavaScriptConstructTargetSelector(cha, options
.getMethodTargetSelector());
if (options.handleCallApply()) {
targetSelector = new JavaScriptFunctionApplyTargetSelector(new JavaScriptFunctionDotCallTargetSelector(targetSelector));
}
if (options.useLoadFileTargetSelector()) {
targetSelector = new LoadFileTargetSelector(targetSelector, this);
}
options.setSelector(targetSelector);
setupMethodTargetSelector(cha, options);
setupContextSelector(options, appContextSelector, doOneCFA);
setInstanceKeys(new JavaScriptScopeMappingInstanceKeys(cha, this, new JavaScriptConstructorInstanceKeys(new ZeroXInstanceKeys(
options, cha, contextInterpreter, instancePolicy))));
}
private void setupContextSelector(JSAnalysisOptions options, ContextSelector appContextSelector, boolean doOneCFA) {
// baseline selector
ContextSelector def = new ContextInsensitiveSelector();
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
// if (!AstTranslator.NEW_LEXICAL) {
// JavaScriptConstructorContextSelector ensures at least a 0-1-CFA (i.e., Andersen's-style) heap abstraction
contextSelector = new JavaScriptConstructorContextSelector(contextSelector, options.usePreciseLexical());
if (!AstTranslator.NEW_LEXICAL || options.usePreciseLexical()) {
contextSelector = new ScopeMappingKeysContextSelector(contextSelector);
// }
contextSelector = new JavaScriptConstructorContextSelector(contextSelector);
}
if (USE_OBJECT_SENSITIVITY) {
contextSelector = new ObjectSensitivityContextSelector(contextSelector);
}
@ -74,9 +72,29 @@ public class JSZeroOrOneXCFABuilder extends JSCFABuilder {
contextSelector = new nCFAContextSelector(1, contextSelector);
}
setContextSelector(contextSelector);
}
setInstanceKeys(new JavaScriptScopeMappingInstanceKeys(cha, this, new JavaScriptConstructorInstanceKeys(new ZeroXInstanceKeys(
options, cha, contextInterpreter, instancePolicy))));
private void setupMethodTargetSelector(IClassHierarchy cha, JSAnalysisOptions options) {
MethodTargetSelector targetSelector = new JavaScriptConstructTargetSelector(cha, options
.getMethodTargetSelector());
if (options.handleCallApply()) {
targetSelector = new JavaScriptFunctionApplyTargetSelector(new JavaScriptFunctionDotCallTargetSelector(targetSelector));
}
if (options.useLoadFileTargetSelector()) {
targetSelector = new LoadFileTargetSelector(targetSelector, this);
}
options.setSelector(targetSelector);
}
private SSAContextInterpreter setupSSAContextInterpreter(IClassHierarchy cha, JSAnalysisOptions options, AnalysisCache cache,
SSAContextInterpreter appContextInterpreter) {
SSAContextInterpreter contextInterpreter = makeDefaultContextInterpreters(appContextInterpreter, options, cha);
if (options.handleCallApply()) {
contextInterpreter = new DelegatingSSAContextInterpreter(new JavaScriptFunctionApplyContextInterpreter(options, cache),
contextInterpreter);
}
setContextInterpreter(contextInterpreter);
return contextInterpreter;
}
/**

View File

@ -10,9 +10,7 @@ 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.DelegatingContext;
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallerSiteContext;
import com.ibm.wala.ipa.callgraph.propagation.cfa.OneLevelSiteContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.cfa.nCFAContextSelector;
import com.ibm.wala.util.intset.IntSet;
@ -28,10 +26,13 @@ public class JavaScriptConstructorContextSelector implements ContextSelector {
private final OneLevelSiteContextSelector oneLevelCallerSite;
public JavaScriptConstructorContextSelector(ContextSelector base) {
private final boolean usePreciseLexical;
public JavaScriptConstructorContextSelector(ContextSelector base, boolean usePreciseLexical) {
this.base = base;
this.oneLevelCallStrings = new nCFAContextSelector(1, base);
this.oneLevelCallerSite = new OneLevelSiteContextSelector(base);
this.usePreciseLexical = usePreciseLexical;
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
@ -44,7 +45,7 @@ public class JavaScriptConstructorContextSelector implements ContextSelector {
final Context callerContext = caller.getContext();
if (!AstTranslator.NEW_LEXICAL && callerContext instanceof ScopeMappingContext) {
return new DelegatingContext(callerContext, oneLevelCallStringContext);
} else if (AstTranslator.NEW_LEXICAL && LexicalScopingResolverContexts.hasExposedUses(caller, site)) {
} else if (AstTranslator.NEW_LEXICAL && usePreciseLexical && LexicalScopingResolverContexts.hasExposedUses(caller, site)) {
// use a caller-site context, to enable lexical scoping lookups (via caller CGNode)
return oneLevelCallerSite.getCalleeTarget(caller, site, callee, receiver);
} else {

View File

@ -10,20 +10,26 @@
*****************************************************************************/
package com.ibm.wala.cast.ipa.callgraph;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts.LexicalScopingResolver;
import com.ibm.wala.cast.ir.translator.AstTranslator;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallString;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallStringContextSelector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator;
@ -94,31 +100,30 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
*/
Iterator<CGNode> getFunargNodes(Pair<String, String> name) {
if (AstTranslator.NEW_LEXICAL) {
CGNode callerOfConstructor = (CGNode) creator.getContext().get(ContextKey.CALLER);
if (callerOfConstructor == null) {
System.err.println(creator);
assert false;
}
if (callerOfConstructor.getMethod().getReference().getDeclaringClass().getName().toString().equals(name.snd)){
return new NonNullSingletonIterator<CGNode>(callerOfConstructor);
} else {
PointerKey funcKey = builder.getPointerKeyForLocal(callerOfConstructor, 1);
OrdinalSet<InstanceKey> funcPtrs = builder.getPointerAnalysis().getPointsToSet(funcKey);
assert funcPtrs.size() == 1;
InstanceKey funcPtr = funcPtrs.iterator().next();
if (funcPtr instanceof ScopeMappingInstanceKey) {
return ((ScopeMappingInstanceKey) funcPtr).getFunargNodes(name);
Collection<CGNode> constructorCallers = getConstructorCallers();
assert !constructorCallers.isEmpty() : "no callers for constructor";
Iterator<CGNode> result = EmptyIterator.instance();
for (CGNode callerOfConstructor : constructorCallers) {
if (callerOfConstructor.getMethod().getReference().getDeclaringClass().getName().toString().equals(name.snd)){
result = new CompoundIterator<CGNode>(result, new NonNullSingletonIterator<CGNode>(callerOfConstructor));
} else {
return EmptyIterator.instance();
}
// Iterator<CGNode> result = EmptyIterator.instance();
// for (InstanceKey x : funcPtrs) {
// if (x instanceof ScopeMappingInstanceKey) {
// result = new CompoundIterator<CGNode>(result, ((ScopeMappingInstanceKey) x).getFunargNodes(name));
PointerKey funcKey = builder.getPointerKeyForLocal(callerOfConstructor, 1);
OrdinalSet<InstanceKey> funcPtrs = builder.getPointerAnalysis().getPointsToSet(funcKey);
for (InstanceKey funcPtr : funcPtrs) {
if (funcPtr instanceof ScopeMappingInstanceKey) {
result = new CompoundIterator<CGNode>(result, ((ScopeMappingInstanceKey) funcPtr).getFunargNodes(name));
}
}
// Iterator<CGNode> result = EmptyIterator.instance();
// for (InstanceKey x : funcPtrs) {
// if (x instanceof ScopeMappingInstanceKey) {
// result = new CompoundIterator<CGNode>(result, ((ScopeMappingInstanceKey) x).getFunargNodes(name));
// }
// }
// }
// return result;
// return result;
}
}
return result;
} else {
Iterator<CGNode> result = EmptyIterator.instance();
@ -154,6 +159,21 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
}
}
private Collection<CGNode> getConstructorCallers() {
final Context creatorContext = creator.getContext();
CGNode callerOfConstructor = (CGNode) creatorContext.get(ContextKey.CALLER);
if (callerOfConstructor != null) {
return Collections.singleton(callerOfConstructor);
} else {
CallString cs = (CallString) creatorContext.get(CallStringContextSelector.CALL_STRING);
assert cs != null : "unexpected context " + creatorContext;
IMethod[] methods = cs.getMethods();
assert methods.length == 1;
IMethod m = methods[0];
return builder.getCallGraph().getNodes(m.getReference());
}
}
public int hashCode() {
return base.hashCode() * creator.hashCode();
}