private static unsafe void InitializeStatics(IntPtr gcStaticRegionStart, int length) { IntPtr gcStaticRegionEnd = (IntPtr)((byte *)gcStaticRegionStart + length); for (IntPtr *block = (IntPtr *)gcStaticRegionStart; block < (IntPtr *)gcStaticRegionEnd; block++) { // Gc Static regions can be shared by modules linked together during compilation. To ensure each // is initialized once, the static region pointer is stored with lowest bit set in the image. // The first time we initialize the static region its pointer is replaced with an object reference // whose lowest bit is no longer set. IntPtr *pBlock = (IntPtr *)*block; long blockAddr = (*pBlock).ToInt64(); if ((blockAddr & GCStaticRegionConstants.Uninitialized) == GCStaticRegionConstants.Uninitialized) { object obj = RuntimeImports.RhNewObject(new EETypePtr(new IntPtr(blockAddr & ~GCStaticRegionConstants.Mask))); if ((blockAddr & GCStaticRegionConstants.HasPreInitializedData) == GCStaticRegionConstants.HasPreInitializedData) { // The next pointer is preinitialized data blob that contains preinitialized static GC fields, // which are pointer relocs to GC objects in frozen segment. // It actually has all GC fields including non-preinitialized fields and we simply copy over the // entire blob to this object, overwriting everything. IntPtr pPreInitDataAddr = *(pBlock + 1); RuntimeImports.RhBulkMoveWithWriteBarrier(ref obj.GetRawData(), ref *(byte *)pPreInitDataAddr, obj.GetRawDataSize()); } *pBlock = RuntimeImports.RhHandleAlloc(obj, GCHandleType.Normal); } } }
internal static void Memmove <T>(ref T destination, ref T source, nuint elementCount) { if (!RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { // Blittable memmove Memmove( ref Unsafe.As <T, byte>(ref destination), ref Unsafe.As <T, byte>(ref source), elementCount * (nuint)Unsafe.SizeOf <T>()); } else { // Non-blittable memmove // Try to avoid calling RhBulkMoveWithWriteBarrier if we can get away // with a no-op. if (!Unsafe.AreSame(ref destination, ref source) && elementCount != 0) { RuntimeImports.RhBulkMoveWithWriteBarrier( ref Unsafe.As <T, byte>(ref destination), ref Unsafe.As <T, byte>(ref source), elementCount * (nuint)Unsafe.SizeOf <T>()); } } }
internal static void Memmove <T>(ref T destination, ref T source, nuint elementCount) { if (!RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { // Blittable memmove #if PROJECTN unsafe { fixed(byte *pDestination = &Unsafe.As <T, byte>(ref destination), pSource = &Unsafe.As <T, byte>(ref source)) Memmove(pDestination, pSource, elementCount * (nuint)Unsafe.SizeOf <T>()); } #else Memmove( new ByReference <byte>(ref Unsafe.As <T, byte>(ref destination)), new ByReference <byte>(ref Unsafe.As <T, byte>(ref source)), elementCount * (nuint)Unsafe.SizeOf <T>()); #endif } else { // Non-blittable memmove // Try to avoid calling RhBulkMoveWithWriteBarrier if we can get away // with a no-op. if (!Unsafe.AreSame(ref destination, ref source) && elementCount != 0) { RuntimeImports.RhBulkMoveWithWriteBarrier( ref Unsafe.As <T, byte>(ref destination), ref Unsafe.As <T, byte>(ref source), elementCount * (nuint)Unsafe.SizeOf <T>()); } } }
internal static unsafe void Memmove <T>(ref T destination, ref T source, nuint elementCount) { if (!RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { // Blittable memmove Memmove( ref Unsafe.As <T, byte>(ref destination), ref Unsafe.As <T, byte>(ref source), elementCount * (nuint)Unsafe.SizeOf <T>()); } else { // Non-blittable memmove RuntimeImports.RhBulkMoveWithWriteBarrier( ref Unsafe.As <T, byte>(ref destination), ref Unsafe.As <T, byte>(ref source), elementCount * (nuint)Unsafe.SizeOf <T>()); } }
internal static unsafe void CopyTo <T>(ref T destination, ref T source, int elementsCount) { if (Unsafe.AreSame(ref destination, ref source)) { return; } if (elementsCount <= 1) { if (elementsCount == 1) { destination = source; } return; } nuint byteCount = (nuint)elementsCount * (nuint)Unsafe.SizeOf <T>(); if (!RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { fixed(byte *pDestination = &Unsafe.As <T, byte>(ref destination)) { fixed(byte *pSource = &Unsafe.As <T, byte>(ref source)) { Buffer.Memmove(pDestination, pSource, byteCount); } } } else { RuntimeImports.RhBulkMoveWithWriteBarrier( ref Unsafe.As <T, byte>(ref destination), ref Unsafe.As <T, byte>(ref source), byteCount); } }
// Move memory which may be on the heap which may have object references in it. // In general, a memcpy on the heap is unsafe, but this is able to perform the // correct write barrier such that the GC is not incorrectly impacted. public static unsafe void BulkMoveWithWriteBarrier(IntPtr dmem, IntPtr smem, int size) { RuntimeImports.RhBulkMoveWithWriteBarrier(ref *(byte *)dmem.ToPointer(), ref *(byte *)smem.ToPointer(), (uint)size); }
internal static void BulkMoveWithWriteBarrier(ref byte dmem, ref byte smem, nuint size) => RuntimeImports.RhBulkMoveWithWriteBarrier(ref dmem, ref smem, size);