From a7403ba61dcdc9834489a8f3ea0b55afbcc2acdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Dec 2025 11:39:07 +0000 Subject: [PATCH 1/2] Add `CopyTo()` to `ReadOnlySpan` - Add implementation for this method. - Update declaration of mscorlib. --- src/CLR/CorLib/corlib_native.cpp | 5 +- src/CLR/CorLib/corlib_native.h | 1 + .../corlib_native_System_ReadOnlySpan_1.cpp | 53 ++++++++++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/CLR/CorLib/corlib_native.cpp b/src/CLR/CorLib/corlib_native.cpp index 116fa8e0a9..640b6d2149 100644 --- a/src/CLR/CorLib/corlib_native.cpp +++ b/src/CLR/CorLib/corlib_native.cpp @@ -702,6 +702,7 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + Library_corlib_native_System_ReadOnlySpan_1::CopyTo___VOID__SystemSpan_1, nullptr, nullptr, nullptr, @@ -1613,7 +1614,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib = #if (NANOCLR_REFLECTION == TRUE) - 0xF1828DE7, + 0x4619DD1E, #elif (NANOCLR_REFLECTION == FALSE) @@ -1624,7 +1625,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib = #endif method_lookup, - { 100, 22, 0, 0 } + { 100, 22, 0, 1 } }; // clang-format on diff --git a/src/CLR/CorLib/corlib_native.h b/src/CLR/CorLib/corlib_native.h index 733223ce5e..24feb42cd0 100644 --- a/src/CLR/CorLib/corlib_native.h +++ b/src/CLR/CorLib/corlib_native.h @@ -786,6 +786,7 @@ struct Library_corlib_native_System_ReadOnlySpan_1 static const int FIELD___length = 2; NANOCLR_NATIVE_DECLARE(_ctor___VOID__VOIDptr__I4); + NANOCLR_NATIVE_DECLARE(CopyTo___VOID__SystemSpan_1); NANOCLR_NATIVE_DECLARE(NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4); //--// diff --git a/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp index a87a3d6ebb..805f123a78 100644 --- a/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp @@ -7,6 +7,7 @@ #include "CorLib.h" typedef Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers RuntimeHelpers; +typedef Library_corlib_native_System_Span_1 Span_1; HRESULT Library_corlib_native_System_ReadOnlySpan_1::_ctor___VOID__VOIDptr__I4(CLR_RT_StackFrame &stack) { @@ -64,12 +65,11 @@ HRESULT Library_corlib_native_System_ReadOnlySpan_1::_ctor___VOID__VOIDptr__I4(C } // check if T is a reference type or contains references - NANOCLR_CHECK_HRESULT( - RuntimeHelpers::CheckReferenceOrContainsReferences( - element.Class, - element.DataType, - &parser, - isRefContainsRefs)); + NANOCLR_CHECK_HRESULT(RuntimeHelpers::CheckReferenceOrContainsReferences( + element.Class, + element.DataType, + &parser, + isRefContainsRefs)); if (isRefContainsRefs) { @@ -105,6 +105,47 @@ HRESULT Library_corlib_native_System_ReadOnlySpan_1::_ctor___VOID__VOIDptr__I4(C NANOCLR_NOCLEANUP(); } +HRESULT Library_corlib_native_System_ReadOnlySpan_1::CopyTo___VOID__SystemSpan_1(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + CLR_RT_HeapBlock_Array *sourceArray; + CLR_RT_HeapBlock_Array *destinationArray; + CLR_RT_HeapBlock *thisSpan = stack.This(); + CLR_RT_HeapBlock *destinationSpan = stack.Arg1().Dereference(); + + // check lengths - destination must be at least as large as source + if (thisSpan[FIELD___length].NumericByRefConst().u4 > + destinationSpan[Span_1::FIELD___length].NumericByRefConst().u4) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // get pointers to the arrays + sourceArray = thisSpan[FIELD___array].DereferenceArray(); + destinationArray = destinationSpan[Span_1::FIELD___array].DereferenceArray(); + + { + // sanity check for empty source array + if (thisSpan[FIELD___length].NumericByRefConst().s4 == 0) + { + NANOCLR_SET_AND_LEAVE(S_OK); + } + + // prevent GC from moving the arrays while we copy the data + CLR_RT_ProtectFromGC gc1(*sourceArray); + CLR_RT_ProtectFromGC gc2(*destinationArray); + + // use memmove to safely handle potential overlapping memory regions + memmove( + destinationArray->GetElement(0), + sourceArray->GetElement(0), + thisSpan[FIELD___length].NumericByRefConst().s4 * sourceArray->m_sizeOfElement); + } + + NANOCLR_NOCLEANUP(); +} + HRESULT Library_corlib_native_System_ReadOnlySpan_1::NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4( CLR_RT_StackFrame &stack) { From 5d1181e973253af792834829ab0c592b8807254d Mon Sep 17 00:00:00 2001 From: nfbot Date: Fri, 12 Dec 2025 11:43:14 +0000 Subject: [PATCH 2/2] Code style fixes Automated fixes for code style. --- .../CorLib/corlib_native_System_ReadOnlySpan_1.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp index 805f123a78..00b34c16b5 100644 --- a/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp @@ -65,11 +65,12 @@ HRESULT Library_corlib_native_System_ReadOnlySpan_1::_ctor___VOID__VOIDptr__I4(C } // check if T is a reference type or contains references - NANOCLR_CHECK_HRESULT(RuntimeHelpers::CheckReferenceOrContainsReferences( - element.Class, - element.DataType, - &parser, - isRefContainsRefs)); + NANOCLR_CHECK_HRESULT( + RuntimeHelpers::CheckReferenceOrContainsReferences( + element.Class, + element.DataType, + &parser, + isRefContainsRefs)); if (isRefContainsRefs) {