File: Compiler\ObjectWriter\ObjectWriter.Aot.cs
Web Access
Project: src\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.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using Internal.Text;
using Internal.TypeSystem;
using Internal.TypeSystem.TypesDebugInfo;
using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData;
using static ILCompiler.DependencyAnalysis.RelocType;

namespace ILCompiler.ObjectWriter
{
    public abstract partial class ObjectWriter
    {
        // Debugging
        private UserDefinedTypeDescriptor _userDefinedTypeDescriptor;

        private protected abstract void EmitUnwindInfo(
            SectionWriter sectionWriter,
            INodeWithCodeInfo nodeWithCodeInfo,
            Utf8String currentSymbolName);

        private protected uint GetVarTypeIndex(bool isStateMachineMoveNextMethod, DebugVarInfoMetadata debugVar)
        {
            uint typeIndex;
            try
            {
                if (isStateMachineMoveNextMethod && debugVar.DebugVarInfo.VarNumber == 0)
                {
                    typeIndex = _userDefinedTypeDescriptor.GetStateMachineThisVariableTypeIndex(debugVar.Type);
                    // FIXME
                    // varName = "locals";
                }
                else
                {
                    typeIndex = _userDefinedTypeDescriptor.GetVariableTypeIndex(debugVar.Type);
                }
            }
            catch (TypeSystemException)
            {
                typeIndex = 0; // T_NOTYPE
                // FIXME
                // Debug.Fail();
            }
            return typeIndex;
        }

        private protected abstract ITypesDebugInfoWriter CreateDebugInfoBuilder();

        private protected abstract void EmitDebugFunctionInfo(
            uint methodTypeIndex,
            Utf8String methodName,
            SymbolDefinition methodSymbol,
            INodeWithDebugInfo debugNode,
            bool hasSequencePoints);

        private protected virtual void EmitDebugThunkInfo(
            Utf8String methodName,
            SymbolDefinition methodSymbol,
            INodeWithDebugInfo debugNode)
        {
        }

        private protected abstract void EmitDebugSections(IDictionary<Utf8String, SymbolDefinition> definedSymbols);

        partial void EmitDebugInfo(IReadOnlyCollection<DependencyNode> nodes, Logger logger)
        {
            if (logger.IsVerbose)
                logger.LogMessage($"Emitting debug information");

            _userDefinedTypeDescriptor = new UserDefinedTypeDescriptor(CreateDebugInfoBuilder(), _nodeFactory);

            foreach (DependencyNode depNode in nodes)
            {
                ObjectNode node = depNode as ObjectNode;
                if (node is null || node.ShouldSkipEmittingObjectNode(_nodeFactory))
                {
                    continue;
                }

                ISymbolNode symbolNode = node as ISymbolNode;
                ISymbolNode deduplicatedSymbolNode = _nodeFactory.ObjectInterner.GetDeduplicatedSymbol(_nodeFactory, symbolNode);
                if (deduplicatedSymbolNode != symbolNode)
                {
                    continue;
                }

                // Ensure any allocated MethodTables have debug info
                if (node is ConstructedEETypeNode methodTable)
                {
                    _userDefinedTypeDescriptor.GetTypeIndex(methodTable.Type, needsCompleteType: true);
                }

                if (node is INodeWithDebugInfo debugNode and ISymbolDefinitionNode symbolDefinitionNode)
                {
                    Utf8String methodName = GetMangledName(symbolDefinitionNode);
                    if (_definedSymbols.TryGetValue(methodName, out var methodSymbol))
                    {
                        if (node is IMethodNode methodNode)
                        {
                            bool hasSequencePoints = debugNode.GetNativeSequencePoints().Any();
                            uint methodTypeIndex = hasSequencePoints ? _userDefinedTypeDescriptor.GetMethodFunctionIdTypeIndex(methodNode.Method) : 0;
                            EmitDebugFunctionInfo(methodTypeIndex, methodName, methodSymbol, debugNode, hasSequencePoints);
                        }
                        else
                        {
                            EmitDebugThunkInfo(methodName, methodSymbol, debugNode);
                        }
                    }
                }
            }

            // Ensure all fields associated with generated static bases have debug info
            foreach (MetadataType typeWithStaticBase in _nodeFactory.MetadataManager.GetTypesWithStaticBases())
            {
                _userDefinedTypeDescriptor.GetTypeIndex(typeWithStaticBase, needsCompleteType: true);
            }

            EmitDebugSections(_definedSymbols);
        }

        private protected abstract void CreateEhSections();

        partial void PrepareForUnwindInfo() => CreateEhSections();

        partial void EmitUnwindInfoForNode(ObjectNode node, Utf8String currentSymbolName, SectionWriter sectionWriter)
        {
            if (node is INodeWithCodeInfo nodeWithCodeInfo)
            {
                EmitUnwindInfo(sectionWriter, nodeWithCodeInfo, currentSymbolName);
            }
        }

        partial void HandleControlFlowForRelocation(ISymbolNode relocTarget, Utf8String relocSymbolName)
        {
            if (relocTarget is IMethodNode or AssemblyStubNode or AddressTakenExternFunctionSymbolNode)
            {
                // For now consider all method symbols address taken.
                // We could restrict this in the future to those that are referenced from
                // reflection tables, EH tables, were actually address taken in code, or are referenced from vtables.
                EmitReferencedMethod(relocSymbolName);
            }
        }
    }
}