File: Contracts\Signature\Signature_1.cs
Web Access
Project: src\src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts)
// 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.Reflection.Metadata;
using Microsoft.Diagnostics.DataContractReader.SignatureHelpers;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

// NOTE: some elements of SignatureTypeProvider remain unimplemented or minimally implemented
// as they are not needed for the current usage of ISignature.
// GetModifiedType and GetPinnedType ignore pinning and custom modifiers.
// GetTypeFromReference does not look up the type in another module.
// GetTypeFromSpecification is unimplemented.
// These can be completed as needed.
internal sealed class Signature_1 : ISignature
{
    private readonly Target _target;
    private readonly Dictionary<ModuleHandle, SignatureTypeProvider<TypeHandle>> _thProviders = [];

    internal Signature_1(Target target)
    {
        _target = target;
    }

    public void Flush()
    {
        _thProviders.Clear();
    }

    private SignatureTypeProvider<TypeHandle> GetTypeHandleProvider(ModuleHandle moduleHandle)
    {
        if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider<TypeHandle>? thProvider))
        {
            return thProvider;
        }

        SignatureTypeProvider<TypeHandle> newProvider = new(_target, moduleHandle);
        _thProviders[moduleHandle] = newProvider;
        return newProvider;
    }

    TypeHandle ISignature.DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx)
    {
        SignatureTypeProvider<TypeHandle> provider = GetTypeHandleProvider(moduleHandle);
        MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!;

        BlobReader blobReader = mdReader.GetBlobReader(blobHandle);
        RuntimeSignatureDecoder<TypeHandle, TypeHandle> decoder = new(provider, _target, mdReader, ctx);
        return decoder.DecodeFieldSignature(ref blobReader);
    }

    TargetPointer ISignature.GetVarArgArgsBase(TargetPointer vaSigCookieAddr)
    {
        // Compute the address of the first argument. On x86 the args are pushed below the cookie
        // pointer (stack grows down on the args walk), so the first argument lies at
        //   vaSigCookieAddr + sizeOfArgs.
        // On all other platforms the first argument follows the cookie pointer in memory
        // (stack grows up on the args walk), so its address is at
        //   vaSigCookieAddr + sizeof(VASigCookie*).
        if (_target.Contracts.RuntimeInfo.GetTargetArchitecture() == RuntimeInfoArchitecture.X86)
        {
            Data.VASigCookie cookie = GetCookie(vaSigCookieAddr);
            return new TargetPointer(vaSigCookieAddr.Value + cookie.SizeOfArgs);
        }

        return new TargetPointer(vaSigCookieAddr.Value + (ulong)_target.PointerSize);
    }

    void ISignature.GetVarArgSignature(TargetPointer vaSigCookieAddr, out TargetPointer signatureAddress, out uint signatureLength)
    {
        Data.VASigCookie cookie = GetCookie(vaSigCookieAddr);

        signatureAddress = cookie.SignaturePointer;
        signatureLength = cookie.SignatureLength;
        Debug.Assert(signatureAddress != TargetPointer.Null || signatureLength == 0,
            "VASigCookie has a non-zero signature length but a null signature pointer.");
    }
    private Data.VASigCookie GetCookie(TargetPointer vaSigCookieAddr)
    {
        TargetPointer vaSigCookie = _target.ReadPointer(vaSigCookieAddr);
        return _target.ProcessedData.GetOrAdd<Data.VASigCookie>(vaSigCookie);
    }
}