Description
A recent Xamarin iOS PR (dotnet/macios#18742) ran into an issue in .NET 8/Mono with the RuntimeTypeHandle.Equals method.
The Xamarin tooling generates several lookup functions in IL using Mono.Cecil which look something like this:
public uint LookupTypeId(RuntimeTypeHandle handle) {
if (handle.Equals(typeof(NSString).TypeHandle)) {
return 1u;
}
if (handle.Equals(typeof(NSSet).TypeHandle)) {
return 2u;
}
// ...
return unchecked((uint)-1);
}
While this worked fine in .NET 7, in .NET 8 calling for example LookupTypeId(typeof(NSString).TypeHandle) won't return the correct value (4294967295 instead of 1).
Reproduction Steps
The issue can be reproduced with a modified HelloWorld Mono sample:
<!-- src/mono/sample/LookupTable/LookupTable.ilproj -->
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
</PropertyGroup>
</Project>
// src/mono/sample/LookupTable/LookupTable.il
.assembly extern mscorlib{}
.assembly LookupTable{}
.class public auto ansi abstract sealed beforefieldinit LookupTable
extends [mscorlib]System.Object
{
.method public hidebysig static
int32 LookupTypeId (
valuetype [mscorlib]System.RuntimeTypeHandle handle
) cil managed
{
.maxstack 8
IL_aaaa: ldarga.s handle
ldtoken [mscorlib]System.String
call instance bool [mscorlib]System.RuntimeTypeHandle::Equals(valuetype [mscorlib]System.RuntimeTypeHandle)
brfalse.s IL_aaab
ldc.i4.2
ret
IL_aaab: ldc.i4.0
ret
}
}
<!-- src/mono/sample/HelloWorld/HelloWorld.csproj -->
<ItemGroup>
<ProjectReference Include="..\LookupTable\LookupTable.ilproj" />
</ItemGroup>
// src/mono/sample/HelloWorld/Program.cs
if (LookupTable.LookupTypeId(typeof(string).TypeHandle) == 2) {
System.Console.WriteLine("FOUND");
} else {
System.Console.WriteLine("NOT FOUND");
}
Build the mono runtime with: ./build.sh mono+libs -c Release
Build and run the sample with mono -C src/mono/sample/HelloWorld MONO_CONFIG=Release MONO_ARCH=arm64 clean run
Expected behavior
The program should print FOUND.
Actual behavior
The program prints NOT FOUND.
Regression?
The generated lookup tables worked well before bumping to .NET 8.
Known Workarounds
When we disable inlining of the RuntimeTypeHandle.Equals method in src/mono/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs, the lookup function works correctly:
[MethodImpl(MethodImplOptions.NoInlining)]
public bool Equals(RuntimeTypeHandle handle)
{
return value == handle.Value;
}
Configuration
- .NET 8 (
e9ce3aac5440b8d5b76bddfea6285e546083589d)
- building on macOS 13.5
- ARM64 (M1)
- Specific to
Release configuration
Other information
@filipnavara managed to workaround the issue by preventing inlining of the Equals method and so we believe that the culprit is inlining.
cc @rolfbjarne @ivanpovazan @filipnavara
Description
A recent Xamarin iOS PR (dotnet/macios#18742) ran into an issue in .NET 8/Mono with the
RuntimeTypeHandle.Equalsmethod.The Xamarin tooling generates several lookup functions in IL using Mono.Cecil which look something like this:
While this worked fine in .NET 7, in .NET 8 calling for example
LookupTypeId(typeof(NSString).TypeHandle)won't return the correct value (4294967295instead of1).Reproduction Steps
The issue can be reproduced with a modified HelloWorld Mono sample:
// src/mono/sample/LookupTable/LookupTable.il .assembly extern mscorlib{} .assembly LookupTable{} .class public auto ansi abstract sealed beforefieldinit LookupTable extends [mscorlib]System.Object { .method public hidebysig static int32 LookupTypeId ( valuetype [mscorlib]System.RuntimeTypeHandle handle ) cil managed { .maxstack 8 IL_aaaa: ldarga.s handle ldtoken [mscorlib]System.String call instance bool [mscorlib]System.RuntimeTypeHandle::Equals(valuetype [mscorlib]System.RuntimeTypeHandle) brfalse.s IL_aaab ldc.i4.2 ret IL_aaab: ldc.i4.0 ret } }Build the mono runtime with:
./build.sh mono+libs -c ReleaseBuild and run the sample with
mono -C src/mono/sample/HelloWorld MONO_CONFIG=Release MONO_ARCH=arm64 clean runExpected behavior
The program should print
FOUND.Actual behavior
The program prints
NOT FOUND.Regression?
The generated lookup tables worked well before bumping to .NET 8.
Known Workarounds
When we disable inlining of the
RuntimeTypeHandle.Equalsmethod insrc/mono/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs, the lookup function works correctly:Configuration
e9ce3aac5440b8d5b76bddfea6285e546083589d)ReleaseconfigurationOther information
@filipnavara managed to workaround the issue by preventing inlining of the
Equalsmethod and so we believe that the culprit is inlining.cc @rolfbjarne @ivanpovazan @filipnavara