package dk.brics.jspointers; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PushbackReader; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import dk.brics.jscontrolflow.Function; import dk.brics.jscontrolflow.ast2cfg.Ast2Cfg; import dk.brics.jscontrolflow.ast2cfg.AstBinding; import dk.brics.jscontrolflow.ast2cfg.IAstBinding; import dk.brics.jsparser.SemicolonInsertingLexer; import dk.brics.jsparser.lexer.LexerException; import dk.brics.jsparser.node.ABody; import dk.brics.jsparser.node.Start; import dk.brics.jsparser.parser.Parser; import dk.brics.jsparser.parser.ParserException; import dk.brics.jspointers.analysis.JSAnalysis; import dk.brics.jspointers.analysis.ObjectSensitiveInvocation; import dk.brics.jspointers.dataflow.DataflowGraph; import dk.brics.jspointers.lattice.keys.Key; import dk.brics.jspointers.lattice.values.Value; import dk.brics.jspointers.solver.AnalysisResult; import dk.brics.jspointers.solver.Solver; public class Main { private static class Timer { private long startTime; private long lastCheckpoint; public void start() { this.startTime = System.currentTimeMillis(); this.lastCheckpoint = startTime; } public int checkpoint() { long time = System.currentTimeMillis(); int delta = (int)(time - this.lastCheckpoint); this.lastCheckpoint = time; return delta; } public int totalTime() { return (int)(System.currentTimeMillis() - startTime); } } private static String getFunctionName(Function func, boolean main) { if (main) return "<main>"; // else if (func.getName() != null) // return func.getName(); else return func.toString(); // return removePathInfo(func.getSourceLocation().getFileName()) + "-" + func.getSourceLocation().getLineNumber(); } private static ABody parse(File file) throws IOException { try { Start start = new Parser(new SemicolonInsertingLexer(new PushbackReader(new FileReader(file)))).parse(); return start.getBody(); } catch (ParserException ex) { throw new RuntimeException(ex); } catch (LexerException ex) { throw new RuntimeException(ex); } } private static InputFile loadFile(File file) throws IOException { ABody ast = parse(file); AstBinding binding = new AstBinding(); Function func = Ast2Cfg.convert(ast, binding, file); return new InputFile(file, ast, func, binding); } static class InputFile { File file; ABody ast; Function cfg; AstBinding binding; public InputFile(File file, ABody ast, Function cfg, AstBinding binding) { this.file = file; this.ast = ast; this.cfg = cfg; this.binding = binding; } } public static void main(String[] args) throws IOException { new File("output/flowgraphs").mkdir(); new File("output/dataflows").mkdir(); Timer timer = new Timer(); timer.start(); List<String> harnessfiles = Arrays.asList( "../jsdatalog/harness/Array.js", "../jsdatalog/harness/Boolean.js", "../jsdatalog/harness/Date.js", "../jsdatalog/harness/Math.js", "../jsdatalog/harness/Number.js", "../jsdatalog/harness/String.js", "../jsdatalog/harness/RegExp.js", "../jsdatalog/harness/Error.js", "../jsdatalog/harness/JSON.js"); // List<String> harnessfiles = Collections.emptyList(); // List<String> inputfiles = Arrays.asList("../jsdatalog/test/html/htmltest.html"); List<String> inputfiles = Arrays.asList("../TAJS/test/google/delta-blue.js"); // List<String> inputfiles = Arrays.asList("../jscontrolflow/testcases/switch1.js"); // List<String> inputfiles = Arrays.asList("../TAJS/benchmark/chrome/anotherworld.html"); Set<Function> harnessToplevels = new HashSet<Function>(); for (String harnessFile : harnessfiles) { harnessToplevels.add(load(harnessFile)); } Set<Function> usercode = new HashSet<Function>(); for (String file : inputfiles) { usercode.add(load(file)); } int flowgraphTime = timer.checkpoint(); final DataflowGraph dataflow = DataflowCreator.convert(usercode, harnessToplevels); dataflow.getEntryFunctions().addAll(usercode); dataflow.getEntryFunctions().addAll(harnessToplevels); int dataflowTime = timer.checkpoint(); // print .dot graph // for (Function function : flowgraph.getFlowGraph().getFunctions()) { // if (flowgraph.getHarnessFunctions().contains(function)) // continue; // String name = getFunctionName(function, flowgraph.getFlowGraph().getMain() == function); // DataflowToDot.print(dataflow.getFunctionFlownodes().getView(function), new File("output/dataflows/" + name + ".dot")); // } // AnalysisResult<Key,Set<Value>> result = Solver.solve( // new JSAnalysis(dataflow, new CallsiteSensitiveInvocation(1))); AnalysisResult<Key,Set<Value>> result = Solver.solve( new JSAnalysis(dataflow, new ObjectSensitiveInvocation(20))); int analysisTime = timer.checkpoint(); int totalTime = timer.totalTime(); System.out.println("Done!"); // annotate .js file System.out.println("Printing annotated JavaScript file"); for (String file : inputfiles) { String name = removePathInfo(file); // AnnotateJs.annotateJavaScriptFile(file, "output/" + name, dataflow, result); } // print type info // PrintTypeInfo.printTypeInfo(dataflow, result); System.out.println("Time spent:"); System.out.printf("Creating flow graph %s\n", formatTime(flowgraphTime)); System.out.printf("Creating dataflow graph %s\n", formatTime(dataflowTime)); System.out.printf("Analysis %s\n", formatTime(analysisTime)); System.out.printf("Total %s\n", formatTime(totalTime)); } private static String formatTime(int time) { return (time / 1000) + "." + (time % 1000) / 100 + " seconds"; } public static String removePathInfo(String filename) { return new File(filename).getName(); } }