Skip to content

Commit

Permalink
Add new DiagnosticMethodInfo public API (#103220)
Browse files Browse the repository at this point in the history
Contributes to #96528.
  • Loading branch information
MichalStrehovsky committed Jun 13, 2024
1 parent 4443a7d commit 5b79b76
Show file tree
Hide file tree
Showing 20 changed files with 790 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -837,4 +837,10 @@
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.Threading.Lock.#ctor(System.Boolean)</Target>
</Suppression>
</Suppressions>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.Diagnostics.DiagnosticMethodInfo.#ctor(System.String,System.String,System.String)</Target>
<Left>ref/net9.0/System.Private.CoreLib.dll</Left>
<Right>lib/net9.0/System.Private.CoreLib.dll</Right>
</Suppression>
</Suppressions>
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;

using Internal.Runtime.CompilerServices;
using System.Diagnostics;

namespace Internal.Runtime.Augments
{
Expand All @@ -26,5 +25,7 @@ public abstract class StackTraceMetadataCallbacks
/// <param name="isStackTraceHidden">Returns a value indicating whether the method should be hidden in stack traces</param>
/// <returns>Formatted method name or null if metadata for the method is not available</returns>
public abstract string TryGetMethodNameFromStartAddress(IntPtr methodStartAddress, out bool isStackTraceHidden);

public abstract DiagnosticMethodInfo TryGetDiagnosticMethodInfoFromStartAddress(IntPtr methodStartAddress);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
<Compile Include="Internal\Reflection\Extensions\NonPortable\CustomAttributeInheritanceRules.cs" />
<Compile Include="Internal\Reflection\Extensions\NonPortable\CustomAttributeInstantiator.cs" />
<Compile Include="Internal\Reflection\Extensions\NonPortable\CustomAttributeSearcher.cs" />
<Compile Include="System\Diagnostics\DiagnosticMethodInfo.NativeAot.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="System\Reflection\RuntimeAssembly.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

using Internal.Reflection.Augments;
using Internal.Runtime;
using Internal.Runtime.Augments;
using Internal.Runtime.CompilerServices;

namespace System
Expand Down Expand Up @@ -254,6 +255,8 @@ private IntPtr GetActualTargetFunctionPointer(object thisObject)

protected virtual MethodInfo GetMethodImpl()
{
// NOTE: this implementation is mirrored in GetDiagnosticMethodInfo below

// Multi-cast delegates return the Method of the last delegate in the list
if (_helperObject is Wrapper[] invocationList)
{
Expand All @@ -270,6 +273,52 @@ protected virtual MethodInfo GetMethodImpl()
return ReflectionAugments.ReflectionCoreCallbacks.GetDelegateMethod(this);
}

internal DiagnosticMethodInfo GetDiagnosticMethodInfo()
{
// NOTE: this implementation is mirrored in GetMethodImpl above

// Multi-cast delegates return the diagnostic method info of the last delegate in the list
if (_helperObject is Wrapper[] invocationList)
{
int invocationCount = (int)_extraFunctionPointerOrData;
return invocationList[invocationCount - 1].Value.GetDiagnosticMethodInfo();
}

// Return the delegate Invoke method for marshalled function pointers and LINQ expressions
if ((_firstParameter is NativeFunctionPointerWrapper) || (_functionPointer == GetThunk(ObjectArrayThunk)))
{
Type t = GetType();
return new DiagnosticMethodInfo("Invoke", t.FullName, t.Module.Assembly.FullName);
}

IntPtr ldftnResult = GetDelegateLdFtnResult(out RuntimeTypeHandle _, out bool isOpenResolver);
if (isOpenResolver)
{
MethodInfo mi = ReflectionAugments.ReflectionCoreCallbacks.GetDelegateMethod(this);
Type? declaringType = mi.DeclaringType;
if (declaringType.IsConstructedGenericType)
declaringType = declaringType.GetGenericTypeDefinition();
return new DiagnosticMethodInfo(mi.Name, declaringType.FullName, mi.Module.Assembly.FullName);
}
else
{
IntPtr functionPointer;
if (FunctionPointerOps.IsGenericMethodPointer(ldftnResult))
{
unsafe
{
GenericMethodDescriptor* realTargetData = FunctionPointerOps.ConvertToGenericDescriptor(ldftnResult);
functionPointer = RuntimeAugments.GetCodeTarget(realTargetData->MethodFunctionPointer);
}
}
else
{
functionPointer = ldftnResult;
}
return RuntimeAugments.StackTraceCallbacksIfAvailable?.TryGetDiagnosticMethodInfoFromStartAddress(functionPointer);
}
}

public object? Target
{
get
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Internal.Runtime.Augments;

namespace System.Diagnostics
{
public sealed partial class DiagnosticMethodInfo
{
// Public for System.Private.StackTraceMetadata sake
public DiagnosticMethodInfo(string name, string declaringTypeName, string declaringAssemblyName)
=> (Name, DeclaringTypeName, DeclaringAssemblyName) = (name, declaringTypeName, declaringAssemblyName);

public string Name { get; }

public string? DeclaringTypeName { get; }

public string? DeclaringAssemblyName { get; }

public static DiagnosticMethodInfo? Create(Delegate @delegate)
{
ArgumentNullException.ThrowIfNull(@delegate);
return @delegate.GetDiagnosticMethodInfo();
}

public static DiagnosticMethodInfo? Create(StackFrame frame)
{
ArgumentNullException.ThrowIfNull(frame);
return frame.TryGetMethodStartAddress(out IntPtr startAddress)
? RuntimeAugments.StackTraceCallbacksIfAvailable?.TryGetDiagnosticMethodInfoFromStartAddress(startAddress)
: null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ public partial class StackFrame
return _method;
}

internal bool TryGetMethodStartAddress(out IntPtr startAddress)
{
if (_ipAddress == IntPtr.Zero || _ipAddress == Exception.EdiSeparator)
{
startAddress = IntPtr.Zero;
return false;
}

startAddress = _ipAddress - _nativeOffset;
Debug.Assert(RuntimeImports.RhFindMethodStartAddress(_ipAddress) == startAddress);
return true;
}

private bool TryInitializeMethodBase()
{
if (_noMethodBaseAvailable || _ipAddress == IntPtr.Zero || _ipAddress == Exception.EdiSeparator)
Expand Down
Loading

0 comments on commit 5b79b76

Please sign in to comment.