/// <summary> /// Builds flowgraph. Prepares list of basic blocks to translate. /// </summary> public static ControlFlowGraph Build(IClrMethodBody body) { #if DEBUG DebugHooks.LogInfo("CFG Builder started"); #endif var graph = body.ControlFlowGraph; if (graph != null) { #if DEBUG body.VisualizeGraph(graph.Entry, false); #endif return(graph); } var builder = new GraphBuilder(body, false) { IsVoidCallEnd = true }; var entry = builder.Build(); if (entry == null) { throw new ILTranslatorException("Unable to build flowgraph"); } #if DEBUG body.VisualizeGraph(entry, false); #endif //Prepares list of basic blocks in the same order as they are located in code. var blocks = new NodeList(); Node prevNode = null; foreach (var instruction in body.Code) { var bb = instruction.BasicBlock; //if (bb == null) // throw new InvalidOperationException(); if (bb == null) { continue; } if (prevNode == bb) { continue; } blocks.Add(bb); prevNode = bb; } graph = new ControlFlowGraph { Entry = entry, Blocks = blocks }; body.ControlFlowGraph = graph; return(graph); }
/// <summary> /// Concatenates code of all basic blocks in order of basic blocks layout. /// Prepares output code (instruction list). /// </summary> public static TranslatorResult Emit(TranslationContext context, string debugFile) { #if DEBUG DebugHooks.LogInfo("ConcatBlocks started"); #endif var begin = Begin(context, debugFile); var provider = context.Provider; var branches = new List <Branch>(); var output = context.Code.New(); output.Emit(begin); foreach (var bb in context.Body.ControlFlowGraph.Blocks) { //UNCOMMENT TO CHECK STACK BALANCE //Checks.CheckStackBalance(bb); bb.TranslatedEntryIndex = output.Count; var il = bb.TranslatedCode; var last = il[il.Count - 1]; if (last.IsBranchOrSwitch()) { branches.Add(new Branch(last, bb)); } TranslatorExtensions.FixSelfCycle(context.New(bb)); output.Emit(il); bb.TranslatedExitIndex = output.Count - 1; } var end = (provider.End() ?? Enumerable.Empty <IInstruction>()).ToArray(); output.Emit(end); #if DEBUG DebugHooks.LogInfo("ConcatBlocks succeeded. CodeSize = {0}", output.Count); #endif return(new TranslatorResult { Begin = begin, End = end, Output = output, Branches = branches }); }
/// <summary> /// Resolves branch instructions. /// </summary> public static void Resolve(IList <Branch> branches, ICodeProvider provider) { #if DEBUG DebugHooks.LogInfo("ResolveBranches started"); #endif for (int i = 0; i < branches.Count; ++i) { var br = branches[i].Source; var bb = branches[i].TargetBlock; if (br.IsSwitch) { var e = bb.FirstOut; int deftarget = e.To.TranslatedEntryIndex; var targets = new List <int>(); for (e = e.NextOut; e != null; e = e.NextOut) { targets.Add(e.To.TranslatedEntryIndex); } provider.SetCaseTargets(br, targets.ToArray(), deftarget); } else if (br.IsConditionalBranch) { var e = bb.TrueEdge; provider.SetBranchTarget(br, e.To.TranslatedEntryIndex); } else //unconditional branch { #if DEBUG if (!br.IsUnconditionalBranch) //sanity check { throw new ILTranslatorException("Invalid branch instruction"); } #endif var e = bb.FirstOut; if (e.To != bb) //avoid cycle! { provider.SetBranchTarget(br, e.To.TranslatedEntryIndex); } else { provider.SetBranchTarget(br, bb.TranslatedExitIndex - 1); } } } #if DEBUG DebugHooks.LogInfo("ResolveBranches succeeded"); #endif }
private static void Analyze(Context context) { #if DEBUG DebugHooks.LogInfo("Flowgraph analysis started"); #endif foreach (var bb in context.Body.ControlFlowGraph.Blocks) { AnalyzeBlock(bb, context); } foreach (var bb in context.Body.ControlFlowGraph.Blocks) { bb.Stack = null; } #if DEBUG DebugHooks.LogInfo("Flowgraph analysis succeeded"); #endif }
public static void Write(IEnumerable <Node> graph, string path, bool subgraph, bool translatedCode) { if (NameService == null) { NameService = new NameService(); } NameService.SetNames(graph); DebugHooks.LogInfo("WriteDotFile started"); WriteDotFile(graph, path, translatedCode); DebugHooks.LogInfo("WriteDotFile succeeded"); DebugHooks.LogInfo("dot.exe started"); int start = Environment.TickCount; Dot.Render(path, null); int end = Environment.TickCount; DebugHooks.LogInfo("dot.exe succeeded. ellapsed time: {0}", (end - start) + "ms"); }
internal static void VisualizeGraph(this IClrMethodBody body, NodeList list, bool translatedCode) { DebugHooks.LogInfo("Flow graph constructed"); DotService.NameService = null; bool filter = DebugHooks.EvalFilter(body.Method); var after = translatedCode; var before = !translatedCode; if (filter || (before && DebugHooks.VisualizeGraphBefore) || (after && DebugHooks.VisualizeGraphAfter)) { DotService.Write(list, DotService.MakePath(body, before ? "before" : "after"), true, translatedCode); } if (filter || DebugHooks.DumpILCode) { DumpService.Dump(list, body, CommonLanguageInfrastructure.TestCaseDirectory); DebugHooks.LogInfo("IL code dumped"); } }
private TranslatorResult TranslateCore(TranslationContext context) { if (context.Method.DeclaringType.IsGeneric()) { throw new ILTranslatorException("Not supported"); } #if DEBUG DebugHooks.LogSeparator(); DebugHooks.LogInfo("ILTranslator started for method: {0}", context.Method); if (DebugHooks.CanBreak(context.Method)) { Debugger.Break(); } #endif try { var output = Process(context); #if DEBUG DebugHooks.LogInfo("ILTranslator succeeded for method: {0}", context.Method); DebugHooks.LogSeparator(); #endif return(output); } catch (Exception e) { #if DEBUG DebugHooks.SetLastError(context.Method); #endif if (e is CompilerException) { throw; } throw Errors.CILTranslator.UnableToTranslateMethod.CreateInnerException(e, context.FullMethodName); } }
/// <summary> /// Translates all basic blocks in flow graph. /// </summary> public void Translate(TranslationContext context) { #if DEBUG DebugHooks.LogInfo("TranslateBlocks started for method: {0}", context.Method); #endif //Note: CIL pops exception from stack for us if it is not used context.Provider.PopException = false; context.Provider.BeforeTranslation(); foreach (var bb in context.Body.ControlFlowGraph.Blocks) { #if DEBUG //if (DebugHooks.CanBreak(_method)) Debugger.Break(); #endif TranslateBlock(context.New(bb)); } context.Provider.AfterTranslation(); #if DEBUG DebugHooks.LogInfo("TranslateBlocks succeeded for method: {0}", context.Method); #endif }
public static void Dump(IClrMethodBody body, TranslatorResult result, string format, string filename) { if (!(DebugHooks.EvalFilter(body.Method) || DebugHooks.DumpILMap)) { return; } DebugHooks.LogInfo("DumpILMap started. Format = {0}. FileName = {1}.", format, filename); string dir = body.GetTestDirectory(); Directory.CreateDirectory(dir); using (var writer = new StreamWriter(Path.Combine(dir, filename))) { DumpService.DumpLocalVariables(writer, body); writer.WriteLine(Separator); if (result.Begin != null && result.Begin.Length > 0) { writer.WriteLine("#BEGIN CODE"); writer.WriteLine(Separator); for (int i = 0; i < result.Begin.Length; ++i) { writer.WriteLine(result.Output[i].ToString(format, null)); } writer.WriteLine(Separator); } foreach (var bb in body.ControlFlowGraph.Blocks) { writer.WriteLine("#BASIC BLOCK {0}", bb.Index); DumpStackState(writer, bb); writer.WriteLine(Separator); writer.WriteLine("#ORIGINAL CODE"); foreach (var instruction in bb.Code) { writer.WriteLine(instruction.ToString(format, null)); } writer.WriteLine(); var code = bb.TranslatedCode; writer.WriteLine("#TRANSLATED CODE"); foreach (var instruction in code) { writer.WriteLine(instruction.ToString(format, null)); } writer.WriteLine(Separator); } if (result.End != null && result.End.Length > 0) { writer.WriteLine("#END CODE"); writer.WriteLine(Separator); foreach (var instruction in result.End) { writer.WriteLine(instruction.ToString(format, null)); } } } DebugHooks.LogInfo("DumpILMap succeded"); }