Skip to content

Commit 5b79b76

Browse files
Add new DiagnosticMethodInfo public API (#103220)
Contributes to #96528.
1 parent 4443a7d commit 5b79b76

File tree

20 files changed

+790
-81
lines changed

20 files changed

+790
-81
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,4 +837,10 @@
837837
<DiagnosticId>CP0002</DiagnosticId>
838838
<Target>M:System.Threading.Lock.#ctor(System.Boolean)</Target>
839839
</Suppression>
840-
</Suppressions>
840+
<Suppression>
841+
<DiagnosticId>CP0002</DiagnosticId>
842+
<Target>M:System.Diagnostics.DiagnosticMethodInfo.#ctor(System.String,System.String,System.String)</Target>
843+
<Left>ref/net9.0/System.Private.CoreLib.dll</Left>
844+
<Right>lib/net9.0/System.Private.CoreLib.dll</Right>
845+
</Suppression>
846+
</Suppressions>

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/StackTraceMetadataCallbacks.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5-
6-
using Internal.Runtime.CompilerServices;
5+
using System.Diagnostics;
76

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

src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
<Compile Include="Internal\Reflection\Extensions\NonPortable\CustomAttributeInheritanceRules.cs" />
132132
<Compile Include="Internal\Reflection\Extensions\NonPortable\CustomAttributeInstantiator.cs" />
133133
<Compile Include="Internal\Reflection\Extensions\NonPortable\CustomAttributeSearcher.cs" />
134+
<Compile Include="System\Diagnostics\DiagnosticMethodInfo.NativeAot.cs" />
134135
</ItemGroup>
135136
<ItemGroup>
136137
<Compile Include="System\Reflection\RuntimeAssembly.cs" />

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
using Internal.Reflection.Augments;
1414
using Internal.Runtime;
15+
using Internal.Runtime.Augments;
1516
using Internal.Runtime.CompilerServices;
1617

1718
namespace System
@@ -254,6 +255,8 @@ private IntPtr GetActualTargetFunctionPointer(object thisObject)
254255

255256
protected virtual MethodInfo GetMethodImpl()
256257
{
258+
// NOTE: this implementation is mirrored in GetDiagnosticMethodInfo below
259+
257260
// Multi-cast delegates return the Method of the last delegate in the list
258261
if (_helperObject is Wrapper[] invocationList)
259262
{
@@ -270,6 +273,52 @@ protected virtual MethodInfo GetMethodImpl()
270273
return ReflectionAugments.ReflectionCoreCallbacks.GetDelegateMethod(this);
271274
}
272275

276+
internal DiagnosticMethodInfo GetDiagnosticMethodInfo()
277+
{
278+
// NOTE: this implementation is mirrored in GetMethodImpl above
279+
280+
// Multi-cast delegates return the diagnostic method info of the last delegate in the list
281+
if (_helperObject is Wrapper[] invocationList)
282+
{
283+
int invocationCount = (int)_extraFunctionPointerOrData;
284+
return invocationList[invocationCount - 1].Value.GetDiagnosticMethodInfo();
285+
}
286+
287+
// Return the delegate Invoke method for marshalled function pointers and LINQ expressions
288+
if ((_firstParameter is NativeFunctionPointerWrapper) || (_functionPointer == GetThunk(ObjectArrayThunk)))
289+
{
290+
Type t = GetType();
291+
return new DiagnosticMethodInfo("Invoke", t.FullName, t.Module.Assembly.FullName);
292+
}
293+
294+
IntPtr ldftnResult = GetDelegateLdFtnResult(out RuntimeTypeHandle _, out bool isOpenResolver);
295+
if (isOpenResolver)
296+
{
297+
MethodInfo mi = ReflectionAugments.ReflectionCoreCallbacks.GetDelegateMethod(this);
298+
Type? declaringType = mi.DeclaringType;
299+
if (declaringType.IsConstructedGenericType)
300+
declaringType = declaringType.GetGenericTypeDefinition();
301+
return new DiagnosticMethodInfo(mi.Name, declaringType.FullName, mi.Module.Assembly.FullName);
302+
}
303+
else
304+
{
305+
IntPtr functionPointer;
306+
if (FunctionPointerOps.IsGenericMethodPointer(ldftnResult))
307+
{
308+
unsafe
309+
{
310+
GenericMethodDescriptor* realTargetData = FunctionPointerOps.ConvertToGenericDescriptor(ldftnResult);
311+
functionPointer = RuntimeAugments.GetCodeTarget(realTargetData->MethodFunctionPointer);
312+
}
313+
}
314+
else
315+
{
316+
functionPointer = ldftnResult;
317+
}
318+
return RuntimeAugments.StackTraceCallbacksIfAvailable?.TryGetDiagnosticMethodInfoFromStartAddress(functionPointer);
319+
}
320+
}
321+
273322
public object? Target
274323
{
275324
get
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Internal.Runtime.Augments;
5+
6+
namespace System.Diagnostics
7+
{
8+
public sealed partial class DiagnosticMethodInfo
9+
{
10+
// Public for System.Private.StackTraceMetadata sake
11+
public DiagnosticMethodInfo(string name, string declaringTypeName, string declaringAssemblyName)
12+
=> (Name, DeclaringTypeName, DeclaringAssemblyName) = (name, declaringTypeName, declaringAssemblyName);
13+
14+
public string Name { get; }
15+
16+
public string? DeclaringTypeName { get; }
17+
18+
public string? DeclaringAssemblyName { get; }
19+
20+
public static DiagnosticMethodInfo? Create(Delegate @delegate)
21+
{
22+
ArgumentNullException.ThrowIfNull(@delegate);
23+
return @delegate.GetDiagnosticMethodInfo();
24+
}
25+
26+
public static DiagnosticMethodInfo? Create(StackFrame frame)
27+
{
28+
ArgumentNullException.ThrowIfNull(frame);
29+
return frame.TryGetMethodStartAddress(out IntPtr startAddress)
30+
? RuntimeAugments.StackTraceCallbacksIfAvailable?.TryGetDiagnosticMethodInfoFromStartAddress(startAddress)
31+
: null;
32+
}
33+
}
34+
}

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackFrame.NativeAot.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ public partial class StackFrame
4646
return _method;
4747
}
4848

49+
internal bool TryGetMethodStartAddress(out IntPtr startAddress)
50+
{
51+
if (_ipAddress == IntPtr.Zero || _ipAddress == Exception.EdiSeparator)
52+
{
53+
startAddress = IntPtr.Zero;
54+
return false;
55+
}
56+
57+
startAddress = _ipAddress - _nativeOffset;
58+
Debug.Assert(RuntimeImports.RhFindMethodStartAddress(_ipAddress) == startAddress);
59+
return true;
60+
}
61+
4962
private bool TryInitializeMethodBase()
5063
{
5164
if (_noMethodBaseAvailable || _ipAddress == IntPtr.Zero || _ipAddress == Exception.EdiSeparator)

0 commit comments

Comments
 (0)