-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
This is extracted out of a discussion whose salient points are #51534 (comment) and #51534 (comment).
In a nutshell, when the JIT sees an initobj instruction, it will attempt to perform SIMD writes to the destination address, This is true whether or not the target type contains gcrefs. See the below example for a demonstration.
using System;
public class C {
internal struct MyStruct
{
object _data0;
object _data1;
}
internal class MyClass1
{
MyStruct _s;
void Clear()
{
_s = default;
}
}
internal class MyClass2
{
object _dataX;
MyStruct _s;
void Clear()
{
_s = default;
}
}
}; Core CLR v5.0.421.11614 on amd64
MyClass1.Clear()
L0000: vzeroupper
L0003: vxorps xmm0, xmm0, xmm0
L0007: vmovdqu [rcx+8], xmm0
L000c: ret
MyClass2.Clear()
L0000: vzeroupper
L0003: vxorps xmm0, xmm0, xmm0
L0007: vmovdqu [rcx+0x10], xmm0
L000c: retIn this example, references to MyStruct are only guaranteed 8-byte aligned, not 16-byte aligned. So it's possible that the vmovdqu instruction could straddle a cache line boundary or a page boundary. The implicit assumption here is that even if the SIMD write as a whole is not atomic, each individual native word-sized element of the vector is published atomically (since the target address is native word-aligned).
Per #51534 (comment), this assumption is valid for ARM64. But per #51534 (comment), this assumption might not be valid for x86 / x64 / ARM32.
So, the larger question: is the current JIT behavior legal such that no other thread will ever see a torn write to a gcref field, or is the JIT relying on undocumented behavior? And if we're relying on a potentially invalid assumption, do we need to change our behavior?