-
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
Allow reference types for pinned GC.AllocateArray() #89293
Allow reference types for pinned GC.AllocateArray() #89293
Conversation
@dotnet-policy-service agree company="Unity Technologies" |
The same fix should be also applied to: |
Tagging subscribers to this area: @dotnet/gc Issue DetailsAfter an offline discussion, this is the "... or similar" part of the suggested feature set in this issue: #48703 This just relaxes front-end constraints as agreed for pinned array allocations with ref types, which is already possible and utilized internally. The use case shortly is forming unmanaged references to array indices, where the array has a very long lifetime. I added some extra coverage of the API, noticing the original constraint wasn't tested in the
|
Done, thanks I missed that. Are there tests to update for these as well? |
I think that AllocateUninitializedArray should also be relaxed to allow this since it already accepts reference types. |
I considered that but I worried that garbage bits on reference fields would perhaps not be good news for the GC. |
Seems like there is a test that expects that exception -
Sounds like a very bad idea to me (unless we want it to work but it will never return garbage) |
That's how it behaves today: runtime/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs Lines 741 to 746 in 7982376
Seeing above, I'd say that making the pinned path forward to |
This was done by deferring reference types to GC.AllocateArray to avoid potential memory issues with the GC + uninitialized memory. The API only promises to avoid initialization if possible, anyway. Refactored tests to parametrically exercise these new relaxed constraints.
Okay, I've similarly relaxed I refactored these tests and combined them to parametric ones to take this into account. |
The tests are shared for all runtime flavors. The test updates that you have done should be sufficient. |
Very nice! |
Relying on internal implementation zeroing refs if necessary.
Mono already piggybacks on the AllocateArray path anyway.
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.
other than my nit comment it LGTM! thanks for doing this work @jthorborg!
Co-authored-by: jthorborg <janus.thorborg@gmail.com>
|
||
GC_ALLOC_FLAGS flags = GC_ALLOC_FLAGS.GC_ALLOC_ZEROING_OPTIONAL; | ||
if (pinned) | ||
flags |= GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP; | ||
|
||
return Unsafe.As<T[]>(AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags)); | ||
// Runtime overrides GC_ALLOC_ZEROING_OPTIONAL if the type contains references, so we don't need to worry about that. | ||
return Unsafe.As<T[]>(AllocateNewArray(typeof(T[]).TypeHandle.Value, length, flags)); |
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.
Why did you change RuntimeTypeHandle.ToIntPtr
to RuntimeTypeHandle.Value
?
RuntimeTypeHandle.ToIntPtr
is JIT intrinsic so it will be optimized to just loading a constant in most cases. RuntimeTypeHandle.Value
does not have that optimization. This change may cause a perf regression.
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! I had no idea it was an intrinsic, how is that discoverable?
I changed it to be identical to the similar usage just below: https://github.com/dotnet/runtime/pull/89293/files/d7dfad7341d828be78b09cbe1e49e696d09fac4c#diff-63ddcf9eb1f63c1ddef526934b79b086b1d30883f3293847bf966d047bc7666dR781
Perhaps the should instead revert this line and change the other to use the intrinsic?
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! I had no idea it was an intrinsic, how is that discoverable?
JIT intrinsics are marked with [Intrinsic]
attributes.
Perhaps the should instead revert this line and change the other to use the intrinsic?
Agree.
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.
Ok, I'll do the change once I get closure on the other discussion
…rray allocation that should be slightly faster.
After a longer discussion, settled on a slightly augmented suggestion that isn't as controversial as the prior one.
I'd maybe remove the runtime/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs Lines 740 to 743 in 349970a
|
@@ -837,7 +830,7 @@ static T[] AllocateNewUninitializedArray(int length, bool pinned) | |||
throw new OverflowException(); | |||
|
|||
T[]? array = null; | |||
RuntimeImports.RhAllocateNewArray(EETypePtr.EETypePtrOf<T[]>().RawValue, (uint)length, (uint)flags, Unsafe.AsPointer(ref array)); | |||
RuntimeImports.RhAllocateNewArray(MethodTable.Of<T[]>(), (uint)length, (uint)flags, Unsafe.AsPointer(ref array)); |
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.
Could you please also change the type of RhAllocateNewArray
argument to MethodTable*
to fix the build break
// This isn't a guarantee since CoreCLR reorders fields and ignores the implicit sequential consistency of | ||
// structs, but it will never hurt the test. |
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 isn't a guarantee since CoreCLR reorders fields and ignores the implicit sequential consistency of | |
// structs, but it will never hurt the test. | |
// The CLR is permitted to reorder fields and ignore the implicit sequential consistency of | |
// value types if they contain managed references, but it will never hurt the test. |
Wouldn't that leave dead code just below when runtime/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs Lines 745 to 755 in 349970a
|
It looks like that this was fine-tuned based on microbenchmarks. If you delete anything here, you will most likely introduce regressions in micro-benchmarks that exercise this API. I do not think that this is worth touching. You would have to come up with perf numbers that demonstrate that you are not regressing anything that matters. |
* Fixing signature for `RhAllocateNewArray` in NativeAOT to directly use a `MethodTable*` * Adding explicit structlayout to silence warning for EmbeddedValueType in GCTests, and improved the comment.
The wasm build failure is known infrastructure error according to the build analysis. |
Thank you! |
Thank you, especially for the handholding while making green contributions. I'm sure it will be smoother the next time I'll have the pleasure. However trivial this may seem, it will mean a great deal to us. |
After an offline discussion, this is the "... or similar" part of the suggested feature set in this issue: #48703
This just relaxes front-end constraints as agreed for pinned array allocations with ref types, which is already possible and utilized internally.
The use case shortly is forming unmanaged references to array indices, where the array has a very long lifetime.
I added some extra coverage of the API, noticing the original constraint wasn't tested in the
System.Runtime
tests. I'm not sure if further documentation edits are necessary, or if it's fine to just remove the<remarks>
section.