| File: Compiler\DependencyAnalysis\MethodCodeNode.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.RyuJit\ILCompiler.RyuJit.csproj (ILCompiler.RyuJit) |
// 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.Diagnostics; using System.Text; using Internal.IL; using Internal.Text; using Internal.TypeSystem; using CombinedDependencyList = System.Collections.Generic.List<ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.CombinedDependencyListEntry>; namespace ILCompiler.DependencyAnalysis { [DebuggerTypeProxy(typeof(MethodCodeNodeDebugView))] public class MethodCodeNode : ObjectNode, IMethodBodyNode, INodeWithCodeInfo, INodeWithDebugInfo, INodeWithFunclets, ISpecialUnboxThunkNode, IMethodCodeNodeWithTypeSignature { private MethodDesc _method; private ObjectData _methodCode; private FrameInfo[] _frameInfos; private byte[] _gcInfo; private MethodExceptionHandlingInfoNode _ehInfo; private DebugLocInfo[] _debugLocInfos; private DebugVarInfo[] _debugVarInfos; private DebugEHClauseInfo[] _debugEHClauseInfos; private DependencyList _nonRelocationDependencies; private MethodDebugInformation _debugInfo; private TypeDesc[] _localTypes; public MethodCodeNode(MethodDesc method) { Debug.Assert(!method.IsAbstract); Debug.Assert(!method.IsGenericMethodDefinition && !method.OwningType.IsGenericDefinition); Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method); _method = method; } public void SetCode(ObjectData data) { Debug.Assert(_methodCode == null); _methodCode = data; } public MethodDesc Method => _method; protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); public override ObjectNodeSection GetSection(NodeFactory factory) { return factory.Target.IsWindows ? ObjectNodeSection.ManagedCodeWindowsContentSection : ObjectNodeSection.ManagedCodeUnixContentSection; } public override bool StaticDependenciesAreComputed => _methodCode != null; public override bool InterestingForDynamicDependencyAnalysis => _method.HasInstantiation || _method.OwningType.HasInstantiation; public virtual void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.GetMangledMethodName(_method)); } public int Offset => 0; public override bool IsShareable => _method is InstantiatedMethod || EETypeNode.IsTypeNodeShareable(_method.OwningType); public override bool HasConditionalStaticDependencies => CodeBasedDependencyAlgorithm.HasConditionalDependenciesDueToMethodCodePresence(_method); public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) { CombinedDependencyList dependencies = null; CodeBasedDependencyAlgorithm.AddConditionalDependenciesDueToMethodCodePresence(ref dependencies, factory, _method); return dependencies ?? (IEnumerable<CombinedDependencyListEntry>)Array.Empty<CombinedDependencyListEntry>(); } protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencies = _nonRelocationDependencies != null ? new DependencyList(_nonRelocationDependencies) : null; TypeDesc owningType = _method.OwningType; if (factory.PreinitializationManager.HasEagerStaticConstructor(owningType)) { dependencies ??= new DependencyList(); dependencies.Add(factory.EagerCctorIndirection(owningType.GetStaticConstructor()), "Eager .cctor"); } if (_ehInfo != null) { dependencies ??= new DependencyList(); dependencies.Add(_ehInfo, "Exception handling information"); } if (MethodAssociatedDataNode.MethodHasAssociatedData(this)) { dependencies ??= new DependencyList(); dependencies.Add(new DependencyListEntry(factory.MethodAssociatedData(this), "Method associated data")); } return dependencies; } public override ObjectData GetData(NodeFactory factory, bool relocsOnly) { return _methodCode; } public bool IsSpecialUnboxingThunk => ((CompilerTypeSystemContext)Method.Context).IsSpecialUnboxingThunk(_method); public ISymbolNode GetUnboxingThunkTarget(NodeFactory factory) { Debug.Assert(IsSpecialUnboxingThunk); MethodDesc nonUnboxingMethod = ((CompilerTypeSystemContext)Method.Context).GetTargetOfSpecialUnboxingThunk(_method); return factory.MethodEntrypoint(nonUnboxingMethod, false); } public FrameInfo[] FrameInfos => _frameInfos; public byte[] GCInfo => _gcInfo; public MethodExceptionHandlingInfoNode EHInfo => _ehInfo; // TODO-WASM: Appropriately extract funclet kinds from eh clause info public FuncletKind[] GetFuncletKinds() => throw new NotImplementedException(); public ISymbolNode GetAssociatedDataNode(NodeFactory factory) { if (MethodAssociatedDataNode.MethodHasAssociatedData(this)) return factory.MethodAssociatedData(this); return null; } public void InitializeFrameInfos(FrameInfo[] frameInfos) { Debug.Assert(_frameInfos == null); _frameInfos = frameInfos; } public void InitializeGCInfo(byte[] gcInfo) { Debug.Assert(_gcInfo == null); _gcInfo = gcInfo; } public void InitializeEHInfo(ObjectData ehInfo) { Debug.Assert(_ehInfo == null); if (ehInfo != null) _ehInfo = new MethodExceptionHandlingInfoNode(_method, ehInfo); } public DebugLocInfo[] DebugLocInfos => _debugLocInfos; public DebugVarInfo[] DebugVarInfos => _debugVarInfos; public DebugEHClauseInfo[] DebugEHClauseInfos => _debugEHClauseInfos; public bool IsStateMachineMoveNextMethod => _debugInfo.IsStateMachineMoveNextMethod; public void InitializeDebugLocInfos(DebugLocInfo[] debugLocInfos) { Debug.Assert(_debugLocInfos == null); _debugLocInfos = debugLocInfos; } public void InitializeDebugVarInfos(DebugVarInfo[] debugVarInfos) { Debug.Assert(_debugVarInfos == null); _debugVarInfos = debugVarInfos; } public void InitializeDebugInfo(MethodDebugInformation debugInfo) { Debug.Assert(_debugInfo == null); _debugInfo = debugInfo; } public void InitializeLocalTypes(TypeDesc[] localTypes) { Debug.Assert(_localTypes == null); _localTypes = localTypes; } public void InitializeDebugEHClauseInfos(DebugEHClauseInfo[] debugEHClauseInfos) { Debug.Assert(_debugEHClauseInfos == null); _debugEHClauseInfos = debugEHClauseInfos; } public IEnumerable<DebugVarInfoMetadata> GetDebugVars() { MethodSignature sig = _method.Signature; int offset = sig.IsStatic ? 0 : 1; var parameterNames = new string[sig.Length + offset]; int i = 0; foreach (var paramName in _debugInfo.GetParameterNames()) { parameterNames[i] = paramName; i++; } string[] localNames; if (_localTypes.Length > 0) { localNames = new string[_localTypes.Length]; var localVariables = _debugInfo.GetLocalVariables(); if (localVariables != null) { foreach (var local in localVariables) { if (!local.CompilerGenerated && local.Slot < localNames.Length) localNames[local.Slot] = local.Name; } } } else { localNames = Array.Empty<string>(); } foreach (var varInfo in _debugVarInfos) { if (varInfo.VarNumber < parameterNames.Length) { // This is a parameter TypeDesc varType; if (!sig.IsStatic && varInfo.VarNumber == 0) { varType = _method.OwningType.IsValueType ? _method.OwningType.MakeByRefType() : _method.OwningType; } else { varType = _method.Signature[(int)varInfo.VarNumber - offset]; } string name = parameterNames[varInfo.VarNumber]; if (name == null) continue; yield return new DebugVarInfoMetadata(name, varType, isParameter: true, varInfo); } else { // This is a local int localNumber = (int)varInfo.VarNumber - sig.Length - offset; string name = localNames[localNumber]; if (name == null) continue; yield return new DebugVarInfoMetadata(name, _localTypes[localNumber], isParameter: false, varInfo); } } } public void InitializeNonRelocationDependencies(DependencyList dependencies) { _nonRelocationDependencies = dependencies; } public IEnumerable<NativeSequencePoint> GetNativeSequencePoints() { // This can be null if we're not generating debug info if (_debugLocInfos == null) yield break; var sequencePoints = new (string Document, int LineNumber)[_debugLocInfos.Length * 4 /* chosen empirically */]; try { foreach (var sequencePoint in _debugInfo.GetSequencePoints()) { int offset = sequencePoint.Offset; if (offset >= sequencePoints.Length) { int newLength = Math.Max(2 * sequencePoints.Length, sequencePoint.Offset + 1); Array.Resize(ref sequencePoints, newLength); } sequencePoints[offset] = (sequencePoint.Document, sequencePoint.LineNumber); } // Propagate last known document/line number forward to enable correct mapping when IL offsets decrease at higher native offsets for (int i = 1; i < sequencePoints.Length; i++) { if (sequencePoints[i].Document == null && sequencePoints[i - 1].Document != null) { sequencePoints[i] = (sequencePoints[i - 1].Document, sequencePoints[i - 1].LineNumber); } } } catch (BadImageFormatException) { // Roslyn had a bug where it was generating bad sequence points: // https://github.com/dotnet/roslyn/issues/20118 // Do not crash the compiler. yield break; } int previousNativeOffset = -1; string previousDocument = null; int previousLineNumber = -1; // OffsetMapping is sorted in order of increasing native offset (but not necessarily by IL offset) foreach (var nativeMapping in _debugLocInfos) { if (nativeMapping.NativeOffset == previousNativeOffset) continue; var sequencePoint = sequencePoints[Math.Min(nativeMapping.ILOffset, sequencePoints.Length - 1)]; // Emit sequence point if its line number or document differ from the previous one. // See WalkILOffsetsCallback in src/coreclr/vm/debugdebugger.cpp for more details. if (sequencePoint.Document != null && (sequencePoint.Document != previousDocument || sequencePoint.LineNumber != previousLineNumber)) { yield return new NativeSequencePoint( nativeMapping.NativeOffset, sequencePoint.Document, sequencePoint.LineNumber); previousNativeOffset = nativeMapping.NativeOffset; previousDocument = sequencePoint.Document; previousLineNumber = sequencePoint.LineNumber; } } } public override int ClassCode => 788492407; public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { return comparer.Compare(_method, ((MethodCodeNode)other)._method); } public override string ToString() { return _method.ToString(); } internal sealed class MethodCodeNodeDebugView { private readonly MethodCodeNode _node; public MethodCodeNodeDebugView(MethodCodeNode node) { _node = node; } public MethodDesc Method => _node.Method; public string Disassembly { get { var sb = new StringBuilder(); sb.Append("// "); sb.AppendLine(_node.Method.ToString()); if (_node.StaticDependenciesAreComputed) { var d = Disassembler.Disassemble( _node.Method.Context.Target.Architecture, _node._methodCode.Data, _node._methodCode.Relocs); sb.Append(d); } else { sb.Append("// Not compiled yet."); } return sb.ToString(); } } } } public readonly struct DebugLocInfo { public readonly int NativeOffset; public readonly int ILOffset; public DebugLocInfo(int nativeOffset, int ilOffset) => (NativeOffset, ILOffset) = (nativeOffset, ilOffset); } }