| File: Compiler\ILAssemblyGeneratingMethodDebugInfoProvider.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.IO; using Internal.IL; using Internal.TypeSystem; namespace ILCompiler { /// <summary> /// Debug information provider that wraps another provider and generates IL assembly listing /// (and maps debug information to it) for all methods the wrapped provider doesn't provide /// debug information for. /// </summary> public class ILAssemblyGeneratingMethodDebugInfoProvider : DebugInformationProvider, IDisposable { private readonly DebugInformationProvider _wrappedProvider; private readonly string _fileName; private readonly StreamWriter _tw; private readonly Dictionary<MethodDesc, MethodDebugInformation> _generatedInfos = new Dictionary<MethodDesc, MethodDebugInformation>(); private int _currentLine; public ILAssemblyGeneratingMethodDebugInfoProvider(string fileName, DebugInformationProvider wrappedProvider = null) { _wrappedProvider = wrappedProvider; _fileName = fileName; _tw = new StreamWriter(new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)); } public override MethodDebugInformation GetDebugInfo(MethodIL methodIL) { MethodDebugInformation debugInfo = _wrappedProvider?.GetDebugInfo(methodIL); if (debugInfo != null && debugInfo != MethodDebugInformation.None) return debugInfo; MethodIL definitionIL = methodIL.GetMethodILDefinition(); // One file per compilation model has obvious stability problems in multithreaded // compilation. This would be fixable by e.g. generating multiple files, or preparing // the file after the IL scanning phase. Since this is a non-shipping feature, // we're going to ignore the stability concern here. lock (_generatedInfos) { if (!_generatedInfos.TryGetValue(definitionIL.OwningMethod, out debugInfo)) { debugInfo = GetDebugInformation(definitionIL); _generatedInfos.Add(definitionIL.OwningMethod, debugInfo); } return debugInfo; } } private SyntheticMethodDebugInformation GetDebugInformation(MethodIL methodIL) { MethodDesc owningMethod = methodIL.OwningMethod; var disasm = new ILDisassembler(methodIL); var fmt = new ILDisassembler.ILTypeNameFormatter(null); ArrayBuilder<ILSequencePoint> sequencePoints = default(ArrayBuilder<ILSequencePoint>); _tw.Write(".method "); // TODO: accessibility, specialname, calling conventions etc. if (!owningMethod.Signature.IsStatic) _tw.Write("instance "); _tw.Write(fmt.FormatName(owningMethod.Signature.ReturnType)); _tw.Write(" "); _tw.Write(owningMethod.GetName()); if (owningMethod.HasInstantiation) { _tw.Write("<"); for (int i = 0; i < owningMethod.Instantiation.Length; i++) { if (i != 0) _tw.Write(", "); _tw.Write(fmt.FormatName(owningMethod.Instantiation[i])); } _tw.Write(">"); } _tw.Write("("); for (int i = 0; i < owningMethod.Signature.Length; i++) { if (i != 0) _tw.Write(", "); _tw.Write(fmt.FormatName(owningMethod.Signature[i])); } _tw.WriteLine(") cil managed"); _currentLine++; _tw.WriteLine("{"); _currentLine++; _tw.Write(" // Code size: "); _tw.Write(disasm.CodeSize); _tw.WriteLine(); _currentLine++; _tw.Write(" .maxstack "); _tw.Write(methodIL.MaxStack); _tw.WriteLine(); _currentLine++; LocalVariableDefinition[] locals = methodIL.GetLocals(); if (locals != null && locals.Length > 0) { _tw.Write(" .locals "); if (methodIL.IsInitLocals) _tw.Write("init "); _tw.Write("("); for (int i = 0; i < locals.Length; i++) { if (i != 0) { _tw.WriteLine(","); _currentLine++; _tw.Write(" "); } _tw.Write(fmt.FormatName(locals[i].Type)); _tw.Write(" "); if (locals[i].IsPinned) _tw.Write("pinned "); _tw.Write("V_"); _tw.Write(i); } _tw.WriteLine(")"); _currentLine++; } _tw.WriteLine(); _currentLine++; while (disasm.HasNextInstruction) { _currentLine++; int offset = disasm.Offset; _tw.WriteLine(disasm.GetNextInstruction()); sequencePoints.Add(new ILSequencePoint(offset, _fileName, _currentLine)); } _tw.WriteLine("}"); _currentLine++; _tw.WriteLine(); _currentLine++; return new SyntheticMethodDebugInformation(sequencePoints.ToArray()); } public void Dispose() { _tw.Dispose(); } private sealed class SyntheticMethodDebugInformation : MethodDebugInformation { private readonly ILSequencePoint[] _sequencePoints; public SyntheticMethodDebugInformation(ILSequencePoint[] sequencePoints) { _sequencePoints = sequencePoints; } public override IEnumerable<ILSequencePoint> GetSequencePoints() { return _sequencePoints; } } } }