-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Mono] RuntimeTypeHandle.Equals seems to be broken in Release mode #90800
Comments
/cc: @lambdageek |
yikes |
Is it important that the generated IL goes through |
@lambdageek I don't think so. This is an example of the actual generated code: .method private final hidebysig newslot virtual
instance uint32 LookupTypeId (
valuetype [System.Private.CoreLib]System.RuntimeTypeHandle handle
) cil managed
{
.override method instance uint32 [Microsoft.MacCatalyst]ObjCRuntime.IManagedRegistrar::LookupTypeId(valuetype [System.Private.CoreLib]System.RuntimeTypeHandle)
// Method begins at RVA 0x224c
// Header size: 12
// Code size: 26 (0x1a)
.maxstack 2
// if (handle.Equals(typeof(AppDelegate).TypeHandle))
IL_0000: ldarga.s handle
IL_0002: ldtoken MySingleView.AppDelegate
IL_0007: call instance bool [System.Private.CoreLib]System.RuntimeTypeHandle::Equals(valuetype [System.Private.CoreLib]System.RuntimeTypeHandle)
IL_000c: brfalse IL_0017
// return 0u;
IL_0011: ldc.i4 0
IL_0016: ret
// return uint.MaxValue;
IL_0017: nop
IL_0018: ldc.i4.m1
IL_0019: ret
} // end of method __Registrar__::LookupTypeId Sorry for the confusion. |
It's a jit problem. If I run in release mode with interp, it finds the type |
It's the inliner. Running with |
It's specifically something about inlining the caller of In this snippet if I change
|
@jandupej I think this is somehow related to the |
@jandupej Maybe as a hack we can just do Although I'm worried about other scenarios where handwritten code might do |
@jandupej I think maybe it's a bug in If I change it like this: case OP_LDTOKEN_FIELD:
#if 0
ins->opcode = OP_VMOVE;
restart = TRUE;
break;
#else
/* fallthru */
#endif
case OP_VMOVE: { the code works. I'm not really sure why. The basic block BEFORE LOWER-VTYPE-OPTS looks like this for both versions:
The problem happens with that last In the version where decompose does a fallthru, the code works and the output AFTER LOWER-VTYPE-OPTS is like this:
Note that the last
In the version where we overwrite the instruction opcode, instead the output is:
And the last
which seems wrong - it's copying the value in R48 into R48 again. but there's nothing that writes a value into R48! But just looking at the code for decompose it's really not obvious to me why doing an extra pass over this basic block would mess things up so much for that three opcode sequence
any ideas? |
Oh. Got it. It's a typo. It's always a typo if (!src_var)
src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
if (!dest_var)
dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg); In the |
Great find 😅 |
Without this, if some previous instruction already created a vreg for ins->dest (for example if we are doing multiple passes over the basic block because `restart == TRUE`) we will use an incorrect vreg when decomposing the current VMOVE Fixes dotnet#90800
Without this, if some previous instruction already created a vreg for ins->dest (for example if we are doing multiple passes over the basic block because `restart == TRUE`) we will use an incorrect vreg when decomposing the current VMOVE Fixes #90800
* Fix typo in mono_decompose_vtype_opts Without this, if some previous instruction already created a vreg for ins->dest (for example if we are doing multiple passes over the basic block because `restart == TRUE`) we will use an incorrect vreg when decomposing the current VMOVE Fixes #90800 * Only emit an OP_LDTOKEN_FIELD if we loaded a field token This is used by a CreateSpan optimization that needs access to the MonoClassField* For other cases of a bare LDTOKEN (such as hand-written IL that calls LDTOKEN on a type but doesn't follow it up with a call to `GetTypeFromHandle` leave the opcode as a VMOVE (from the `EMIT_NEW_TEMPLOAD` above))
* Fix typo in mono_decompose_vtype_opts Without this, if some previous instruction already created a vreg for ins->dest (for example if we are doing multiple passes over the basic block because `restart == TRUE`) we will use an incorrect vreg when decomposing the current VMOVE Fixes #90800 * Only emit an OP_LDTOKEN_FIELD if we loaded a field token This is used by a CreateSpan optimization that needs access to the MonoClassField* For other cases of a bare LDTOKEN (such as hand-written IL that calls LDTOKEN on a type but doesn't follow it up with a call to `GetTypeFromHandle` leave the opcode as a VMOVE (from the `EMIT_NEW_TEMPLOAD` above)) --------- Co-authored-by: Aleksey Kliger <alklig@microsoft.com>
@lambdageek looks like this fix is not in .NET 8, only main (.NET 9) and .NET 8 rc1? |
Ah nvm, I was looking for a PR into release/8.0, but it seems fixes in release/8.0-rc1 are automatically backported. |
This reverts commit 959cef6.
Description
A recent Xamarin iOS PR (xamarin/xamarin-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:
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 of1
).Reproduction Steps
The issue can be reproduced with a modified HelloWorld Mono sample:
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 insrc/mono/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs
, the lookup function works correctly:Configuration
e9ce3aac5440b8d5b76bddfea6285e546083589d
)Release
configurationOther 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
The text was updated successfully, but these errors were encountered: