From 4f68861544cfa76da45bbcde2e768439068951b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Mon, 4 Feb 2013 00:27:40 +0000 Subject: [PATCH] Simplify debug symbols generated by ILSpy --- .../Ast/AstMethodBodyBuilder.cs | 2 +- .../Ast/TextOutputFormatter.cs | 41 ++-- .../ICSharpCode.Decompiler/CodeMappings.cs | 231 +----------------- .../Disassembler/MethodBodyDisassembler.cs | 26 +- .../Disassembler/ReflectionDisassembler.cs | 11 +- .../ICSharpCode.Decompiler/ITextOutput.cs | 2 +- .../ICSharpCode.Decompiler/PlainTextOutput.cs | 2 +- 7 files changed, 52 insertions(+), 263 deletions(-) diff --git a/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 3437af546b..36066b1a43 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -126,7 +126,7 @@ namespace ICSharpCode.Decompiler.Ast astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); } - astBlock.AddAnnotation(new MemberMapping(methodDef) { LocalVariables = localVariables }); + astBlock.AddAnnotation(new MethodDebugSymbols(methodDef) { LocalVariables = localVariables.ToList() }); return astBlock; } diff --git a/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index c43b0c7c25..6fa539280a 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -265,8 +265,7 @@ namespace ICSharpCode.Decompiler.Ast } Stack startLocations = new Stack(); - MemberMapping currentMemberMapping; - Stack parentMemberMappings = new Stack(); + Stack symbolsStack = new Stack(); public void StartNode(AstNode node) { @@ -284,11 +283,10 @@ namespace ICSharpCode.Decompiler.Ast if (node is EntityDeclaration && node.Annotation() != null && node.GetChildByRole(Roles.Identifier).IsNull) output.WriteDefinition("", node.Annotation(), false); - - MemberMapping mapping = node.Annotation(); - if (mapping != null) { - parentMemberMappings.Push(currentMemberMapping); - currentMemberMapping = mapping; + + if (node.Annotation() != null) { + symbolsStack.Push(node.Annotation()); + symbolsStack.Peek().StartLocation = startLocations.Peek(); } } @@ -305,26 +303,19 @@ namespace ICSharpCode.Decompiler.Ast var startLocation = startLocations.Pop(); // code mappings - if (currentMemberMapping != null) { - var ranges = node.Annotation>(); - if (ranges != null && ranges.Count > 0) { - // add all ranges - foreach (var range in ranges) { - currentMemberMapping.MemberCodeMappings.Add( - new SourceCodeMapping { - ILInstructionOffset = range, - StartLocation = startLocation, - EndLocation = output.Location, - MemberMapping = currentMemberMapping - }); - } - } + var ranges = node.Annotation>(); + if (symbolsStack.Count > 0 && ranges != null && ranges.Count > 0) { + symbolsStack.Peek().SequencePoints.Add( + new SequencePoint() { + ILRanges = ranges, + StartLocation = startLocation, + EndLocation = output.Location + }); } - - if (node.Annotation() != null) { - output.AddDebuggerMemberMapping(currentMemberMapping); - currentMemberMapping = parentMemberMappings.Pop(); + if (node.Annotation() != null) { + symbolsStack.Peek().EndLocation = output.Location; + output.AddDebugSymbols(symbolsStack.Pop()); } } diff --git a/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs b/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs index 3fef8970b4..c6c0f06571 100644 --- a/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs +++ b/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs @@ -17,240 +17,35 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using ICSharpCode.Decompiler.Ast; -using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.ILAst; using ICSharpCode.NRefactory; -using ICSharpCode.NRefactory.CSharp; using Mono.Cecil; namespace ICSharpCode.Decompiler { - /// - /// Maps the source code to IL. - /// - public sealed class SourceCodeMapping + /// Maps method's source code to IL + public class MethodDebugSymbols { - /// - /// Gets or sets the start location of the instruction. - /// + public MethodDefinition CecilMethod { get; set; } + public List LocalVariables { get; set; } + public List SequencePoints { get; set; } public TextLocation StartLocation { get; set; } - - /// - /// Gets or sets the end location of the instruction. - /// public TextLocation EndLocation { get; set; } - /// - /// Gets or sets IL Range offset for the source code line. E.g.: 13-19 <-> 135. - /// - public ILRange ILInstructionOffset { get; set; } - - /// - /// Gets or sets the member mapping this source code mapping belongs to. - /// - public MemberMapping MemberMapping { get; set; } - - /// - /// Retrieves the array that contains the IL range and the missing gaps between ranges. - /// - /// The array representation of the step aranges. - public int[] ToArray(bool isMatch) + public MethodDebugSymbols(MethodDefinition methodDef) { - var currentList = new List(); - - // add list for the current source code line - currentList.AddRange(ILRange.OrderAndJoint(MemberMapping.MemberCodeMappings - .FindAll(m => m.StartLocation.Line == this.StartLocation.Line) - .ConvertAll(m => m.ILInstructionOffset))); - - if (!isMatch) { - // add inverted - currentList.AddRange(MemberMapping.InvertedList); - } else { - // if the current list contains the last mapping, add also the last gap - var lastInverted = MemberMapping.InvertedList.LastOrDefault(); - if (lastInverted != null && lastInverted.From == currentList[currentList.Count - 1].To) - currentList.Add(lastInverted); - } - - // set the output - var resultList = new List(); - foreach (var element in ILRange.OrderAndJoint(currentList)) { - resultList.Add(element.From); - resultList.Add(element.To); - } - - return resultList.ToArray(); + this.CecilMethod = methodDef; + this.LocalVariables = new List(); + this.SequencePoints = new List(); } } - /// - /// Stores the member information and its source code mappings. - /// - public sealed class MemberMapping + public class SequencePoint { - IEnumerable invertedList; - - internal MemberMapping() - { - } - - public MemberMapping(MethodDefinition method) - { - this.MetadataToken = method.MetadataToken.ToInt32(); - this.MemberCodeMappings = new List(); - this.MemberReference = method; - this.CodeSize = method.Body.CodeSize; - } - - /// - /// Gets or sets the type of the mapping. - /// - public MemberReference MemberReference { get; internal set; } - - /// - /// Metadata token of the member. - /// - public int MetadataToken { get; internal set; } - - /// - /// Gets or sets the code size for the member mapping. - /// - public int CodeSize { get; internal set; } - - /// - /// Gets or sets the source code mappings. - /// - public List MemberCodeMappings { get; internal set; } - - /// - /// Gets or sets the local variables. - /// - public IEnumerable LocalVariables { get; internal set; } - - /// - /// Gets the inverted IL Ranges.
- /// E.g.: for (0-9, 11-14, 14-18, 21-25) => (9-11,18-21). - ///
- /// IL Range inverted list. - public IEnumerable InvertedList - { - get { - if (invertedList == null) { - var list = MemberCodeMappings.ConvertAll( - s => new ILRange { From = s.ILInstructionOffset.From, To = s.ILInstructionOffset.To }); - invertedList = ILRange.OrderAndJoint(ILRange.Invert(list, CodeSize)); - } - return invertedList; - } - } - } - - /// - /// Code mappings helper class. - /// - public static class CodeMappings - { - /// - /// Gets source code mapping and metadata token based on type name and line number. - /// - /// Code mappings storage. - /// Member reference name. - /// Line number. - /// Metadata token. - /// - public static SourceCodeMapping GetInstructionByLineNumber( - this MemberMapping codeMapping, - int lineNumber, - out int metadataToken) - { - if (codeMapping == null) - throw new ArgumentException("CodeMappings storage must be valid!"); - - var map = codeMapping.MemberCodeMappings.Find(m => m.StartLocation.Line == lineNumber); - if (map != null) { - metadataToken = codeMapping.MetadataToken; - return map; - } - - metadataToken = 0; - return null; - } - - /// - /// Gets a mapping given a type, a token and an IL offset. - /// - /// Code mappings storage. - /// Token. - /// IL offset. - /// True, if perfect match. - /// A code mapping. - public static SourceCodeMapping GetInstructionByTokenAndOffset( - this MemberMapping codeMapping, - int ilOffset, - out bool isMatch) - { - isMatch = false; - - if (codeMapping == null) - throw new ArgumentNullException("CodeMappings storage must be valid!"); - - // try find an exact match - var map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To); - - if (map == null) { - // get the immediate next one - map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset); - isMatch = false; - if (map == null) - map = codeMapping.MemberCodeMappings.LastOrDefault(); // get the last - - return map; - } - - isMatch = true; - return map; - } - - /// - /// Gets the source code and type name from metadata token and offset. - /// - /// Code mapping storage. - /// Metadata token. - /// IL offset. - /// Type definition. - /// Line number. - /// It is possible to exist to different types from different assemblies with the same metadata token. - public static bool GetInstructionByTokenAndOffset( - this MemberMapping mapping, - int ilOffset, - out MemberReference member, - out int line) - { - member = null; - line = 0; - - if (mapping == null) - throw new ArgumentException("CodeMappings storage must be valid!"); - - var codeMapping = mapping.MemberCodeMappings.Find( - cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1); - if (codeMapping == null) { - codeMapping = mapping.MemberCodeMappings.Find(cm => cm.ILInstructionOffset.From > ilOffset); - if (codeMapping == null) { - codeMapping = mapping.MemberCodeMappings.LastOrDefault(); - if (codeMapping == null) - return false; - } - } - - member = mapping.MemberReference; - line = codeMapping.StartLocation.Line; - return true; - } + public List ILRanges { get; set; } + public TextLocation StartLocation { get; set; } + public TextLocation EndLocation { get; set; } } } diff --git a/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index 04abfe5118..52c2772271 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Disassembler this.cancellationToken = cancellationToken; } - public void Disassemble(MethodBody body, MemberMapping methodMapping) + public void Disassemble(MethodBody body, MethodDebugSymbols debugSymbols) { // start writing IL code MethodDefinition method = body.Method; @@ -82,20 +82,19 @@ namespace ICSharpCode.Decompiler.Disassembler if (detectControlStructure && body.Instructions.Count > 0) { Instruction inst = body.Instructions[0]; HashSet branchTargets = GetBranchTargets(body.Instructions); - WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize); + WriteStructureBody(new ILStructure(body), branchTargets, ref inst, debugSymbols, method.Body.CodeSize); } else { foreach (var inst in method.Body.Instructions) { var startLocation = output.Location; inst.WriteTo(output); - if (methodMapping != null) { + if (debugSymbols != null) { // add IL code mappings - used in debugger - methodMapping.MemberCodeMappings.Add( - new SourceCodeMapping() { + debugSymbols.SequencePoints.Add( + new SequencePoint() { StartLocation = output.Location, EndLocation = output.Location, - ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset }, - MemberMapping = methodMapping + ILRanges = new List() { new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset } } }); } @@ -174,7 +173,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Indent(); } - void WriteStructureBody(ILStructure s, HashSet branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) + void WriteStructureBody(ILStructure s, HashSet branchTargets, ref Instruction inst, MethodDebugSymbols debugSymbols, int codeSize) { bool isFirstInstructionInStructure = true; bool prevInstructionWasBranch = false; @@ -184,7 +183,7 @@ namespace ICSharpCode.Decompiler.Disassembler if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) { ILStructure child = s.Children[childIndex++]; WriteStructureHeader(child); - WriteStructureBody(child, branchTargets, ref inst, currentMethodMapping, codeSize); + WriteStructureBody(child, branchTargets, ref inst, debugSymbols, codeSize); WriteStructureFooter(child); } else { if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { @@ -194,13 +193,12 @@ namespace ICSharpCode.Decompiler.Disassembler inst.WriteTo(output); // add IL code mappings - used in debugger - if (currentMethodMapping != null) { - currentMethodMapping.MemberCodeMappings.Add( - new SourceCodeMapping() { + if (debugSymbols != null) { + debugSymbols.SequencePoints.Add( + new SequencePoint() { StartLocation = startLocation, EndLocation = output.Location, - ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset }, - MemberMapping = currentMethodMapping + ILRanges = new List() { new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset } } }); } diff --git a/src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index ed246a092a..ec20cfa72a 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -22,6 +22,7 @@ using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; +using ICSharpCode.NRefactory; using Mono.Cecil; using Mono.Collections.Generic; @@ -114,6 +115,8 @@ namespace ICSharpCode.Decompiler.Disassembler // instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed // + TextLocation startLocation = output.Location; + //emit flags WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); @@ -217,9 +220,11 @@ namespace ICSharpCode.Decompiler.Disassembler if (method.HasBody) { // create IL code mappings - used in debugger - MemberMapping methodMapping = new MemberMapping(method); - methodBodyDisassembler.Disassemble(method.Body, methodMapping); - output.AddDebuggerMemberMapping(methodMapping); + MethodDebugSymbols debugSymbols = new MethodDebugSymbols(method); + debugSymbols.StartLocation = startLocation; + methodBodyDisassembler.Disassemble(method.Body, debugSymbols); + debugSymbols.EndLocation = output.Location; + output.AddDebugSymbols(debugSymbols); } CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name)); diff --git a/src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs b/src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs index 0bcf5eac6b..f13a55d61b 100644 --- a/src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs +++ b/src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler void WriteDefinition(string text, object definition, bool isLocal = true); void WriteReference(string text, object reference, bool isLocal = false); - void AddDebuggerMemberMapping(MemberMapping memberMapping); + void AddDebugSymbols(MethodDebugSymbols methodDebugSymbols); void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false); void MarkFoldEnd(); diff --git a/src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs b/src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs index f2d709cdd5..6319226d16 100644 --- a/src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs +++ b/src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs @@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler { } - void ITextOutput.AddDebuggerMemberMapping(MemberMapping memberMapping) + void ITextOutput.AddDebugSymbols(MethodDebugSymbols methodDebugSymbols) { } }