-
Couldn't load subscription status.
- Fork 5.2k
Open
Milestone
Description
This was hit downstream in some XUnit async code in libraries tests. The small reproduction is as follows:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
internal class Program
{
public static void Main(string[] args)
{
// Expose 'ReflectedMethod'
typeof(Program).GetMethod("ReflectedMethod", BindingFlags.Static | BindingFlags.NonPublic);
ReflectedMethod<string>();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ReflectedMethod<T>()
{
NonReflectedGenericMethod<T>();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void NonReflectedGenericMethod<T>()
{
Console.WriteLine(typeof(T));
Console.WriteLine(Environment.StackTrace);
}
}> dotnet publish -r win-x64 /p:PublishAot=true -c debug
> .\bin\debug\net10.0\win-x64\publish\TestConsole.exe
System.String
at System.Environment.get_StackTrace() + 0x33
at TestConsole!<BaseAddress>+0x1d917f
at Program.ReflectedMethod[T]() + 0x25
at Program.Main(String[] args) + 0x5eNotice at TestConsole!<BaseAddress>+0x1d917f that should be at Program.NonReflectedGenericMethod[T]() + 0x1e:
> dotnet publish -r win-x64 /p:PublishAot=true -c release
System.String
at System.Environment.get_StackTrace() + 0x21
at Program.NonReflectedGenericMethod[T]() + 0x1e
at Program.ReflectedMethod[T]() + 0x11
at Program.Main(String[] args) + 0x29
The underlying ILC logic goes something like this:
ReflectedMethodgets reflection-exposed.- This causes us to generate generic templates for
NonReflectedGenericMethod(its callee). - This adds a 'limited'
MethodMetadataNodenode to the graph (GetNativeLayoutMetadataDependencies). - This causes the "metadata transform" to consider the method included in the metadata produced.
- This causes it to be excluded it from the normal ST mappings ().
runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
Lines 735 to 740 in 9be281b
// Methods that will end up in the reflection invoke table should not have an entry in stack trace table // We'll try looking them up in reflection data at runtime. if (transformed.GetTransformedMethodDefinition(typicalMethod) != null && ShouldMethodBeInInvokeMap(method) && (GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) != 0) continue; - But we don't actually generate any invoke map entries for it, since that's not needed.
It seems it would be nice to avoid this kind of discrepancy by construction by more directly connecting the code which determines which methods go into the invoke map with the stack trace mappings code.
Metadata
Metadata
Assignees
Type
Projects
Status
No status