static Graph <Function> BuildFunctionCallGraph(Microsoft.Armada.Program program) { Graph <Function> functionCallGraph = new Graph <Function>(); FunctionCallFinder callFinder = new FunctionCallFinder(); foreach (var module in program.Modules()) { foreach (var decl in module.TopLevelDecls) { if (decl is ClassDecl) { var c = (ClassDecl)decl; foreach (var member in c.Members) { if (member is Function) { var f = (Function)member; List <Function> calls = new List <Function>(); foreach (var e in f.Reads) { if (e != null && e.E != null) { callFinder.Visit(e.E, calls); } } foreach (var e in f.Req) { if (e != null) { callFinder.Visit(e, calls); } } foreach (var e in f.Ens) { if (e != null) { callFinder.Visit(e, calls); } } if (f.Body != null) { callFinder.Visit(f.Body, calls); } foreach (var callee in calls) { functionCallGraph.AddEdge(f, callee); } } } } } } return(functionCallGraph); }
/// <summary> /// Prints the program's function call graph in a format suitable for consumption in other tools /// </summary> public static void PrintFunctionCallGraph(Microsoft.Armada.Program program) { var functionCallGraph = BuildFunctionCallGraph(program); foreach (var vertex in functionCallGraph.GetVertices()) { var func = vertex.N; Console.Write("{0},{1}=", func.CompileName, func.EnclosingClass.Module.CompileName); foreach (var callee in vertex.Successors) { Console.Write("{0} ", callee.N.CompileName); } Console.Write("\n"); } }
/// <summary> /// Generate a C# program from the Dafny program and, if "invokeCompiler" is "true", invoke /// the C# compiler to compile it. /// </summary> public static bool CompileDafnyProgram(Microsoft.Armada.Program dafnyProgram, string dafnyProgramName, ReadOnlyCollection <string> otherFileNames, bool invokeCompiler, TextWriter outputWriter = null) { Contract.Requires(dafnyProgram != null); Contract.Assert(dafnyProgramName != null); Console.WriteLine("Running CompileDafnyProgram : {0}", dafnyProgramName); Console.WriteLine("Number of modules = {0}", dafnyProgram.CompileModules.Count); if (outputWriter == null) { outputWriter = Console.Out; } // Compile the Dafny program into a string that contains the target program var oldErrorCount = dafnyProgram.reporter.Count(ErrorLevel.Error); Microsoft.Armada.Compiler compiler; switch (ArmadaOptions.O.CompileTarget) { case ArmadaOptions.CompilationTarget.Clight: default: compiler = new Microsoft.Armada.ClightTsoCompiler(dafnyProgram.reporter, otherFileNames); break; } Method mainMethod; var hasMain = compiler.HasMain(dafnyProgram, out mainMethod); string targetProgramText; var otherFiles = new Dictionary <string, string>(); { var fileQueue = new Queue <FileTargetWriter>(); using (var wr = new TargetWriter(0)) { compiler.Compile(dafnyProgram, wr); var sw = new StringWriter(); wr.Collect(sw, fileQueue); targetProgramText = sw.ToString(); } while (fileQueue.Count > 0) { var wr = fileQueue.Dequeue(); var sw = new StringWriter(); wr.Collect(sw, fileQueue); otherFiles.Add(wr.Filename, sw.ToString()); } } string baseName = Path.GetFileNameWithoutExtension(dafnyProgramName); string callToMain = null; if (hasMain) { using (var wr = new TargetWriter(0)) { compiler.EmitCallToMain(mainMethod, wr); callToMain = wr.ToString(); // assume there aren't multiple files just to call main } } bool completeProgram = dafnyProgram.reporter.Count(ErrorLevel.Error) == oldErrorCount; // blurt out the code to a file, if requested, or if other files were specified for the C# command line. string targetFilename = null; if (ArmadaOptions.O.SpillTargetCode > 0 || otherFileNames.Count > 0 || (invokeCompiler && !compiler.SupportsInMemoryCompilation)) { var p = callToMain == null ? targetProgramText : targetProgramText + callToMain; targetFilename = WriteDafnyProgramToFiles(dafnyProgramName, p, completeProgram, otherFiles, outputWriter); } // compile the program into an assembly if (!completeProgram || !invokeCompiler) { // don't compile // Caller interprets this as success/fail and returns an error if false, // but we didn't actually hit an error, we just didn't invoke the compiler return(true); } // compile the program into an assembly object compilationResult; var compiledCorrectly = compiler.CompileTargetProgram(dafnyProgramName, targetProgramText, callToMain, targetFilename, otherFileNames, hasMain, hasMain && ArmadaOptions.O.RunAfterCompile, outputWriter, out compilationResult); if (compiledCorrectly && ArmadaOptions.O.RunAfterCompile) { if (hasMain) { if (ArmadaOptions.O.CompileVerbose) { outputWriter.WriteLine("Running..."); outputWriter.WriteLine(); } compiledCorrectly = compiler.RunTargetProgram(dafnyProgramName, targetProgramText, callToMain, targetFilename, otherFileNames, compilationResult, outputWriter); } else { // make sure to give some feedback to the user if (ArmadaOptions.O.CompileVerbose) { outputWriter.WriteLine("Program compiled successfully"); } } } return(compiledCorrectly); }
/// <summary> /// Compute various interesting statistics about the Dafny program /// </summary> public static void PrintStats(Microsoft.Armada.Program program) { SortedDictionary <string, ulong> stats = new SortedDictionary <string, ulong>(); foreach (var module in program.Modules()) { IncrementStat(stats, "Modules"); UpdateMax(stats, "Module height (max)", (ulong)module.Height); ulong num_scc = (ulong)module.CallGraph.TopologicallySortedComponents().Count; UpdateMax(stats, "Call graph width (max)", num_scc); foreach (var decl in module.TopLevelDecls) { if (decl is DatatypeDecl) { IncrementStat(stats, "Datatypes"); } else if (decl is ClassDecl) { var c = (ClassDecl)decl; if (c.Name != "_default") { IncrementStat(stats, "Classes"); } foreach (var member in c.Members) { if (member is Function) { IncrementStat(stats, "Functions (total)"); var f = (Function)member; if (f.IsRecursive) { IncrementStat(stats, "Functions recursive"); } } else if (member is Method) { IncrementStat(stats, "Methods (total)"); var method = (Method)member; if (method.IsRecursive) { IncrementStat(stats, "Methods recursive"); } if (method.IsGhost) { IncrementStat(stats, "Methods ghost"); } } } } } } // Print out the results, with some nice formatting Console.WriteLine(""); Console.WriteLine("Statistics"); Console.WriteLine("----------"); int max_key_length = 0; foreach (var key in stats.Keys) { if (key.Length > max_key_length) { max_key_length = key.Length; } } foreach (var keypair in stats) { string keyString = keypair.Key.PadRight(max_key_length + 2); Console.WriteLine("{0} {1,4}", keyString, keypair.Value); } }