From 9ea544dd11cf4064b4af8639c30e421ca264d8bf Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Mon, 15 Jun 2020 15:18:14 -0400 Subject: [PATCH] Move the Buffer.Memmove implementation into the runtime specific files since it requires a runtime specific BulkMoveWithWriteBarrier icall. The mono version has an extra type argument since it uses copy functions which are type specific. Also add an elementCount > 0 check to avoid icall overhead if possible. --- .../src/System/Buffer.CoreCLR.cs | 23 +++++++++++++++++ .../src/System/Buffer.cs | 23 ----------------- src/mono/mono/metadata/icall-decl.h | 2 +- src/mono/mono/metadata/icall-def-netcore.h | 2 +- src/mono/mono/metadata/icall.c | 7 ++++-- .../src/System/Buffer.Mono.cs | 25 ++++++++++++++++++- 6 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs index 5e1d8249e3ddda..36f6c0b9ba0f47 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs @@ -101,5 +101,28 @@ internal static unsafe void Memcpy(byte* pDest, int destIndex, byte[] src, int s Memcpy(pDest + destIndex, pSrc + srcIndex, len); } } + + // This method has different signature for x64 and other platforms and is done for performance reasons. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Memmove(ref T destination, ref T source, nuint elementCount) + { + if (!RuntimeHelpers.IsReferenceOrContainsReferences()) + { + // Blittable memmove + + Memmove( + ref Unsafe.As(ref destination), + ref Unsafe.As(ref source), + elementCount * (nuint)Unsafe.SizeOf()); + } + else + { + // Non-blittable memmove + BulkMoveWithWriteBarrier( + ref Unsafe.As(ref destination), + ref Unsafe.As(ref source), + elementCount * (nuint)Unsafe.SizeOf()); + } + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs index 3880d590ca4ce0..121981b9ae3498 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs @@ -305,29 +305,6 @@ internal static unsafe void Memmove(byte* dest, byte* src, nuint len) _Memmove(dest, src, len); } - // This method has different signature for x64 and other platforms and is done for performance reasons. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void Memmove(ref T destination, ref T source, nuint elementCount) - { - if (!RuntimeHelpers.IsReferenceOrContainsReferences()) - { - // Blittable memmove - - Memmove( - ref Unsafe.As(ref destination), - ref Unsafe.As(ref source), - elementCount * (nuint)Unsafe.SizeOf()); - } - else - { - // Non-blittable memmove - BulkMoveWithWriteBarrier( - ref Unsafe.As(ref destination), - ref Unsafe.As(ref source), - elementCount * (nuint)Unsafe.SizeOf()); - } - } - // This method has different signature for x64 and other platforms and is done for performance reasons. private static void Memmove(ref byte dest, ref byte src, nuint len) { diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index e018529df17936..1bb8ab1cfa67db 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -183,7 +183,7 @@ ICALL_EXPORT void ves_icall_System_IO_LogcatTextWriter_Log (const char*, gint32, ICALL_EXPORT void ves_icall_System_NumberFormatter_GetFormatterTables (guint64 const**, gint32 const**, gunichar2 const**, gunichar2 const**, gint64 const**, gint32 const**); #if ENABLE_NETCORE ICALL_EXPORT void ves_icall_System_Runtime_RuntimeImports_Memmove (guint8*, guint8*, size_t); -ICALL_EXPORT void ves_icall_System_Runtime_RuntimeImports_RhBulkMoveWithWriteBarrier (guint8*, guint8*, size_t); +ICALL_EXPORT void ves_icall_System_Buffer_BulkMoveWithWriteBarrier (guint8 *, guint8 *, size_t, MonoType *); #else ICALL_EXPORT void ves_icall_System_Runtime_RuntimeImports_Memmove (guint8*, guint8*, guint); ICALL_EXPORT void ves_icall_System_Runtime_RuntimeImports_Memmove_wbarrier (guint8*, guint8*, guint, MonoType*); diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 9206bebfc8347c..ee55fbbc7fc291 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -53,7 +53,7 @@ HANDLES(ARRAY_13, "SetValueImpl", ves_icall_System_Array_SetValueImpl, void, 3, HANDLES(ARRAY_14, "SetValueRelaxedImpl", ves_icall_System_Array_SetValueRelaxedImpl, void, 3, (MonoArray, MonoObject, guint32)) ICALL_TYPE(BUFFER, "System.Buffer", BUFFER_0) -NOHANDLES(ICALL(BUFFER_0, "BulkMoveWithWriteBarrier", ves_icall_System_Runtime_RuntimeImports_RhBulkMoveWithWriteBarrier)) +NOHANDLES(ICALL(BUFFER_0, "BulkMoveWithWriteBarrier", ves_icall_System_Buffer_BulkMoveWithWriteBarrier)) NOHANDLES(ICALL(BUFFER_2, "__Memmove", ves_icall_System_Runtime_RuntimeImports_Memmove)) NOHANDLES(ICALL(BUFFER_3, "__ZeroMemory", ves_icall_System_Runtime_RuntimeImports_ZeroMemory)) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 61930a68ef0935..dc69ca08ab3130 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -1156,9 +1156,12 @@ ves_icall_System_Runtime_RuntimeImports_Memmove (guint8 *destination, guint8 *so #if ENABLE_NETCORE void -ves_icall_System_Runtime_RuntimeImports_RhBulkMoveWithWriteBarrier (guint8 *destination, guint8 *source, size_t byte_count) +ves_icall_System_Buffer_BulkMoveWithWriteBarrier (guint8 *destination, guint8 *source, size_t len, MonoType *type) { - mono_gc_wbarrier_range_copy (destination, source, byte_count); + if (MONO_TYPE_IS_REFERENCE (type)) + mono_gc_wbarrier_arrayref_copy_internal (destination, source, (guint)len); + else + mono_gc_wbarrier_value_copy_internal (destination, source, (guint)len, mono_class_from_mono_type_internal (type)); } #else void diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs index 6f04b9742a55a2..acf5597198f469 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Runtime.CompilerServices; +using Internal.Runtime.CompilerServices; namespace System { @@ -14,7 +15,7 @@ public partial class Buffer private static extern unsafe void __Memmove(byte* dest, byte* src, nuint len); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void BulkMoveWithWriteBarrier(ref byte dmem, ref byte smem, nuint size); + private static extern void BulkMoveWithWriteBarrier(ref byte dmem, ref byte smem, nuint len, IntPtr type_handle); [MethodImpl(MethodImplOptions.NoInlining)] internal static unsafe void _ZeroMemory(ref byte b, nuint byteLength) @@ -27,5 +28,27 @@ internal static unsafe void _ZeroMemory(ref byte b, nuint byteLength) [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe void __ZeroMemory(void* p, nuint byteLength); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void Memmove(ref T destination, ref T source, nuint elementCount) + { + if (!RuntimeHelpers.IsReferenceOrContainsReferences()) + { + // Blittable memmove + Memmove( + ref Unsafe.As(ref destination), + ref Unsafe.As(ref source), + elementCount * (nuint)Unsafe.SizeOf()); + } + else if (elementCount > 0) + { + // Non-blittable memmove + BulkMoveWithWriteBarrier( + ref Unsafe.As(ref destination), + ref Unsafe.As(ref source), + elementCount, + typeof(T).TypeHandle.Value); + } + } } }