WALA icon indicating copy to clipboard operation
WALA copied to clipboard

How can I get call graph of multiple js files?

Open SherlockNovitch opened this issue 1 year ago • 1 comments

The wiki only has single-file api usage examples. I try to use the public static CallGraph makeScriptCG(SourceModule[] scripts, CGBuilderType builderType, IRFactory<IMethod> irFactory) api for multi-file call graph generation.

The complete code is as follows:

    public static SourceURLModule getSourceURLModule(String path) {
        try {
            return new SourceURLModule(JSCallGraphBuilderUtil.getURLforFile("", String.valueOf(path)
                    , JSCallGraphBuilderUtil.class.getClassLoader()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void generateCallGraph(String filePath) throws WalaException, IOException, CancelException {
        Path path = Paths.get(filePath);
        
        JSCallGraphUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory());
        
        LinkedList<SourceURLModule> sourceURLModules = new LinkedList<>();
        Files.walk(path).filter(aPath -> aPath.toString().endsWith(".js"))
                .forEach(apath -> sourceURLModules.add(getSourceURLModule(String.valueOf(apath))));

        CallGraph cg = JSCallGraphBuilderUtil.makeScriptCG(sourceURLModules.toArray(new SourceURLModule[0]),
                JSCallGraphBuilderUtil.CGBuilderType.ZERO_ONE_CFA,
                AstIRFactory.makeDefaultFactory());

//        CallGraph cg = JSCallGraphBuilderUtil.makeScriptCG(path.getParent().toString(), path.getFileName().toString());
        System.out.println(CallGraphStats.getStats(cg));
        System.out.println(cg);
    }

The output results only contain the edge between the fake root and the file node under the filePath folder. No other information is output, which is very different from the output of a single file.

Call graph stats:
  Nodes: 14
  Edges: 13
  Methods: 14
  Bytecode Bytes: 0

Node: synthetic < JavaScriptLoader, LFakeRoot, fakeRootMethod()V > Context: Everywhere
 - JSCall@1
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/apply.js> Context: Everywhere
 - JSCall@3
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/bind.js> Context: Everywhere
 - JSCall@5
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/call.js> Context: Everywhere
 - JSCall@7
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/callback.js> Context: Everywhere
 - JSCall@9
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/closure.js> Context: Everywhere
 - JSCall@11
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/dynamic_property.js> Context: Everywhere
 - JSCall@13
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/eval.js> Context: Everywhere
 - JSCall@15
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/helloworld.js> Context: Everywhere
 - JSCall@17
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/iife.js> Context: Everywhere
 - JSCall@19
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/prototype.js> Context: Everywhere
 - JSCall@21
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/prototype_chain.js> Context: Everywhere
 - JSCall@23
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/unknown_property.js> Context: Everywhere
 - JSCall@25
     -> Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/with.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/apply.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/bind.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/call.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/callback.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/closure.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/dynamic_property.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/eval.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/helloworld.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/iife.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/prototype.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/prototype_chain.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/unknown_property.js> Context: Everywhere

Node: <Code body of function L/D:/Project/JavaScriptCGUtil/src/test/js-benchmark1/with.js> Context: Everywhere

How can i get correct call graph of multiplejs files?

SherlockNovitch avatar Jan 23 '24 08:01 SherlockNovitch

Sorry this is not better documented. I was looking at this code to create Modules when there is a single file:

https://github.com/wala/WALA/blob/130b92c444c206572682f2e007cca64670e3b03e/cast/js/src/main/java/com/ibm/wala/cast/js/util/JSCallGraphBuilderUtil.java#L143-L143

It also adds a Module for the prologue by calling this function:

https://github.com/wala/WALA/blob/130b92c444c206572682f2e007cca64670e3b03e/cast/js/src/main/java/com/ibm/wala/cast/js/ipa/callgraph/JSCallGraphUtil.java#L347-L347

Does that help to fix your case?

msridhar avatar Feb 01 '24 00:02 msridhar