-
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
Optimize 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' #101858
Optimize 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' #101858
Conversation
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
Failure: | ||
Debug.Fail("Unexpected CorElementType: " + dstElementType + ": Not a valid widening target."); | ||
dstObject = null; | ||
return CreateChangeTypeException(srcEEType, dstEEType, semantics); | ||
} | ||
|
||
private static bool CanPrimitiveWiden(EETypeElementType destType, EETypeElementType srcType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete - no longer used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed in 54092d4.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we delete the CanPrimitiveWiden
method and create the exception at the end? I do not think that we care about how fast the exception gets created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted it in 95ea639🙂
Will leave this open, feel free to resolve if that change matches what you had in mind.
@jkotas was looking at this table: runtime/src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs Lines 225 to 242 in 6f18b5e
And noticed that |
Looks like a bug to me. |
I've added the flag in ee8def8. |
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
case EETypeElementType.Int16: | ||
short shortValue = Convert.ToInt16(srcObject); | ||
dstObject = dstEEType->IsEnum ? Enum.ToObject(dstEEType, shortValue) : shortValue; | ||
// Can only be sbyte here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? Can this be reboxing enum to primitive or vice versa? I think the exact matches are handled earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean? My understanding was that regardless of whether either value was an enum here, we're just copying the raw primitive value to that local and then RuntimeHelpers.Box
will take care of both scenarios at the end, either just boxing the primitive or boxing it as the target enum type. Is that not correct? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment was meant to be on the bool
case. The bool-backed enums are partially supported. I am not sure whether we can get here with bool backed enum, but the current code handles the bool backed enums so it would keep it that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh interesting. I thought we had removed bool-backed enum support in .NET 8. Anyway, fixed in cdccf69. It also allows us to remove that check on rawDstValue
not being null
, so that's also nice 😄
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
84fbc82
to
ff4abbc
Compare
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
src/coreclr/nativeaot/System.Private.CoreLib/src/System/InvokeUtils.cs
Outdated
Show resolved
Hide resolved
I got an idea on how to de-duplicate the implementation with the array one - pushed it into this PR. |
Is this expected or would you expect the savings to be higher? |
} | ||
|
||
private static bool CanPrimitiveWiden(EETypeElementType destType, EETypeElementType srcType) | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] // Two callers, one of them is potentially perf sensitive | ||
internal static bool CanPrimitiveWiden(EETypeElementType dstType, EETypeElementType srcType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out this method is useful to aid with deduplication, so I put it back.
@@ -232,7 +359,7 @@ private static bool CanPrimitiveWiden(EETypeElementType destType, EETypeElementT | |||
0xC540, // Int16 (W = I2, I4, I8, R4, R8) | |||
0xCF88, // UInt16 (W = U2, CHAR, I4, U4, I8, U8, R4, R8) | |||
0xC500, // Int32 (W = I4, I8, R4, R8) | |||
0xCE00, // UInt32 (W = U4, I8, R4, R8) | |||
0xCE00, // UInt32 (W = U4, I8, U8, R4, R8) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bit mask looks correct, it is just the comment that's wrong.
I'm a bit puzzled by eg. the minimal hello world sample showing a 0 bytes diff. We were clearly seeing a bunch of stuff being rooted by this method in our WinRT component. Wondering if there wasn't some other secondary root that was also keep that same stuff alive, or if it's something else. Would be curious to check that same project out with sizoscope once I get a new build of the runtime with this change in as well 🤔 |
I would be surprised if the code touched in this PR is part of a minimal hello world. One has to do reflection invocation, or something like |
I've added a two more apps to rt-sz measurements and they do show savings. 3% on a small app that uses reflection. It also still demonstrates savings for something more substantial, like a raw kestrel app. Nice!
|
/azp run runtime-nativeaot-outerloop |
Azure Pipelines successfully started running 1 pipeline(s). |
/ba-g Slow mac |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for raising the issues and the collaboration!
Happy to help! I really appreciate you taking the time to review and get this one through! 🙂 |
…#101858) * Optimize 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' * Add missing U4 -> U8 widening flag * Skip type checks when unboxing * Centralized boxing operations * Remove unnecessary code to handle enums * Combine 'Char' cases with 'UInt16' ones * Deduplicate the implementation between array and reflection --------- Co-authored-by: Jan Kotas <jkotas@microsoft.com>
…#101858) * Optimize 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' * Add missing U4 -> U8 widening flag * Skip type checks when unboxing * Centralized boxing operations * Remove unnecessary code to handle enums * Combine 'Char' cases with 'UInt16' ones * Deduplicate the implementation between array and reflection --------- Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Closes #101821
This PR optimizes 'ConvertOrWidenPrimitivesEnumsAndPointersIfPossible' to drop the dependency on
Convert.*
methods. Because the full matrix of types we have to handle is known, we can just hardcode it here, in a similar way to how other methods doing pretty much the same are already doing in the runtime. Should save a bit of size (eg. not rootBigInteger
) and be marginally faster.