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:
parent
c861bfed80
commit
4037ef9b02
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue