Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,33 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

/// <summary>
/// Classification of a signature type for GC scanning purposes.
/// </summary>
public enum GcTypeKind
{
/// <summary>Not a GC reference (primitives, pointers).</summary>
None,
/// <summary>Object reference (class, string, array).</summary>
Ref,
/// <summary>Interior pointer (byref).</summary>
Interior,
/// <summary>Value type that may contain embedded GC references.</summary>
Other,
}

public interface ISignatureDecoder : IContract
{
static string IContract.Name { get; } = nameof(SignatureDecoder);

TypeHandle DecodeFieldSignature(BlobHandle blobHandle, ModuleHandle moduleHandle, TypeHandle ctx) => throw new NotImplementedException();

/// <summary>
/// Decodes a method's signature for GC scanning purposes, classifying each parameter
/// as a GC reference, interior pointer, value type, or non-GC type.
/// Handles ELEMENT_TYPE_INTERNAL via the runtime type system.
/// </summary>
MethodSignature<GcTypeKind> DecodeMethodSignatureForGC(BlobHandle blobHandle, ModuleHandle moduleHandle) => throw new NotImplementedException();
}

public readonly struct SignatureDecoder : ISignatureDecoder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,27 @@

using System.Collections.Immutable;
using System.Reflection.Metadata;
using Microsoft.Diagnostics.DataContractReader.Contracts;

namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;

/// <summary>
/// Classification of a signature type for GC scanning purposes.
/// </summary>
internal enum GcTypeKind
{
/// <summary>Not a GC reference (primitives, pointers).</summary>
None,
/// <summary>Object reference (class, string, array).</summary>
Ref,
/// <summary>Interior pointer (byref).</summary>
Interior,
/// <summary>Value type that may contain embedded GC references.</summary>
Other,
}
namespace Microsoft.Diagnostics.DataContractReader.SignatureHelpers;

/// <summary>
/// Classifies signature types for GC scanning purposes.
/// Implements <see cref="ISignatureTypeProvider{TType, TGenericContext}"/> for use
/// with SRM's <see cref="SignatureDecoder{TType, TGenericContext}"/>.
/// Implements <see cref="IRuntimeSignatureTypeProvider{TType, TGenericContext}"/> which
/// is a superset of SRM's <see cref="ISignatureTypeProvider{TType, TGenericContext}"/>,
/// adding support for <c>ELEMENT_TYPE_INTERNAL</c>.
/// </summary>
internal sealed class GcSignatureTypeProvider
: ISignatureTypeProvider<GcTypeKind, object?>
: IRuntimeSignatureTypeProvider<GcTypeKind, object?>
{
public static readonly GcSignatureTypeProvider Instance = new();
private readonly Target _target;
private readonly ModuleHandle _moduleHandle;

public GcSignatureTypeProvider(Target target, ModuleHandle moduleHandle)
{
_target = target;
_moduleHandle = moduleHandle;
}

public GcTypeKind GetPrimitiveType(PrimitiveTypeCode typeCode)
=> typeCode switch
Expand Down Expand Up @@ -60,5 +54,41 @@ public GcTypeKind GetGenericInstantiation(GcTypeKind genericType, ImmutableArray
public GcTypeKind GetGenericTypeParameter(object? genericContext, int index) => GcTypeKind.Ref;
public GcTypeKind GetFunctionPointerType(MethodSignature<GcTypeKind> signature) => GcTypeKind.None;
public GcTypeKind GetModifiedType(GcTypeKind modifier, GcTypeKind unmodifiedType, bool isRequired) => unmodifiedType;
public GcTypeKind GetInternalModifiedType(Target target, TargetPointer typeHandlePointer, GcTypeKind unmodifiedType, bool isRequired) => unmodifiedType;
public GcTypeKind GetPinnedType(GcTypeKind elementType) => elementType;

public GcTypeKind GetInternalType(Target target, TargetPointer typeHandlePointer)
{
if (typeHandlePointer == TargetPointer.Null)
return GcTypeKind.None;

try
{
IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
TypeHandle th = rts.GetTypeHandle(typeHandlePointer);
CorElementType corType = rts.GetSignatureCorElementType(th);

return corType switch
{
CorElementType.Void or CorElementType.Boolean or CorElementType.Char
or CorElementType.I1 or CorElementType.U1
or CorElementType.I2 or CorElementType.U2
or CorElementType.I4 or CorElementType.U4
or CorElementType.I8 or CorElementType.U8
or CorElementType.R4 or CorElementType.R8
or CorElementType.I or CorElementType.U
or CorElementType.FnPtr or CorElementType.Ptr
=> GcTypeKind.None,

CorElementType.Byref => GcTypeKind.Interior,
CorElementType.ValueType => GcTypeKind.Other,

_ => GcTypeKind.Ref,
};
}
catch
{
return GcTypeKind.Ref;
}
}
}
Loading
Loading