refactoring to integrate field-based cg builders with Eclipse-based

JavaScript front end
This commit is contained in:
Julian Dolby 2013-08-05 14:35:41 -04:00
parent beab92e359
commit d528c16b0f
18 changed files with 268 additions and 114 deletions

View File

@ -84,7 +84,7 @@ public class CGUtil {
}
try {
return builder.buildCallGraph(new NullProgressMonitor());
return builder.buildCallGraph(roots, new NullProgressMonitor());
} catch (CancelException e) {
return null;
}

View File

@ -7,7 +7,8 @@ Bundle-ClassPath: .,
lib/jericho-html-3.2.jar
Bundle-Activator: com.ibm.wala.cast.js.JavaScriptPlugin
Bundle-Vendor: IBM
Export-Package: com.ibm.wala.cast.js,
Export-Package: .,
com.ibm.wala.cast.js,
com.ibm.wala.cast.js.analysis.typeInference,
com.ibm.wala.cast.js.callgraph.fieldbased,
com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph,

View File

@ -16,6 +16,7 @@ import java.util.Set;
import com.ibm.wala.cast.ipa.callgraph.AstContextInsensitiveSSAContextInterpreter;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FlowGraph;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FlowGraphBuilder;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.AbstractVertexVisitor;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.CallVertex;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.FuncVertex;
@ -25,8 +26,10 @@ import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactor
import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraph;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptConstructTargetSelector;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptConstructTargetSelector.JavaScriptConstructor;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptEntryPoints;
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionDotCallTargetSelector;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
@ -46,6 +49,7 @@ import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterprete
import com.ibm.wala.ipa.callgraph.propagation.cfa.nCFAContextSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
import com.ibm.wala.util.collections.HashSetFactory;
@ -87,6 +91,11 @@ public abstract class FieldBasedCallGraphBuilder {
return result;
}
protected FlowGraph flowGraphFactory() {
FlowGraphBuilder builder = new FlowGraphBuilder(cha, cache);
return builder.buildFlowGraph();
}
/**
* Build a flow graph for the program to be analysed.
*/
@ -95,7 +104,7 @@ public abstract class FieldBasedCallGraphBuilder {
/**
* Main entry point: builds a flow graph, then extracts a call graph and returns it.
*/
public JSCallGraph buildCallGraph(IProgressMonitor monitor) throws CancelException {
public JSCallGraph buildCallGraph(Iterable<Entrypoint> eps, IProgressMonitor monitor) throws CancelException {
long fgBegin, fgEnd, cgBegin, cgEnd;
if(LOG_TIMINGS) fgBegin = System.currentTimeMillis();
@ -108,7 +117,7 @@ public abstract class FieldBasedCallGraphBuilder {
cgBegin = System.currentTimeMillis();
}
JSCallGraph cg = extract(flowGraph, monitor);
JSCallGraph cg = extract(flowGraph, eps, monitor);
if(LOG_TIMINGS) {
cgEnd = System.currentTimeMillis();
@ -122,15 +131,13 @@ public abstract class FieldBasedCallGraphBuilder {
* Extract a call graph from a given flow graph.
*/
@SuppressWarnings("deprecation")
protected JSCallGraph extract(FlowGraph flowgraph, IProgressMonitor monitor) throws CancelException {
protected JSCallGraph extract(FlowGraph flowgraph, Iterable<Entrypoint> eps, IProgressMonitor monitor) throws CancelException {
// set up call graph
final JSCallGraph cg = new JSCallGraph(cha, options, cache);
cg.init();
cg.setInterpreter(new DelegatingSSAContextInterpreter(new AstContextInsensitiveSSAContextInterpreter(options, cache), new DefaultSSAInterpreter(options, cache)));
// set up call edges from fake root to all script nodes
JavaScriptEntryPoints eps = new JavaScriptEntryPoints(cha, cha.getLoader(JavaScriptTypes.jsLoader));
// set up call edges from fake root to all script nodes
AbstractRootMethod fakeRootMethod = (AbstractRootMethod)cg.getFakeRootNode().getMethod();
CGNode fakeRootNode = cg.findOrCreateNode(fakeRootMethod, Everywhere.EVERYWHERE);
for(Iterator<Entrypoint> iter = eps.iterator(); iter.hasNext();) {
@ -145,34 +152,33 @@ public abstract class FieldBasedCallGraphBuilder {
// now add genuine call edges
Set<Pair<CallVertex, FuncVertex>> edges = extractCallGraphEdges(flowgraph, monitor);
for (Pair<CallVertex, FuncVertex> edge : edges) {
CallVertex callVertex = edge.fst;
FuncVertex targetVertex = edge.snd;
IClass kaller = callVertex.getCaller().getIClass();
CGNode caller = cg.findOrCreateNode(kaller.getMethod(AstMethodReference.fnSelector), Everywhere.EVERYWHERE);
CallSiteReference site = callVertex.getSite();
IMethod target = targetSelector.getCalleeTarget(caller, site, targetVertex.getIClass());
boolean isFunctionPrototypeCall = target != null
&& target.getName().toString().startsWith(JavaScriptFunctionDotCallTargetSelector.SYNTHETIC_CALL_METHOD_PREFIX);
if (isFunctionPrototypeCall) {
handleFunctionPrototypeCallInvocation(flowgraph, monitor, cg, callVertex, caller, site, target);
} else {
addEdgeToJSCallGraph(cg, site, target, caller);
}
}
for (Pair<CallVertex, FuncVertex> edge : edges) {
CallVertex callVertex = edge.fst;
FuncVertex targetVertex = edge.snd;
IClass kaller = callVertex.getCaller().getIClass();
CGNode caller = cg.findOrCreateNode(kaller.getMethod(AstMethodReference.fnSelector), Everywhere.EVERYWHERE);
CallSiteReference site = callVertex.getSite();
IMethod target = targetSelector.getCalleeTarget(caller, site, targetVertex.getIClass());
boolean isFunctionPrototypeCall = target != null
&& target.getName().toString().startsWith(JavaScriptFunctionDotCallTargetSelector.SYNTHETIC_CALL_METHOD_PREFIX);
if (isFunctionPrototypeCall) {
handleFunctionPrototypeCallInvocation(flowgraph, monitor, cg, callVertex, caller, site, target);
} else {
addEdgeToJSCallGraph(cg, site, target, caller);
}
}
return cg;
}
private void handleFunctionPrototypeCallInvocation(FlowGraph flowgraph, IProgressMonitor monitor, final JSCallGraph cg,
private boolean handleFunctionPrototypeCallInvocation(FlowGraph flowgraph, IProgressMonitor monitor, final JSCallGraph cg,
CallVertex callVertex, CGNode caller, CallSiteReference site,
IMethod target) throws CancelException {
// use to get 1-level of call string for Function.prototype.call, to
// preserve the precision of the field-based call graph
final nCFAContextSelector functionPrototypeCallSelector = new nCFAContextSelector(1, new ContextInsensitiveSelector());
Context calleeContext = functionPrototypeCallSelector.getCalleeTarget(caller, site, target, null);
addCGEdgeWithContext(cg, site, target, caller, calleeContext);
boolean ret = addCGEdgeWithContext(cg, site, target, caller, calleeContext);
CGNode functionPrototypeCallNode = cg.findOrCreateNode(target, calleeContext);
// need to create nodes for reflective targets of call, and then add them
// as callees of the synthetic method
@ -181,29 +187,36 @@ public abstract class FieldBasedCallGraphBuilder {
CallSiteReference reflectiveCallSite = functionPrototypeCallNode.getIR().iterateCallSites().next();
for (FuncVertex f : reflectiveTargets) {
IMethod reflectiveTgtMethod = targetSelector.getCalleeTarget(functionPrototypeCallNode, reflectiveCallSite, f.getIClass());
addEdgeToJSCallGraph(cg, reflectiveCallSite, reflectiveTgtMethod, functionPrototypeCallNode);
ret |= addEdgeToJSCallGraph(cg, reflectiveCallSite, reflectiveTgtMethod, functionPrototypeCallNode);
}
return ret;
}
private IMethod addEdgeToJSCallGraph(final JSCallGraph cg, CallSiteReference site, IMethod target, CGNode caller)
private boolean addEdgeToJSCallGraph(final JSCallGraph cg, CallSiteReference site, IMethod target, CGNode caller)
throws CancelException {
return addCGEdgeWithContext(cg, site, target, caller, Everywhere.EVERYWHERE);
}
Set<IClass> constructedTypes = HashSetFactory.make();
Everywhere targetContext = Everywhere.EVERYWHERE;
@SuppressWarnings("deprecation")
private IMethod addCGEdgeWithContext(final JSCallGraph cg, CallSiteReference site, IMethod target, CGNode caller,
private boolean addCGEdgeWithContext(final JSCallGraph cg, CallSiteReference site, IMethod target, CGNode caller,
Context targetContext) throws CancelException {
boolean ret = false;
if(target != null) {
CGNode callee = cg.findOrCreateNode(target, targetContext);
// add nodes first, to be on the safe side
cg.addNode(caller); cg.addNode(callee);
cg.addNode(caller);
cg.addNode(callee);
// add callee as successor of caller
cg.addEdge(caller, callee);
// add as site-specific target
caller.addTarget(site, callee);
ret = !cg.getPossibleTargets(caller, site).contains(callee);
if (ret) {
cg.addEdge(caller, callee);
caller.addTarget(site, callee);
}
}
return target;
return ret;
}
/**

View File

@ -53,8 +53,7 @@ public class OptimisticCallgraphBuilder extends FieldBasedCallGraphBuilder {
@Override
public FlowGraph buildFlowGraph(IProgressMonitor monitor) throws CancelException {
FlowGraphBuilder builder = new FlowGraphBuilder(cha, cache);
FlowGraph flowgraph = builder.buildFlowGraph();
FlowGraph flowgraph = flowGraphFactory();
// keep track of which call edges we already know about
Set<Pair<CallVertex, FuncVertex>> knownEdges = HashSetFactory.make();

View File

@ -46,9 +46,8 @@ public class PessimisticCallGraphBuilder extends FieldBasedCallGraphBuilder {
@Override
public FlowGraph buildFlowGraph(IProgressMonitor monitor) {
FlowGraphBuilder builder = new FlowGraphBuilder(cha, cache);
FlowGraph flowgraph = builder.buildFlowGraph();
resolveLocalCalls(flowgraph);
FlowGraph flowgraph = flowGraphFactory();
resolveLocalCalls(flowgraph);
return flowgraph;
}

View File

@ -79,33 +79,42 @@ public class FlowGraphBuilder {
addPrimitives(flowgraph);
for(IClass klass : cha) {
for(IMethod method : klass.getDeclaredMethods()) {
if(method.getDescriptor().equals(AstMethodReference.fnDesc)) {
IR ir = cache.getIR(method);
FlowGraphSSAVisitor visitor = new FlowGraphSSAVisitor(ir, flowgraph);
// first visit normal instructions
SSAInstruction[] normalInstructions = ir.getInstructions();
for(int i=0;i<normalInstructions.length;++i)
if(normalInstructions[i] != null) {
visitor.instructionIndex = i;
normalInstructions[i].visit(visitor);
}
// now visit phis and catches
visitor.instructionIndex = -1;
for(Iterator<? extends SSAInstruction> iter=ir.iteratePhis();iter.hasNext();)
iter.next().visit(visitor);
for(Iterator<SSAInstruction> iter=ir.iterateCatchInstructions();iter.hasNext();)
iter.next().visit(visitor);
}
}
}
visitProgram(flowgraph);
return flowgraph;
}
protected void visitProgram(FlowGraph flowgraph) {
for(IClass klass : cha) {
for(IMethod method : klass.getDeclaredMethods()) {
if(method.getDescriptor().equals(AstMethodReference.fnDesc))
visitFunction(flowgraph, method);
}
}
}
protected void visitFunction(FlowGraph flowgraph, IMethod method) {
{
IR ir = cache.getIR(method);
FlowGraphSSAVisitor visitor = new FlowGraphSSAVisitor(ir, flowgraph);
// first visit normal instructions
SSAInstruction[] normalInstructions = ir.getInstructions();
for(int i=0;i<normalInstructions.length;++i)
if(normalInstructions[i] != null) {
visitor.instructionIndex = i;
normalInstructions[i].visit(visitor);
}
// now visit phis and catches
visitor.instructionIndex = -1;
for(Iterator<? extends SSAInstruction> iter=ir.iteratePhis();iter.hasNext();)
iter.next().visit(visitor);
for(Iterator<SSAInstruction> iter=ir.iterateCatchInstructions();iter.hasNext();)
iter.next().visit(visitor);
}
}
// primitive functions that are treated specially
private static String[] primitiveFunctions = { "Object", "Function", "Array", "String", "Number", "RegExp" };

View File

@ -106,5 +106,4 @@ public class JSCallGraph extends AstCallGraph {
}
}
}

View File

@ -117,7 +117,7 @@ public class JSCallGraphUtil extends com.ibm.wala.cast.ipa.callgraph.CAstCallGra
return ClassHierarchy.make(scope, loaders, JavaScriptLoader.JS);
}
public static Iterable<Entrypoint> makeScriptRoots(IClassHierarchy cha) {
public static JavaScriptEntryPoints makeScriptRoots(IClassHierarchy cha) {
return new JavaScriptEntryPoints(cha, cha.getLoader(JavaScriptTypes.jsLoader));
}

View File

@ -55,22 +55,28 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
private final Map<Object, IMethod> constructors = HashMapFactory.make();
class JavaScriptConstructor extends JavaScriptSummarizedFunction {
public static class JavaScriptConstructor extends JavaScriptSummarizedFunction {
private final String toStringExtra;
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, String toStringExtra) {
private final IClass constructorForType;
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType, String toStringExtra) {
super(ref, summary, declaringClass);
this.toStringExtra = toStringExtra;
this.constructorForType = constructorForType;
}
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass) {
this(ref, summary, declaringClass, "");
private JavaScriptConstructor(MethodReference ref, MethodSummary summary, IClass declaringClass, IClass constructorForType) {
this(ref, summary, declaringClass, constructorForType, "");
}
@Override
public String toString() {
return "<ctor for " + getReference().getDeclaringClass() + toStringExtra + ">";
}
public IClass constructedType() {
return constructorForType;
}
}
public JavaScriptConstructTargetSelector(IClassHierarchy cha, MethodTargetSelector base) {
@ -106,7 +112,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(9, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cls);
}
private IMethod makeUnaryValueConstructor(IClass cls) {
@ -131,7 +137,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(7, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cls);
}
private IMethod makeValueConstructor(IClass cls, int nargs, Object value) {
@ -171,7 +177,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(6, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Object));
}
private IMethod makeUnaryObjectConstructor(IClass cls) {
@ -182,7 +188,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
S.addStatement(insts.ReturnInstruction(2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Object));
}
private IMethod makeObjectConstructor(IClass cls, int nargs) {
@ -234,7 +240,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(7, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Array));
}
private IMethod makeArrayContentsConstructor(IClass cls, int nargs) {
@ -270,7 +276,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(vn, new ConstantValue("__proto__"));
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Array));
}
private IMethod makeArrayConstructor(IClass cls, int nargs) {
@ -291,7 +297,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
S.addStatement(insts.ReturnInstruction(2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.String));
}
private IMethod makeUnaryStringCall(IClass cls) {
@ -308,7 +314,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
S.addStatement(insts.ReturnInstruction(5, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.String));
}
private IMethod makeStringCall(IClass cls, int nargs) {
@ -331,7 +337,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
S.addStatement(insts.ReturnInstruction(2, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Number));
}
private IMethod makeUnaryNumberCall(IClass cls) {
@ -348,7 +354,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
S.addStatement(insts.ReturnInstruction(5, false));
S.getNextProgramCounter();
return new JavaScriptConstructor(ref, S, cls);
return new JavaScriptConstructor(ref, S, cls, cha.lookupClass(JavaScriptTypes.Number));
}
private IMethod makeNumberCall(IClass cls, int nargs) {
@ -395,9 +401,9 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(8, new ConstantValue("__proto__"));
if (receiver != cls)
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, "(" + cls.getReference().getName() + ")"));
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, cls, "(" + cls.getReference().getName() + ")"));
else
return record(tableKey, new JavaScriptConstructor(ref, S, receiver));
return record(tableKey, new JavaScriptConstructor(ref, S, receiver, cls));
}
private int ctorCount = 0;
@ -409,11 +415,11 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
return makeFunctionConstructor(cls, cls);
} else if (nargs == 1) {
if (ST.isStringConstant(callStmt.getUse(1))) {
TypeReference ref = TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName((String) ST
TypeReference ref = TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName(ST
.getStringValue(callStmt.getUse(1))));
if (DEBUG) {
System.err.println(("ctor type name is " + (String) ST.getStringValue(callStmt.getUse(1))));
System.err.println(("ctor type name is " + ST.getStringValue(callStmt.getUse(1))));
}
IClass cls2 = cha.lookupClass(ref);
@ -511,7 +517,7 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector {
//S.addConstant(nargs + 9, new ConstantValue("__proto__"));
return record(key, new JavaScriptConstructor(ref, S, cls));
return record(key, new JavaScriptConstructor(ref, S, cls, cls));
}
private IMethod findOrCreateConstructorMethod(IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass receiver, int nargs) {

View File

@ -103,4 +103,16 @@ public abstract class ScriptEntryPoints implements Iterable<Entrypoint> {
return ES.iterator();
}
}
public Entrypoint make(String scriptName) {
IClass cls = cha.lookupClass(TypeReference.findOrCreate(scriptType.getClassLoader().getReference(), scriptName));
assert cls != null && cha.isSubclassOf(cls, scriptType) && !cls.isAbstract();
for (IMethod method : cls.getDeclaredMethods()) {
if (keep(method)) {
return new ScriptEntryPoint(method);
}
}
assert false;
return null;
}
}

View File

@ -1092,6 +1092,8 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
private final int[] instructionToBlockMap;
private final int[] pcMap;
private final String functionName;
private final SymbolTable symtab;
@ -1149,7 +1151,8 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
this.symtab = symtab;
functionName = n.getName();
instructionToBlockMap = new int[liveBlocks.size()];
pcMap = hasDeadBlocks? new int[ icfg.currentInstruction ]: null;
final Map<PreBasicBlock, Collection<PreBasicBlock>> normalEdges =
hasDeadBlocks? HashMapFactory.<PreBasicBlock,Collection<PreBasicBlock>>make() : null;
final Map<PreBasicBlock, Collection<PreBasicBlock>> exceptionalEdges =
@ -1179,6 +1182,14 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
PreBasicBlock block = blocks.get(i);
block.setGraphNodeId(-1);
if (liveBlocks.contains(block)) {
if (hasDeadBlocks) {
int offset = 0;
for(int oldPC = block.getFirstInstructionIndex();
offset < block.instructions().size();
oldPC++, offset++) {
pcMap[instruction + offset] = oldPC;
}
}
if (block.getFirstInstructionIndex() >= 0) {
block.setFirstIndex(instruction);
block.setLastIndex((instruction += block.instructions().size()) - 1);
@ -1277,12 +1288,12 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
@Override
public int getProgramCounter(int index) {
return index;
return pcMap == null? index: pcMap[index];
}
@Override
public String toString() {
SSAInstruction[] insts = (SSAInstruction[]) getInstructions();
SSAInstruction[] insts = getInstructions();
StringBuffer s = new StringBuffer("CAst CFG of " + functionName);
int params[] = symtab.getParameterValueNumbers();
for (int i = 0; i < params.length; i++)
@ -1290,7 +1301,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
s.append("\n");
for (int i = 0; i < getNumberOfNodes(); i++) {
PreBasicBlock bb = (PreBasicBlock) getNode(i);
PreBasicBlock bb = getNode(i);
s.append(bb).append("\n");
for (Iterator ss = getSuccNodes(bb); ss.hasNext();)
@ -1843,12 +1854,12 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
@Override
public boolean isLexicallyScoped(Symbol s) {
return ((AbstractScope) getEntityScope()).isLexicallyScoped(s);
return getEntityScope().isLexicallyScoped(s);
}
@Override
public CAstEntity getEntity() {
return ((AbstractScope) getEntityScope()).getEntity();
return getEntityScope().getEntity();
}
@Override

View File

@ -28,7 +28,7 @@
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.ibm.wala.ide.jsdt.tests"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -XX:MaxPermSize=512m -Xmx2048m -Xdock:icon=../Resources/Eclipse.icns -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -XX:MaxPermSize=512m -Xmx2048m -ea -Xdock:icon=../Resources/Eclipse.icns -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
<booleanAttribute key="run_in_ui_thread" value="true"/>

View File

@ -0,0 +1,25 @@
package com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.functions.Function;
public class FilteredFlowGraphBuilder extends FlowGraphBuilder {
private final Function<IMethod, Boolean> filter;
public FilteredFlowGraphBuilder(IClassHierarchy cha, AnalysisCache cache, Function<IMethod, Boolean> filter) {
super(cha, cache);
this.filter = filter;
}
@Override
protected void visitFunction(FlowGraph flowgraph, IMethod method) {
if (filter.apply(method)) {
super.visitFunction(flowgraph, method);
}
}
}

View File

@ -12,6 +12,7 @@ package com.ibm.wala.cast.js.client;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
@ -20,6 +21,9 @@ import com.ibm.wala.cast.ipa.callgraph.CAstAnalysisScope;
import com.ibm.wala.cast.ir.ssa.AstIRFactory;
import com.ibm.wala.cast.js.callgraph.fieldbased.FieldBasedCallGraphBuilder;
import com.ibm.wala.cast.js.callgraph.fieldbased.PessimisticCallGraphBuilder;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FilteredFlowGraphBuilder;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FlowGraph;
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FlowGraphBuilder;
import com.ibm.wala.cast.js.client.impl.ZeroCFABuilderFactory;
import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil;
@ -27,7 +31,9 @@ import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.loader.JavaScriptLoaderFactory;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.loader.AstMethod;
import com.ibm.wala.classLoader.ClassLoaderFactory;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ide.client.EclipseProjectSourceAnalysisEngine;
import com.ibm.wala.ide.util.JavaScriptEclipseProjectPath;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
@ -41,6 +47,8 @@ import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.NullProgressMonitor;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.functions.Function;
public class EclipseJavaScriptAnalysisEngine extends EclipseProjectSourceAnalysisEngine<IJavaScriptProject> {
@ -97,8 +105,45 @@ public class EclipseJavaScriptAnalysisEngine extends EclipseProjectSourceAnalysi
}
public CallGraph getFieldBasedCallGraph() throws CancelException {
Iterable<Entrypoint> roots = JSCallGraphUtil.makeScriptRoots(getClassHierarchy());
FieldBasedCallGraphBuilder builder = new PessimisticCallGraphBuilder(getClassHierarchy(), getDefaultOptions(roots), makeDefaultCache());
return builder.buildCallGraph(new NullProgressMonitor());
return getFieldBasedCallGraph(JSCallGraphUtil.makeScriptRoots(getClassHierarchy()));
}
public CallGraph getFieldBasedCallGraph(String scriptName) throws CancelException {
Set<Entrypoint> eps= HashSetFactory.make();
eps.add(JSCallGraphUtil.makeScriptRoots(getClassHierarchy()).make(scriptName));
eps.add(JSCallGraphUtil.makeScriptRoots(getClassHierarchy()).make("Lprologue.js"));
return getFieldBasedCallGraph(eps);
}
private String getScriptName(AstMethod m) {
String fileName = m.getSourcePosition().getURL().getFile();
return fileName.substring(fileName.lastIndexOf('/') + 1);
}
protected CallGraph getFieldBasedCallGraph(Iterable<Entrypoint> roots) throws CancelException {
final Set<String> scripts = HashSetFactory.make();
for(Entrypoint e : roots) {
String scriptName = getScriptName(((AstMethod)e.getMethod()));
scripts.add(scriptName);
}
FieldBasedCallGraphBuilder builder = new PessimisticCallGraphBuilder(getClassHierarchy(), getDefaultOptions(roots), makeDefaultCache()) {
@Override
protected FlowGraph flowGraphFactory() {
FlowGraphBuilder b = new FilteredFlowGraphBuilder(cha, cache, new Function<IMethod, Boolean>() {
@Override
public Boolean apply(IMethod object) {
if (object instanceof AstMethod) {
return scripts.contains(getScriptName((AstMethod)object));
} else {
return true;
}
}
});
return b.buildFlowGraph();
}
};
return builder.buildCallGraph(roots, new NullProgressMonitor());
}
}

View File

@ -2,19 +2,25 @@ package com.ibm.wala.cast.js.client;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import com.ibm.wala.cast.ipa.callgraph.CAstAnalysisScope;
import com.ibm.wala.cast.js.html.WebPageLoaderFactory;
import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
import com.ibm.wala.classLoader.ClassLoaderFactory;
import com.ibm.wala.ide.util.EclipseWebProjectPath;
import com.ibm.wala.ide.util.JavaScriptEclipseProjectPath;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.SetOfClasses;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.collections.HashSetFactory;
public class EclipseWebAnalysisEngine extends EclipseJavaScriptAnalysisEngine {
@ -37,4 +43,13 @@ public class EclipseWebAnalysisEngine extends EclipseJavaScriptAnalysisEngine {
return new EclipseWebProjectPath(project);
}
@Override
public CallGraph getFieldBasedCallGraph(String scriptName) throws CancelException {
Set<Entrypoint> eps= HashSetFactory.make();
eps.add(JSCallGraphUtil.makeScriptRoots(getClassHierarchy()).make(scriptName));
eps.add(JSCallGraphUtil.makeScriptRoots(getClassHierarchy()).make("Lpreamble.js"));
eps.add(JSCallGraphUtil.makeScriptRoots(getClassHierarchy()).make("Lprologue.js"));
return getFieldBasedCallGraph(eps);
}
}

View File

@ -1,5 +1,6 @@
package com.ibm.wala.ide.util;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
@ -12,15 +13,21 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.Error;
import com.ibm.wala.cast.js.JavaScriptPlugin;
import com.ibm.wala.cast.js.html.MappedSourceModule;
import com.ibm.wala.cast.js.html.WebUtil;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.classLoader.FileModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.SourceFileModule;
import com.ibm.wala.ide.classloader.EclipseSourceDirectoryTreeModule;
import com.ibm.wala.util.collections.MapUtil;
import com.ibm.wala.util.io.FileProvider;
public class EclipseWebProjectPath extends JavaScriptEclipseProjectPath {
private boolean addedPreamble;
public EclipseWebProjectPath(IJavaScriptProject p) throws IOException, CoreException {
super(p);
}
@ -36,6 +43,11 @@ public class EclipseWebProjectPath extends JavaScriptEclipseProjectPath {
try {
scripts = WebUtil.extractScriptFromHTML(new URL(urlString)).fst;
s.addAll(scripts);
if (! addedPreamble) {
File preamble = getProlgueFile("preamble.js");
s.add(new SourceFileModule(preamble, "preamble.js", null));
addedPreamble = true;
}
} catch (MalformedURLException e1) {
assert false : "internal error constructing URL " + urlString;
} catch (Error e1) {

View File

@ -10,13 +10,10 @@
*******************************************************************************/
package com.ibm.wala.ide.util;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
@ -25,21 +22,28 @@ import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.Error;
import com.ibm.wala.cast.js.html.MappedSourceModule;
import com.ibm.wala.cast.js.html.WebUtil;
import com.ibm.wala.cast.js.JavaScriptPlugin;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.loader.CAstAbstractLoader;
import com.ibm.wala.classLoader.FileModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.SourceModule;
import com.ibm.wala.classLoader.SourceURLModule;
import com.ibm.wala.ide.classloader.EclipseSourceDirectoryTreeModule;
import com.ibm.wala.classLoader.SourceFileModule;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.util.collections.MapUtil;
import com.ibm.wala.util.io.FileProvider;
public class JavaScriptEclipseProjectPath extends EclipseProjectPath<IIncludePathEntry, IJavaScriptProject> {
protected File getProlgueFile(String file) {
try {
FileProvider fileProvider = new EclipseFileProvider(JavaScriptPlugin.getDefault());
JavaScriptLoader.addBootstrapFile(file);
return fileProvider.getFile("dat/" + file, getClass().getClassLoader());
} catch (IOException e) {
assert false : "cannot find " + file;
return null;
}
}
public enum JSLoader implements ILoader {
JAVASCRIPT(JavaScriptTypes.jsLoader);
@ -58,6 +62,10 @@ public class JavaScriptEclipseProjectPath extends EclipseProjectPath<IIncludePat
protected JavaScriptEclipseProjectPath(IJavaScriptProject p) throws IOException,
CoreException {
super(p.getProject(), AnalysisScopeType.SOURCE_FOR_PROJ_AND_LINKED_PROJS);
List<Module> s = MapUtil.findOrCreateList(modules, JSLoader.JAVASCRIPT);
File preamble = getProlgueFile("prologue.js");
s.add(new SourceFileModule(preamble, "prologue.js", null));
}
public static JavaScriptEclipseProjectPath make(IJavaScriptProject p) throws IOException, CoreException {

View File

@ -198,11 +198,11 @@ public class EclipseFileProvider extends FileProvider {
if (p == null) {
return getFileFromClassLoader(fileName, loader);
} else {
File f = getFileFromPlugin(p, fileName);
if (f == null) {
f = getFileFromClassLoader(fileName, loader);
}
return f;
try {
return getFileFromPlugin(p, fileName);
} catch (IOException e) {
return getFileFromClassLoader(fileName, loader);
}
}
}