Cleanup memory copy helpers (dotnet/coreclr#27307)
authorJan Kotas <jkotas@microsoft.com>
Mon, 21 Oct 2019 16:32:30 +0000 (09:32 -0700)
committerGitHub <noreply@github.com>
Mon, 21 Oct 2019 16:32:30 +0000 (09:32 -0700)
- Merge RuntimeImports that has just a few FCalls into Buffer.
- Delete assembly implementation of memcpy for ARM. The implementation was outdated and it was used only on Windows ARM and only for fraction of memcpy callsites.
- Delete unnecessary PInvoke into SysStringLen. We have a managed equivalent on System.Runtime.InteropServices.Marshal.
- Delete large amount of redundant code between SecureString.Windows.cs and SecureString.Unix.cs, and switch SecureString to use Spans
- Fold null check into IsWin32Atom

Commit migrated from https://github.com/dotnet/coreclr/commit/17cbbeeac4c6e455d6fd34be22f38ef1f1f49834

31 files changed:
src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj
src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs
src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs
src/coreclr/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs [deleted file]
src/coreclr/src/pal/inc/rt/palrt.h
src/coreclr/src/vm/CMakeLists.txt
src/coreclr/src/vm/arm/cgencpu.h
src/coreclr/src/vm/arm/memcpy.S [deleted file]
src/coreclr/src/vm/arm/memcpy.asm [deleted file]
src/coreclr/src/vm/arm/memcpy_crt.asm [deleted file]
src/coreclr/src/vm/comutilnative.cpp
src/coreclr/src/vm/comutilnative.h
src/coreclr/src/vm/ecalllist.h
src/coreclr/src/vm/excep.cpp
src/coreclr/src/vm/jithelpers.cpp
src/libraries/System.Private.CoreLib/src/Interop/Windows/Crypt32/Interop.CryptProtectMemory.cs
src/libraries/System.Private.CoreLib/src/Interop/Windows/OleAut32/Interop.SysAllocStringLen.cs
src/libraries/System.Private.CoreLib/src/Interop/Windows/OleAut32/Interop.SysStringLen.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/Buffer.cs
src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs
src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Unix.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
src/libraries/System.Private.CoreLib/src/System/Security/SafeBSTRHandle.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System/Security/SecureString.Unix.cs
src/libraries/System.Private.CoreLib/src/System/Security/SecureString.Windows.cs
src/libraries/System.Private.CoreLib/src/System/Security/SecureString.cs
src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs
src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs

index ca3624d..d4e5265 100644 (file)
     <Compile Include="$(CommonPath)\NotImplemented.cs" />
     <Compile Include="$(CommonPath)\System\SR.cs" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="src\System\Runtime\RuntimeImports.cs" />
-  </ItemGroup>
   <Import Project="shared\System.Private.CoreLib.Shared.projitems" />
   <PropertyGroup>
     <CheckCDefines Condition="'$(CheckCDefines)'==''">true</CheckCDefines>
index b4878dc..7675da8 100644 (file)
@@ -23,26 +23,31 @@ namespace System
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern bool IsPrimitiveTypeArray(Array array);
 
-        // This method has a slightly different behavior on arm and other platforms.
-        // On arm this method behaves like memcpy and does not handle overlapping buffers.
-        // While on other platforms it behaves like memmove and handles overlapping buffers.
-        // This behavioral difference is unfortunate but intentional because
-        // 1. This method is given access to other internal dlls and this close to release we do not want to change it.
-        // 2. It is difficult to get this right for arm and again due to release dates we would like to visit it later.
-#if ARM
+        // Non-inlinable wrapper around the QCall that avoids polluting the fast path
+        // with P/Invoke prolog/epilog.
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        internal static unsafe void _ZeroMemory(ref byte b, nuint byteLength)
+        {
+            fixed (byte* bytePointer = &b)
+            {
+                __ZeroMemory(bytePointer, byteLength);
+            }
+        }
+
+        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+        private static extern unsafe void __ZeroMemory(void* b, nuint byteLength);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern unsafe void Memcpy(byte* dest, byte* src, int len);
-#else // ARM
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal static extern void BulkMoveWithWriteBarrier(ref byte destination, ref byte source, nuint byteCount);
+
+        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+        private static extern unsafe void __Memmove(byte* dest, byte* src, nuint len);
+
         internal static unsafe void Memcpy(byte* dest, byte* src, int len)
         {
             Debug.Assert(len >= 0, "Negative length in memcpy!");
             Memmove(dest, src, (nuint)len);
         }
-#endif // ARM
-
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        private static extern unsafe void __Memmove(byte* dest, byte* src, nuint len);
 
         // Used by ilmarshalers.cpp
         internal static unsafe void Memcpy(byte* pDest, int destIndex, byte[] src, int srcIndex, int len)
index aa11b8e..34dd7c9 100644 (file)
@@ -275,7 +275,7 @@ namespace System.Runtime.InteropServices
 
         public static void FreeHGlobal(IntPtr hglobal)
         {
-            if (!IsWin32Atom(hglobal))
+            if (!IsNullOrWin32Atom(hglobal))
             {
                 if (IntPtr.Zero != Interop.Kernel32.LocalFree(hglobal))
                 {
@@ -419,7 +419,7 @@ namespace System.Runtime.InteropServices
 
         public static void FreeCoTaskMem(IntPtr ptr)
         {
-            if (!IsWin32Atom(ptr))
+            if (!IsNullOrWin32Atom(ptr))
             {
                 Interop.Ole32.CoTaskMemFree(ptr);
             }
@@ -448,7 +448,7 @@ namespace System.Runtime.InteropServices
 
         public static void FreeBSTR(IntPtr ptr)
         {
-            if (!IsWin32Atom(ptr))
+            if (!IsNullOrWin32Atom(ptr))
             {
                 Interop.OleAut32.SysFreeString(ptr);
             }
@@ -461,12 +461,6 @@ namespace System.Runtime.InteropServices
                 return IntPtr.Zero;
             }
 
-            // Overflow checking
-            if (s.Length + 1 < s.Length)
-            {
-                throw new ArgumentOutOfRangeException(nameof(s));
-            }
-
             IntPtr bstr = Interop.OleAut32.SysAllocStringLen(s, s.Length);
             if (bstr == IntPtr.Zero)
             {
@@ -478,7 +472,12 @@ namespace System.Runtime.InteropServices
 
         public static string PtrToStringBSTR(IntPtr ptr)
         {
-            return PtrToStringUni(ptr, (int)Interop.OleAut32.SysStringLen(ptr));
+            if (ptr == IntPtr.Zero)
+            {
+                throw new ArgumentNullException(nameof(ptr));
+            }
+
+            return PtrToStringUni(ptr, (int)(SysStringByteLen(ptr) / sizeof(char)));
         }
 
 #if FEATURE_COMINTEROP
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
deleted file mode 100644 (file)
index 1574812..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
-#if BIT64
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
-namespace System.Runtime
-{
-    public class RuntimeImports
-    {
-        // Non-inlinable wrapper around the QCall that avoids poluting the fast path
-        // with P/Invoke prolog/epilog.
-        [MethodImpl(MethodImplOptions.NoInlining)]
-        internal static unsafe void RhZeroMemory(ref byte b, nuint byteLength)
-        {
-            fixed (byte* bytePointer = &b)
-            {
-                RhZeroMemory(bytePointer, byteLength);
-            }
-        }
-
-        internal static unsafe void RhZeroMemory(IntPtr p, UIntPtr byteLength)
-        {
-            RhZeroMemory((void*)p, (nuint)byteLength);
-        }
-
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        private static extern unsafe void RhZeroMemory(void* b, nuint byteLength);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void RhBulkMoveWithWriteBarrier(ref byte destination, ref byte source, nuint byteCount);
-    }
-}
index 54e5ad7..913a8c1 100644 (file)
@@ -714,34 +714,8 @@ typedef unsigned int ALG_ID;
 
 /******************* NLS ****************************************/
 
-typedef 
-enum tagMIMECONTF {
-    MIMECONTF_MAILNEWS  = 0x1,
-    MIMECONTF_BROWSER   = 0x2,
-    MIMECONTF_MINIMAL   = 0x4,
-    MIMECONTF_IMPORT    = 0x8,
-    MIMECONTF_SAVABLE_MAILNEWS  = 0x100,
-    MIMECONTF_SAVABLE_BROWSER   = 0x200,
-    MIMECONTF_EXPORT    = 0x400,
-    MIMECONTF_PRIVCONVERTER = 0x10000,
-    MIMECONTF_VALID = 0x20000,
-    MIMECONTF_VALID_NLS = 0x40000,
-    MIMECONTF_MIME_IE4  = 0x10000000,
-    MIMECONTF_MIME_LATEST   = 0x20000000,
-    MIMECONTF_MIME_REGISTRY = 0x40000000
-    }   MIMECONTF;
-
 #define LCMAP_LOWERCASE           0x00000100
 #define LCMAP_UPPERCASE           0x00000200
-#define LCMAP_SORTKEY             0x00000400
-#define LCMAP_BYTEREV             0x00000800
-
-#define LCMAP_HIRAGANA            0x00100000
-#define LCMAP_KATAKANA            0x00200000
-#define LCMAP_HALFWIDTH           0x00400000
-#define LCMAP_FULLWIDTH           0x00800000
-
-#define LCMAP_LINGUISTIC_CASING   0x01000000
 
 // 8 characters for language
 // 8 characters for region
@@ -751,23 +725,10 @@ enum tagMIMECONTF {
 // 1 null termination
 #define LOCALE_NAME_MAX_LENGTH   85
 
-#define LOCALE_SCOUNTRY           0x00000006
-#define LOCALE_SENGCOUNTRY        0x00001002
-
-#define LOCALE_SLANGUAGE          0x00000002
-#define LOCALE_SENGLANGUAGE       0x00001001
-
-#define LOCALE_SDATE              0x0000001D
-#define LOCALE_STIME              0x0000001E
-
 #define CSTR_LESS_THAN            1
 #define CSTR_EQUAL                2
 #define CSTR_GREATER_THAN         3
 
-#define NORM_IGNORENONSPACE       0x00000002
-
-#define WC_COMPOSITECHECK         0x00000000 // NOTE: diff from winnls.h
-
 /******************* shlwapi ************************************/
 
 // note: diff in NULL handing and calling convetion
index ed72c94..cebf370 100644 (file)
@@ -686,7 +686,6 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM)
         ${ARCH_SOURCES_DIR}/asmhelpers.asm
         ${ARCH_SOURCES_DIR}/CrtHelpers.asm
         ${ARCH_SOURCES_DIR}/ehhelpers.asm
-        ${ARCH_SOURCES_DIR}/memcpy.asm
         ${ARCH_SOURCES_DIR}/patchedcode.asm
         ${ARCH_SOURCES_DIR}/PInvokeStubs.asm
     )
@@ -740,7 +739,6 @@ else(WIN32)
             ${ARCH_SOURCES_DIR}/asmhelpers.S
             ${ARCH_SOURCES_DIR}/crthelpers.S
             ${ARCH_SOURCES_DIR}/ehhelpers.S
-            ${ARCH_SOURCES_DIR}/memcpy.S
             ${ARCH_SOURCES_DIR}/patchedcode.S
             ${ARCH_SOURCES_DIR}/pinvokestubs.S
         )
index 95c68cc..61ba2ab 100644 (file)
@@ -1366,6 +1366,4 @@ inline size_t GetARMInstructionLength(PBYTE pInstr)
     return GetARMInstructionLength(*(WORD*)pInstr);
 }
 
-EXTERN_C void FCallMemcpy(BYTE* dest, BYTE* src, int len);
-
 #endif // __cgencpu_h__
diff --git a/src/coreclr/src/vm/arm/memcpy.S b/src/coreclr/src/vm/arm/memcpy.S
deleted file mode 100644 (file)
index 0c2c26e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#include "unixasmmacros.inc"
-#include "asmconstants.h"
-
-.syntax unified
-.thumb
-
-//
-// void *memcpy(void *dst, const void *src, size_t length)
-//
-// Copy a block of memory in a forward direction.
-//
-
-    NESTED_ENTRY FCallMemcpy, _TEXT, NoHandler
-        cmp r2, #0
-        
-        beq LOCAL_LABEL(GC_POLL)
-
-        PROLOG_PUSH  "{r7, lr}"
-        PROLOG_STACK_SAVE r7
-        
-        ldrb r3, [r0]
-        ldrb r3, [r1]
-        
-        blx C_FUNC(memcpy)
-
-        EPILOG_POP   "{r7, pc}"
-
-LOCAL_LABEL(GC_POLL):
-        ldr r0, =g_TrapReturningThreads
-        ldr r0, [r0]
-        cmp r0, #0
-        it ne
-        bne C_FUNC(FCallMemCpy_GCPoll)
-        bx lr
-    NESTED_END_MARKED FCallMemcpy, _TEXT
diff --git a/src/coreclr/src/vm/arm/memcpy.asm b/src/coreclr/src/vm/arm/memcpy.asm
deleted file mode 100644 (file)
index 9a0e7d3..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-; Licensed to the .NET Foundation under one or more agreements.
-; The .NET Foundation licenses this file to you under the MIT license.
-; See the LICENSE file in the project root for more information.
-
-;
-
-;
-
-; This is the fast memcpy implementation for ARM stolen from the CRT (original location 
-; vctools\crt\crtw32\string\arm\memcpy.asm) and modified to be compatible with CLR.
-;
-; For reference, the unmodified crt version of memcpy is preserved as memcpy_crt.asm
-
-#include "ksarm.h"
-#include "asmmacros.h"
-
-        IMPORT FCallMemCpy_GCPoll
-        IMPORT g_TrapReturningThreads
-
-        AREA    |.text|,ALIGN=5,CODE,READONLY
-
-;
-; void *memcpy(void *dst, const void *src, size_t length)
-;
-; Copy a block of memory in a forward direction.
-;
-
-        ALIGN 32
-        LEAF_ENTRY FCallMemcpy
-
-        pld     [r1]                                    ; preload the first cache line
-        cmp     r2, #16                                 ; less than 16 bytes?
-        mov     r3, r0                                  ; use r3 as our destination
-        bhs.W     __FCallMemcpy_large                   ; go to the large copy case directly. ".W" indicates encoding using 32bits
-
-CpySmal tbb     [pc, r2]                                ; branch to specialized bits for small copies
-__SwitchTable1_Copy
-CTable  dcb     (Copy0 - CTable) / 2                    ; 0B
-        dcb     (Copy1 - CTable) / 2                    ; 1B
-        dcb     (Copy2 - CTable) / 2                    ; 2B
-        dcb     (Copy3 - CTable) / 2                    ; 3B
-        dcb     (Copy4 - CTable) / 2                    ; 4B
-        dcb     (Copy5 - CTable) / 2                    ; 5B
-        dcb     (Copy6 - CTable) / 2                    ; 6B
-        dcb     (Copy7 - CTable) / 2                    ; 7B
-        dcb     (Copy8 - CTable) / 2                    ; 8B
-        dcb     (Copy9 - CTable) / 2                    ; 9B
-        dcb     (Copy10 - CTable) / 2                   ; 10B
-        dcb     (Copy11 - CTable) / 2                   ; 11B
-        dcb     (Copy12 - CTable) / 2                   ; 12B
-        dcb     (Copy13 - CTable) / 2                   ; 13B
-        dcb     (Copy14 - CTable) / 2                   ; 14B
-        dcb     (Copy15 - CTable) / 2                   ; 15B
-__SwitchTableEnd_Copy
-
-Copy1   ldrb    r2, [r1]
-        strb    r2, [r3]
-Copy0   b       GC_POLL
-
-Copy2   ldrh    r2, [r1]
-        strh    r2, [r3]
-        b       GC_POLL
-
-Copy3   ldrh    r2, [r1]
-        ldrb    r1, [r1, #2]
-        strh    r2, [r3]
-        strb    r1, [r3, #2]
-        b       GC_POLL
-
-Copy4   ldr     r2, [r1]
-        str     r2, [r3]
-        b       GC_POLL
-
-Copy5   ldr     r2, [r1]
-        ldrb    r1, [r1, #4]
-        str     r2, [r3]
-        strb    r1, [r3, #4]
-        b       GC_POLL
-
-Copy6   ldr     r2, [r1]
-        ldrh    r1, [r1, #4]
-        str     r2, [r3]
-        strh    r1, [r3, #4]
-        b       GC_POLL
-
-Copy7   ldr     r12, [r1]
-        ldrh    r2, [r1, #4]
-        ldrb    r1, [r1, #6]
-        str     r12, [r3]
-        strh    r2, [r3, #4]
-        strb    r1, [r3, #6]
-        b       GC_POLL
-
-Copy8   ldr     r2, [r1]
-        ldr     r1, [r1, #4]
-        str     r2, [r3]
-        str     r1, [r3, #4]
-        b       GC_POLL
-
-Copy9   ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldrb    r1, [r1, #8]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        strb    r1, [r3, #8]
-        b       GC_POLL
-
-Copy10  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldrh    r1, [r1, #8]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        strh    r1, [r3, #8]
-        b       GC_POLL
-
-Copy11  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldrh    r2, [r1, #8]
-        ldrb    r1, [r1, #10]
-        strh    r2, [r3, #8]
-        strb    r1, [r3, #10]
-        b       GC_POLL
-
-Copy12  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldr     r1, [r1, #8]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        str     r1, [r3, #8]
-        b       GC_POLL
-
-Copy13  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldr     r2, [r1, #8]
-        ldrb    r1, [r1, #12]
-        str     r2, [r3, #8]
-        strb    r1, [r3, #12]
-        b       GC_POLL
-
-Copy14  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldr     r2, [r1, #8]
-        ldrh    r1, [r1, #12]
-        str     r2, [r3, #8]
-        strh    r1, [r3, #12]
-        b       GC_POLL
-
-Copy15  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldr     r12, [r1, #8]
-        ldrh    r2, [r1, #12]
-        ldrb    r1, [r1, #14]
-        str     r12, [r3, #8]
-        strh    r2, [r3, #12]
-        strb    r1, [r3, #14]
-GC_POLL
-        ldr     r0, =g_TrapReturningThreads
-        ldr     r0, [r0]
-        cmp     r0, #0
-        bne     FCallMemCpy_GCPoll
-
-        bx      lr
-
-        LEAF_END FCallMemcpy
-
-
-;
-; __memcpy_forward_large_integer (internal calling convention)
-;
-; Copy large (>= 16 bytes) blocks of memory in a forward direction,
-; using integer registers only.
-;
-
-        ALIGN 32
-        NESTED_ENTRY __FCallMemcpy_large
-        
-        PROLOG_NOP lsls r12, r3, #31                    ; C = bit 1, N = bit 0
-        PROLOG_PUSH {r4-r9, r11, lr}
-
-;
-; Align destination to a word boundary
-;
-
-        bpl     %F1
-        ldrb    r4, [r1], #1                            ; fetch byte
-        subs    r2, r2, #1                              ; decrement count
-        strb    r4, [r3], #1                            ; store byte
-        lsls    r12, r3, #31                            ; compute updated status
-1
-        bcc     %F2                                     ; if already aligned, just skip ahead
-        ldrh    r4, [r1], #2                            ; fetch halfword
-        subs    r2, r2, #2                              ; decrement count
-        strh    r4, [r3], #2                            ; store halfword
-2
-        tst     r1, #3                                  ; is the source now word-aligned?
-        bne     %F20                                    ; if not, we have to use the slow path
-
-;
-; Source is word-aligned; fast case
-;
-
-10
-        subs    r2, r2, #32                             ; take 32 off the top
-        blo     %F13                                    ; if not enough, recover and do small copies
-        subs    r2, r2, #32                             ; take off another 32
-        pld     [r1, #32]                               ; pre-load one block ahead
-        blo     %F12                                    ; skip the loop if that's all we have
-11
-        pld     [r1, #64]                               ; prefetch ahead
-        subs    r2, r2, #32                             ; count the bytes for this block
-        ldm     r1!, {r4-r9, r12, lr}                   ; load 32 bytes
-        stm     r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-        bhs     %B11                                    ; keep going until we're done
-12
-        ldm     r1!, {r4-r9, r12, lr}                   ; load 32 bytes
-        stm     r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-13
-        adds    r2, r2, #(32 - 8)                       ; recover original count, and pre-decrement
-        blo     %F15                                    ; if not enough remaining, skip this loop
-14 
-        subs    r2, r2, #8                              ; decrement count
-        ldrd    r4, r5, [r1], #8                        ; fetch pair of words
-        strd    r4, r5, [r3], #8                        ; store pair of words
-        bhs     %B14                                    ; loop while we still have data remaining
-15
-        adds    r2, r2, #8                              ; recover final count
-
-        EPILOG_POP {r4-r9, r11, lr}
-        EPILOG_NOP bne CpySmal                          ; if some left, continue with small
-        EPILOG_BRANCH GC_POLL
-
-;
-; Source is not word-aligned; slow case
-;
-
-20
-        subs    r2, r2, #64                             ; pre-decrement to simplify the loop
-        blo     %23                                     ; skip over the loop if we don't have enough
-        pld     [r1, #32]                               ; pre-load one block ahead
-21
-        pld     [r1, #64]                               ; prefetch ahead
-        ldr     r4, [r1, #0]                            ; load 32 bytes
-        ldr     r5, [r1, #4]                            ;
-        ldr     r6, [r1, #8]                            ;
-        ldr     r7, [r1, #12]                           ;
-        ldr     r8, [r1, #16]                           ;
-        ldr     r9, [r1, #20]                           ;
-        ldr     r12, [r1, #24]                          ;
-        ldr     lr, [r1, #28]                           ;
-        adds    r1, r1, #32                             ; update pointer
-        subs    r2, r2, #32                             ; count the bytes for this block
-        stm     r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-        bhs     %B21                                    ; keep going until we're done
-23
-        adds    r2, r2, #(64 - 8)                       ; recover original count, and pre-decrement
-        blo     %F25                                    ; if not enough remaining, skip this loop
-24
-        ldr     r4, [r1]                                ; fetch pair of words
-        ldr     r5, [r1, #4]                            ;
-        adds    r1, r1, #8                              ; update pointer
-        subs    r2, r2, #8                              ; decrement count
-        strd    r4, r5, [r3], #8                        ; store pair of words
-        bhs     %B24                                    ; loop while we still have data remaining
-25
-        adds    r2, r2, #8                              ; recover final count
-
-        EPILOG_POP {r4-r9, r11, lr}
-        EPILOG_NOP bne CpySmal                          ; if some left, continue with small
-        EPILOG_BRANCH GC_POLL
-
-        EXPORT FCallMemcpy_End                          ; this is used to place the entire 
-FCallMemcpy_End                                         ; implementation in av-exclusion list
-
-        NESTED_END __FCallMemcpy_large
-
-        END
diff --git a/src/coreclr/src/vm/arm/memcpy_crt.asm b/src/coreclr/src/vm/arm/memcpy_crt.asm
deleted file mode 100644 (file)
index 5e3a97e..0000000
+++ /dev/null
@@ -1,1001 +0,0 @@
-; Licensed to the .NET Foundation under one or more agreements.
-; The .NET Foundation licenses this file to you under the MIT license.
-; See the LICENSE file in the project root for more information.
-
-;
-
-;
-
-#include "ksarm.h"
-
-#if !defined PF_ARM_EXTERNAL_CACHE_AVAILABLE
-#define PF_ARM_EXTERNAL_CACHE_AVAILABLE 0x1a
-#endif
-
-#if !defined(_BOOTCRT_)
-
-        DATAAREA
-
-__memcpy_forward_large_func dcd __memcpy_decide
-        EXPORT __memcpy_forward_large_func
-__memcpy_reverse_large_func dcd __memcpy_decide
-        EXPORT __memcpy_reverse_large_func
-
-#endif
-
-        AREA    |.text|,ALIGN=5,CODE,READONLY
-
-;
-; void *memcpy(void *dst, const void *src, size_t length)
-;
-; Copy a block of memory in a forward direction.
-;
-
-        ALIGN 32
-        LEAF_ENTRY memcpy
-
-        ALTERNATE_ENTRY __memcpy_forward_new
-        
-        pld     [r1]                                    ; preload the first cache line
-        cmp     r2, #16                                 ; less than 16 bytes?
-        mov     r3, r0                                  ; use r3 as our destination
-        bhs     CpyLrge                                 ; go to the small copy case directly
-
-CpySmal tbb     [pc, r2]                                ; branch to specialized bits for small copies
-__SwitchTable1_Copy
-CTable  dcb     (Copy0 - CTable) / 2                    ; 0B
-        dcb     (Copy1 - CTable) / 2                    ; 1B
-        dcb     (Copy2 - CTable) / 2                    ; 2B
-        dcb     (Copy3 - CTable) / 2                    ; 3B
-        dcb     (Copy4 - CTable) / 2                    ; 4B
-        dcb     (Copy5 - CTable) / 2                    ; 5B
-        dcb     (Copy6 - CTable) / 2                    ; 6B
-        dcb     (Copy7 - CTable) / 2                    ; 7B
-        dcb     (Copy8 - CTable) / 2                    ; 8B
-        dcb     (Copy9 - CTable) / 2                    ; 9B
-        dcb     (Copy10 - CTable) / 2                   ; 10B
-        dcb     (Copy11 - CTable) / 2                   ; 11B
-        dcb     (Copy12 - CTable) / 2                   ; 12B
-        dcb     (Copy13 - CTable) / 2                   ; 13B
-        dcb     (Copy14 - CTable) / 2                   ; 14B
-        dcb     (Copy15 - CTable) / 2                   ; 15B
-__SwitchTableEnd_Copy
-
-Copy1   ldrb    r2, [r1]
-        strb    r2, [r3]
-Copy0   bx      lr
-
-Copy2   ldrh    r2, [r1]
-        strh    r2, [r3]
-        bx      lr
-
-Copy3   ldrh    r2, [r1]
-        ldrb    r1, [r1, #2]
-        strh    r2, [r3]
-        strb    r1, [r3, #2]
-        bx      lr
-
-Copy4   ldr     r2, [r1]
-        str     r2, [r3]
-        bx      lr
-
-Copy5   ldr     r2, [r1]
-        ldrb    r1, [r1, #4]
-        str     r2, [r3]
-        strb    r1, [r3, #4]
-        bx      lr
-
-Copy6   ldr     r2, [r1]
-        ldrh    r1, [r1, #4]
-        str     r2, [r3]
-        strh    r1, [r3, #4]
-        bx      lr
-
-Copy7   ldr     r12, [r1]
-        ldrh    r2, [r1, #4]
-        ldrb    r1, [r1, #6]
-        str     r12, [r3]
-        strh    r2, [r3, #4]
-        strb    r1, [r3, #6]
-        bx      lr
-
-Copy8   ldr     r2, [r1]
-        ldr     r1, [r1, #4]
-        str     r2, [r3]
-        str     r1, [r3, #4]
-        bx      lr
-
-Copy9   ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldrb    r1, [r1, #8]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        strb    r1, [r3, #8]
-        bx      lr
-
-Copy10  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldrh    r1, [r1, #8]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        strh    r1, [r3, #8]
-        bx      lr
-
-Copy11  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldrh    r2, [r1, #8]
-        ldrb    r1, [r1, #10]
-        strh    r2, [r3, #8]
-        strb    r1, [r3, #10]
-        bx      lr
-
-Copy12  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldr     r1, [r1, #8]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        str     r1, [r3, #8]
-        bx      lr
-
-Copy13  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldr     r2, [r1, #8]
-        ldrb    r1, [r1, #12]
-        str     r2, [r3, #8]
-        strb    r1, [r3, #12]
-        bx      lr
-
-Copy14  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldr     r2, [r1, #8]
-        ldrh    r1, [r1, #12]
-        str     r2, [r3, #8]
-        strh    r1, [r3, #12]
-        bx      lr
-
-Copy15  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        str     r12, [r3]
-        str     r2, [r3, #4]
-        ldr     r12, [r1, #8]
-        ldrh    r2, [r1, #12]
-        ldrb    r1, [r1, #14]
-        str     r12, [r3, #8]
-        strh    r2, [r3, #12]
-        strb    r1, [r3, #14]
-        bx      lr
-
-CpyLrge
-
-#if defined(_BOOTCRT_)
-
-        b       __memcpy_forward_large_integer          ; always use integer in boot code
-
-#else
-
-        eor     r12, r0, r1                             ; see if src/dst are equally aligned
-        tst     r12, #3                                 ; at least to a 4 byte boundary
-        bne     __memcpy_forward_large_neon             ; if not, always use NEON
-        mov32   r12, __memcpy_forward_large_func        ; otherwise, load the large function pointer
-        ldr     pc, [r12]                               ; and call it
-
-#endif
-
-        LEAF_END memcpy
-
-
-;
-; __memcpy_forward_large_integer (internal calling convention)
-;
-; Copy large (>= 16 bytes) blocks of memory in a forward direction,
-; using integer registers only.
-;
-
-        ALIGN 32
-        NESTED_ENTRY __memcpy_forward_large_integer_wrapper
-
-__memcpy_forward_large_integer
-        
-        PROLOG_NOP lsls r12, r3, #31                    ; C = bit 1, N = bit 0
-        PROLOG_PUSH {r4-r9, r11, lr}
-
-;
-; Align destination to a word boundary
-;
-
-        bpl     %F1
-        ldrb    r4, [r1], #1                            ; fetch byte
-        subs    r2, r2, #1                              ; decrement count
-        strb    r4, [r3], #1                            ; store byte
-        lsls    r12, r3, #31                            ; compute updated status
-1
-        bcc     %F2                                     ; if already aligned, just skip ahead
-        ldrh    r4, [r1], #2                            ; fetch halfword
-        subs    r2, r2, #2                              ; decrement count
-        strh    r4, [r3], #2                            ; store halfword
-2
-        tst     r1, #3                                  ; is the source now word-aligned?
-        bne     %F20                                    ; if not, we have to use the slow path
-
-;
-; Source is word-aligned; fast case
-;
-
-10
-        subs    r2, r2, #32                             ; take 32 off the top
-        blo     %F13                                    ; if not enough, recover and do small copies
-        subs    r2, r2, #32                             ; take off another 32
-        pld     [r1, #32]                               ; pre-load one block ahead
-        blo     %F12                                    ; skip the loop if that's all we have
-11
-        pld     [r1, #64]                               ; prefetch ahead
-        subs    r2, r2, #32                             ; count the bytes for this block
-        ldm     r1!, {r4-r9, r12, lr}                   ; load 32 bytes
-        stm     r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-        bhs     %B11                                    ; keep going until we're done
-12
-        ldm     r1!, {r4-r9, r12, lr}                   ; load 32 bytes
-        stm     r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-13
-        adds    r2, r2, #(32 - 8)                       ; recover original count, and pre-decrement
-        blo     %F15                                    ; if not enough remaining, skip this loop
-14 
-        subs    r2, r2, #8                              ; decrement count
-        ldrd    r4, r5, [r1], #8                        ; fetch pair of words
-        strd    r4, r5, [r3], #8                        ; store pair of words
-        bhs     %B14                                    ; loop while we still have data remaining
-15
-        adds    r2, r2, #8                              ; recover final count
-
-        EPILOG_POP {r4-r9, r11, lr}
-        EPILOG_NOP bne CpySmal                          ; if some left, continue with small
-        EPILOG_RETURN                                   ; else just return
-
-;
-; Source is not word-aligned; slow case
-;
-
-20
-        subs    r2, r2, #64                             ; pre-decrement to simplify the loop
-        blo     %23                                     ; skip over the loop if we don't have enough
-        pld     [r1, #32]                               ; pre-load one block ahead
-21
-        pld     [r1, #64]                               ; prefetch ahead
-        ldr     r4, [r1, #0]                            ; load 32 bytes
-        ldr     r5, [r1, #4]                            ;
-        ldr     r6, [r1, #8]                            ;
-        ldr     r7, [r1, #12]                           ;
-        ldr     r8, [r1, #16]                           ;
-        ldr     r9, [r1, #20]                           ;
-        ldr     r12, [r1, #24]                          ;
-        ldr     lr, [r1, #28]                           ;
-        adds    r1, r1, #32                             ; update pointer
-        subs    r2, r2, #32                             ; count the bytes for this block
-        stm     r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-        bhs     %B21                                    ; keep going until we're done
-23
-        adds    r2, r2, #(64 - 8)                       ; recover original count, and pre-decrement
-        blo     %F25                                    ; if not enough remaining, skip this loop
-24
-        ldr     r4, [r1]                                ; fetch pair of words
-        ldr     r5, [r1, #4]                            ;
-        adds    r1, r1, #8                              ; update pointer
-        subs    r2, r2, #8                              ; decrement count
-        strd    r4, r5, [r3], #8                        ; store pair of words
-        bhs     %B24                                    ; loop while we still have data remaining
-25
-        adds    r2, r2, #8                              ; recover final count
-
-        EPILOG_POP {r4-r9, r11, lr}
-        EPILOG_NOP bne CpySmal                          ; if some left, continue with small
-        EPILOG_RETURN                                   ; else just return
-
-        NESTED_END __memcpy_forward_large_integer
-
-
-;
-; __memcpy_forward_large_neon (internal calling convention)
-;
-; Copy large (>= 16 bytes) blocks of memory in a forward direction,
-; using NEON registers.
-;
-
-#if !defined(_BOOTCRT_)
-
-        ALIGN 32
-        NESTED_ENTRY __memcpy_forward_large_neon_wrapper
-
-__memcpy_forward_large_neon
-        
-        PROLOG_PUSH {r4-r5, r11, lr}
-
-        subs    r2, r2, #32                             ; pre-decrement to simplify the loop
-        blo     %F13                                    ; skip over the loop if we don't have enough
-        subs    r2, r2, #32                             ; pre-decrement to simplify the loop
-        pld     [r1, #32]                               ; pre-load one block ahead
-        blo     %F12                                    ; skip over the loop if we don't have enough
-11
-        pld     [r1, #64]                               ; prefetch ahead
-        subs    r2, r2, #32                             ; count the bytes for this block
-        vld1.8  {d0-d3}, [r1]!                          ; load 32 bytes
-        vst1.8  {d0-d3}, [r3]!                          ; store 32 bytes
-        bhs     %B11                                    ; keep going until we're done
-12
-        vld1.8  {d0-d3}, [r1]!                          ; load 32 bytes
-        vst1.8  {d0-d3}, [r3]!                          ; store 32 bytes
-13
-        adds    r2, r2, #(32 - 8)                       ; recover original count, and pre-decrement
-        blo     %F15                                    ; if not enough remaining, skip this loop
-14   
-        ldr     r4, [r1]                                ; fetch pair of words
-        ldr     r5, [r1, #4]                            ;
-        adds    r1, r1, #8                              ; update pointer
-        str     r4, [r3]                                ; store pair of words
-        str     r5, [r3, #4]                            ;
-        adds    r3, r3, #8
-        subs    r2, r2, #8                              ; decrement count
-        bhs     %B14                                    ; loop while we still have data remaining
-15
-        adds    r2, r2, #8                              ; recover final count
-
-        EPILOG_POP {r4-r5, r11, lr}
-        EPILOG_NOP bne CpySmal                          ; if some left, continue with small
-        EPILOG_RETURN                                   ; else just return
-
-        NESTED_END __memcpy_forward_large_neon
-
-#endif
-
-
-;
-; void *memmove(void *dst, const void *src, size_t length)
-;
-; Copy a block of memory in a forward or reverse direction, ensuring that
-; overlapping source/destination regions are copied correctly.
-;
-
-        ALIGN 32
-        LEAF_ENTRY memmove
-        
-        subs    r3, r0, r1                              ; compute dest - source
-        cmp     r3, r2                                  ; compare against size
-        bhs     memcpy                                  ; if no overlap, we can just do memcpy
-        
-        ALTERNATE_ENTRY __memcpy_reverse_new
-        
-        cmp     r2, #16                                 ; less than 16 bytes?
-        pld     [r1]                                    ; preload the first cache line
-        bhs     MovLrge                                 ; go to the small copy case directly
-
-MovSmal tbb     [pc, r2]                                ; branch to specialized bits for small copies
-__SwitchTable1_Move
-MTable  dcb     (Move0 - MTable) / 2                    ; 0B
-        dcb     (Move1 - MTable) / 2                    ; 1B
-        dcb     (Move2 - MTable) / 2                    ; 2B
-        dcb     (Move3 - MTable) / 2                    ; 3B
-        dcb     (Move4 - MTable) / 2                    ; 4B
-        dcb     (Move5 - MTable) / 2                    ; 5B
-        dcb     (Move6 - MTable) / 2                    ; 6B
-        dcb     (Move7 - MTable) / 2                    ; 7B
-        dcb     (Move8 - MTable) / 2                    ; 8B
-        dcb     (Move9 - MTable) / 2                    ; 9B
-        dcb     (Move10 - MTable) / 2                   ; 10B
-        dcb     (Move11 - MTable) / 2                   ; 11B
-        dcb     (Move12 - MTable) / 2                   ; 12B
-        dcb     (Move13 - MTable) / 2                   ; 13B
-        dcb     (Move14 - MTable) / 2                   ; 14B
-        dcb     (Move15 - MTable) / 2                   ; 15B
-__SwitchTableEnd_Move
-
-Move1   ldrb    r2, [r1]
-        strb    r2, [r0]
-Move0   bx      lr
-
-Move2   ldrh    r2, [r1]
-        strh    r2, [r0]
-        bx      lr
-
-Move3   ldrh    r2, [r1]
-        ldrb    r1, [r1, #2]
-        strh    r2, [r0]
-        strb    r1, [r0, #2]
-        bx      lr
-
-Move4   ldr     r2, [r1]
-        str     r2, [r0]
-        bx      lr
-
-Move5   ldr     r2, [r1]
-        ldrb    r1, [r1, #4]
-        str     r2, [r0]
-        strb    r1, [r0, #4]
-        bx      lr
-
-Move6   ldr     r2, [r1]
-        ldrh    r1, [r1, #4]
-        str     r2, [r0]
-        strh    r1, [r0, #4]
-        bx      lr
-
-Move7   ldr     r3, [r1]
-        ldrh    r2, [r1, #4]
-        ldrb    r1, [r1, #6]
-        str     r3, [r0]
-        strh    r2, [r0, #4]
-        strb    r1, [r0, #6]
-        bx      lr
-
-Move8   ldr     r2, [r1]
-        ldr     r1, [r1, #4]
-        str     r2, [r0]
-        str     r1, [r0, #4]
-        bx      lr
-
-Move9   ldr     r3, [r1]
-        ldr     r2, [r1, #4]
-        ldrb    r1, [r1, #8]
-        str     r3, [r0]
-        str     r2, [r0, #4]
-        strb    r1, [r0, #8]
-        bx      lr
-
-Move10  ldr     r3, [r1]
-        ldr     r2, [r1, #4]
-        ldrh    r1, [r1, #8]
-        str     r3, [r0]
-        str     r2, [r0, #4]
-        strh    r1, [r0, #8]
-        bx      lr
-
-Move11  ldr     r12, [r1]
-        ldr     r3, [r1, #4]
-        ldrh    r2, [r1, #8]
-        ldrb    r1, [r1, #10]
-        str     r12, [r0]
-        str     r3, [r0, #4]
-        strh    r2, [r0, #8]
-        strb    r1, [r0, #10]
-        bx      lr
-
-Move12  ldr     r12, [r1]
-        ldr     r2, [r1, #4]
-        ldr     r1, [r1, #8]
-        str     r12, [r0]
-        str     r2, [r0, #4]
-        str     r1, [r0, #8]
-        bx      lr
-
-Move13  ldr     r12, [r1]
-        ldr     r3, [r1, #4]
-        ldr     r2, [r1, #8]
-        ldrb    r1, [r1, #12]
-        str     r12, [r0]
-        str     r3, [r0, #4]
-        str     r2, [r0, #8]
-        strb    r1, [r0, #12]
-        bx      lr
-
-Move14  ldr     r12, [r1]
-        ldr     r3, [r1, #4]
-        ldr     r2, [r1, #8]
-        ldrh    r1, [r1, #12]
-        str     r12, [r0]
-        str     r3, [r0, #4]
-        str     r2, [r0, #8]
-        strh    r1, [r0, #12]
-        bx      lr
-
-Move15  ldrh    r3, [r1, #12]
-        ldrb    r2, [r1, #14]
-        strh    r3, [r0, #12]
-        strb    r2, [r0, #14]
-        ldr     r3, [r1]
-        ldr     r2, [r1, #4]
-        ldr     r1, [r1, #8]
-        str     r3, [r0]
-        str     r2, [r0, #4]
-        str     r1, [r0, #8]
-        bx      lr
-
-MovLrge
-
-#if defined(_BOOTCRT_)
-
-        b       __memcpy_reverse_large_integer          ; always use integer in boot code
-
-#else
-
-        eor     r12, r0, r1                             ; see if src/dst are equally aligned
-        tst     r12, #3                                 ; at least to a 4 byte boundary
-        bne     __memcpy_reverse_large_neon             ; if not, always use NEON
-        mov32   r12, __memcpy_reverse_large_func
-        ldr     pc, [r12]
-
-#endif
-
-        LEAF_END memmove
-
-
-;
-; __memcpy_reverse_large_integer (internal calling convention)
-;
-; Copy large (>= 16 bytes) block of memory in a reverse direction, 
-; using NEON registers.
-;
-
-        ALIGN 32
-        NESTED_ENTRY __memcpy_reverse_large_integer_wrapper
-
-__memcpy_reverse_large_integer
-        
-        PROLOG_NOP adds r3, r0, r2                      ; advance destination to end
-        PROLOG_NOP adds r1, r1, r2                      ; advance source to end
-        PROLOG_NOP lsls r12, r3, #31                    ; C = bit 1, N = bit 0
-        PROLOG_NOP pld [r1, #-32]                       ; pre-load one block ahead
-        PROLOG_PUSH {r4-r9, r11, lr}
-
-;
-; Align destination to a word boundary
-;
-
-        bpl     %F1
-        ldrb    r4, [r1, #-1]!                          ; fetch byte
-        subs    r2, r2, #1                              ; decrement count
-        strb    r4, [r3, #-1]!                          ; store byte
-        lsls    r12, r3, #31                            ; compute updated status
-1
-        bcc     %F2                                     ; if already aligned, just skip ahead
-        ldrh    r4, [r1, #-2]!                          ; fetch halfword
-        subs    r2, r2, #2                              ; decrement count
-        strh    r4, [r3, #-2]!                          ; store halfword
-2
-        tst     r1, #3                                  ; is the source now word-aligned?
-        bne     %F20                                    ; if not, we have to use the slow path
-
-;
-; Source is word-aligned; fast case
-;
-
-10
-        subs    r2, r2, #32                             ; pre-decrement to simplify the loop
-        blo     %F13                                    ; skip over the loop if we don't have enough
-        subs    r2, r2, #32                             ; pre-decrement to simplify the loop
-        pld     [r1, #-64]                              ; pre-load one block ahead
-        blo     %F12                                    ; skip over the loop if we don't have enough
-11
-        pld     [r1, #-96]                              ; prefetch ahead
-        subs    r2, r2, #32                             ; count the bytes for this block
-        ldmdb   r1!, {r4-r9, r12, lr}                   ; load 32 bytes
-        stmdb   r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-        bhs     %B11                                    ; keep going until we're done
-12
-        ldmdb   r1!, {r4-r9, r12, lr}                   ; load 32 bytes
-        stmdb   r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-13
-        adds    r2, r2, #(32 - 8)                       ; recover original count, and pre-decrement
-        blo     %F15                                    ; if not enough remaining, skip this loop
-14
-        subs    r2, r2, #8                              ; decrement count
-        ldrd    r4, r5, [r1, #-8]!                      ; fetch pair of words
-        strd    r4, r5, [r3, #-8]!                      ; store pair of words
-        bhs     %B14                                    ; loop while we still have data remaining
-15
-        adds    r2, r2, #8                              ; determine final count
-        subs    r1, r1, r2                              ; recover original source
-        
-        EPILOG_POP {r4-r9, r11, lr}
-        EPILOG_NOP bne MovSmal                          ; if some left, continue with small
-        EPILOG_RETURN                                   ; else just return
-
-
-;
-; Source is not word-aligned; slow case
-;
-
-20
-        subs    r2, r2, #64                             ; pre-decrement to simplify the loop
-        blo     %F23                                    ; skip over the loop if we don't have enough
-        pld     [r1, #-64]                              ; pre-load one block ahead
-21
-        pld     [r1, #-96]                              ; prefetch ahead
-        subs    r2, r2, #32                             ; count the bytes for this block
-        ldr     r4, [r1, #-32]!                         ; load 32 bytes
-        ldr     r5, [r1, #4]                            ;
-        ldr     r6, [r1, #8]                            ;
-        ldr     r7, [r1, #12]                           ;
-        ldr     r8, [r1, #16]                           ;
-        ldr     r9, [r1, #20]                           ;
-        ldr     r12, [r1, #24]                          ;
-        ldr     lr, [r1, #28]                           ;
-        stmdb   r3!, {r4-r9, r12, lr}                   ; store 32 bytes
-        bhs     %B21                                    ; keep going until we're done
-23
-        adds    r2, r2, #(64 - 8)                       ; recover original count, and pre-decrement
-        blo     %F25                                    ; if not enough remaining, skip this loop
-24
-        subs    r2, r2, #8                              ; decrement count
-        ldr     r4, [r1, #-8]!                          ; fetch pair of words
-        ldr     r5, [r1, #4]                            ;
-        strd    r4, r5, [r3, #-8]!                      ; store pair of words
-        bhs     %B24                                    ; loop while we still have data remaining
-25
-        adds    r2, r2, #8                              ; determine final count
-        subs    r1, r1, r2                              ; recover original source
-        
-        EPILOG_POP {r4-r9, r11, lr}
-        EPILOG_NOP bne MovSmal                          ; if some left, continue with small
-        EPILOG_RETURN                                   ; else just return
-
-        NESTED_END __memcpy_reverse_large_integer
-
-
-;
-; __memcpy_reverse_large_neon (internal calling convention)
-;
-; Copy large (>= 16 bytes) block of memory in a reverse direction, 
-; using NEON registers.
-;
-
-#if !defined(_BOOTCRT_)
-
-        ALIGN 32
-        NESTED_ENTRY __memcpy_reverse_large_neon_wrapper
-
-__memcpy_reverse_large_neon
-        
-        PROLOG_NOP adds r3, r0, r2                      ; advance destination to end
-        PROLOG_NOP adds r1, r1, r2                      ; advance source to end
-        PROLOG_NOP lsls r12, r3, #31                    ; C = bit 1, N = bit 0
-        PROLOG_NOP pld [r1, #-32]                       ; pre-load one block ahead
-        PROLOG_PUSH {r4-r5, r11, lr}
-
-;
-; Align destination to a word boundary
-;
-
-        bpl     %F1
-        ldrb    r4, [r1, #-1]!                          ; fetch byte
-        subs    r2, r2, #1                              ; decrement count
-        strb    r4, [r3, #-1]!                          ; store byte
-        lsls    r12, r3, #31                            ; compute updated status
-1
-        bcc     %F2                                     ; if already aligned, just skip ahead
-        ldrh    r4, [r1, #-2]!                          ; fetch halfword
-        subs    r2, r2, #2                              ; decrement count
-        strh    r4, [r3, #-2]!                          ; store halfword
-2
-
-;
-; Perform main copy
-;
-
-        subs    r2, r2, #32                             ; pre-decrement to simplify the loop
-        blo     %F13                                    ; skip over the loop if we don't have enough
-        subs    r2, r2, #32                             ; pre-decrement to simplify the loop
-        pld     [r1, #-64]                              ; pre-load one block ahead
-        blo     %F12                                    ; skip over the loop if we don't have enough
-11
-        pld     [r1, #-96]                              ; prefetch ahead
-        subs    r1, r1, #32
-        subs    r3, r3, #32
-        subs    r2, r2, #32                             ; count the bytes for this block
-        vld1.8  {d0-d3}, [r1]                           ; load 32 bytes
-        vst1.8  {d0-d3}, [r3]                           ; store 32 bytes
-        bhs     %B11                                    ; keep going until we're done
-12
-        subs    r1, r1, #32
-        subs    r3, r3, #32
-        vld1.8  {d0-d3}, [r1]                           ; load 32 bytes
-        vst1.8  {d0-d3}, [r3]                           ; store 32 bytes
-13
-        adds    r2, r2, #(32 - 8)                       ; recover original count, and pre-decrement
-        blo     %F15                                    ; if not enough remaining, skip this loop
-14
-        ldr     r4, [r1, #-8]!                          ; fetch pair of words
-        ldr     r5, [r1, #4]                            ; fetch pair of words
-        subs    r2, r2, #8                              ; decrement count
-        str     r4, [r3, #-8]!                          ; store pair of words
-        str     r5, [r3, #4]
-        bhs     %B14                                    ; loop while we still have data remaining
-15
-        adds    r2, r2, #8                              ; determine final count
-        subs    r1, r1, r2                              ; recover original source
-        
-        EPILOG_POP {r4-r5, r11, lr}
-        EPILOG_NOP bne MovSmal                          ; if some left, continue with small
-        EPILOG_RETURN                                   ; else just return
-
-        NESTED_END __memcpy_reverse_large_neon
-
-#endif
-
-
-;
-; __memcpy_decide (internal calling convention)
-;
-; Determine whether to use integer or NEON for future memcpy's.
-;
-
-#if !defined(_BOOTCRT_)
-
-        ALIGN 32
-        NESTED_ENTRY __memcpy_decide_wrapper
-
-__memcpy_decide
-
-        PROLOG_PUSH {r4-r5, r11, lr}
-        
-        ;
-        ; We want to use integer memcpy's on the A9, which has an external cache.
-        ;
-        ; First determine if we're in user or kernel mode. Reading CPSR
-        ; from user mode will either return the proper 5 mode bits, or all 0s.
-        ; Conveniently, user mode is 0x10, and there is no mode 0x00, so if
-        ; we read CPSR and the low 4 bits are 0, that's good enough.
-        ;
-        
-        mrs     r4, cpsr                                ; get CPSR
-        ands    r4, r4, #0xf                            ; isolate the low 4 bits of the mode
-        beq     %F1                                     ; if 0, we're in user mode
-
-        ;
-        ; If we are in kernel mode, read the MIDR directly.
-        ;
-
-        CP_READ r4, CP15_MIDR                           ; read main ID register
-        ubfx    r5, r4, #24, #8                         ; get implementer
-        lsrs    r4, r4, #4                              ; shift off revision field
-        cmp     r5, #0x41                               ; is implementer == ARM?
-        bne     %F3                                     ; if not, use NEON
-        bfc     r4, #12, #20                            ; clear upper bits
-        ldr     r5, =0xc09                              ; A9 signature
-        cmp     r4, r5                                  ; is this an A9?
-        bne     %F3                                     ; if not, use NEON
-        b       %F2                                     ; otherwise, use integer
-
-        ;
-        ; If we are in user mode, check the "external cache available" flag
-        ;
-1
-        ldr     r4, =MM_SHARED_USER_DATA_VA + UsProcessorFeatures + PF_ARM_EXTERNAL_CACHE_AVAILABLE
-        ldrb    r4, [r4]                                ; get external cache bit
-        cbz     r4, %F3                                 ; if no external cache, do NEON
-
-        ;
-        ; Register for integer functions
-        ;
-2
-        ldr     r4, =__memcpy_forward_large_integer     ; select integer functions
-        ldr     r5, =__memcpy_forward_large_func        ;
-        str     r4, [r5]                                ;   
-        ldr     r4, =__memcpy_reverse_large_integer     ; select integer functions
-        ldr     r5, =__memcpy_reverse_large_func        ;
-        str     r4, [r5]                                ;
-        b       %F4        
-
-        ;
-        ; Register for NEON functions
-        ;
-3
-        ldr     r4, =__memcpy_forward_large_neon        ; select NEON functions
-        ldr     r5, =__memcpy_forward_large_func        ;
-        str     r4, [r5]                                ;   
-        ldr     r4, =__memcpy_reverse_large_neon        ; select NEON functions
-        ldr     r5, =__memcpy_reverse_large_func        ;
-        str     r4, [r5]                                ;   
-4
-        EPILOG_POP {r4-r5, r11, lr}                     ; restore saved registers
-        EPILOG_NOP ldr     pc, [r12]                    ; jump to the appropriate target
-
-        NESTED_END __memcpy_decide
-
-#endif
-
-
-;
-; void _memcpy_strict_align(void *dst, const void *src, size_t length)
-;
-; Copy a block of memory in a forward direction, only performing naturally-aligned
-; accesses.
-;
-
-        ALIGN 32
-        LEAF_ENTRY _memcpy_strict_align
-        
-;
-; Verify alignment between source and destination
-;
-        
-        sub     r3, r0, r1                              ; get relative alignment of source and destination
-        cbz     r2, CopyExit                            ; exit if 0 count        
-        ands    r3, r3, #3                              ; check DWORD alignment
-        bne     CopyMisalignedHalf                      ; misaligned
-
-;
-; Source and destination are equally aligned: just align the
-; destination and the source will end up aligned as well
-;
-        
-        tst     r0, #3                                  ; dword aligned at the dest?
-        beq     WordAligned_0                           ; if so, skip ahead
-        tst     r0, #1                                  ; halfword aligned at the dest?
-        beq     HalfAligned_0                           ; if so, skip ahead
-
-        subs    r2, r2, #1                              ; decrement count
-        ldrb    r3, [r1], #1                            ; fetch byte
-        strb    r3, [r0], #1                            ; store it
-        beq     CopyExit                                ; stop if done
-        tst     r0, #3                                  ; word aligned now?
-        beq     WordAligned_0                           ; if so, skip ahead
-
-HalfAligned_0
-        cmp     r2, #2                                  ; do we have at least 2 bytes left?
-        blo     CopyFinalBytes                          ; if not, copy bytes
-        subs    r2, r2, #2                              ; decrement count
-        ldrh    r3, [r1], #2                            ; fetch halfword
-        strh    r3, [r0], #2                            ; store it
-        beq     CopyExit                                ; stop if done
-
-WordAligned_0
-        subs    r2, r2, #4                              ; at least 4 bytes remaining?
-        blt     WordLoopEnd_0                           ; if not, skip the main loop
-WordLoop_0
-        subs    r2, r2, #4                              ; decrement count
-        ldr     r3, [r1], #4                            ; fetch word
-        str     r3, [r0], #4                            ; store it
-        bge     WordLoop_0                              ; stop if done
-WordLoopEnd_0
-        adds    r2, r2, #4                              ; recover the extra 4 we subtracted
-        beq     CopyExit                                ; stop if that's everything
-
-CopyFinalHalfwords
-        subs    r2, r2, #2                              ; at least 2 bytes remaining?
-        blt     CopyFinalHalfwordsEnd                   ; if not, skip this
-CopyFinalHalfwordsLoop
-        subs    r2, r2, #2                              ; decrement count
-        ldrh    r3, [r1], #2                            ; fetch halfword
-        strh    r3, [r0], #2                            ; store it
-        bge     CopyFinalHalfwordsLoop                  ; loop until done
-CopyFinalHalfwordsEnd
-        adds    r2, r2, #2                              ; recover the extra 2 we subtracted
-        beq     CopyExit                                ; stop if that's everything
-
-CopyFinalBytes
-        subs    r2, r2, #1                              ; decrement count
-        ldrb    r3, [r1], #1                            ; fetch byte
-        strb    r3, [r0], #1                            ; store it
-        bne     CopyFinalBytes                          ; loop until done
-CopyExit
-        bx      lr                                      ; return        
-
-
-;
-; Source and destination are misaligned by 2 bytes
-;
-        
-CopyMisalignedHalf
-        cmp     r3, #2                                  ; misaligned by a halfword?
-        bne     CopyMisalignedByte                      ; if not, skip
-
-        tst     r0, #3                                  ; dword aligned at the dest?
-        beq     WordAligned_2                           ; if so, skip ahead
-        tst     r0, #1                                  ; halfword aligned at the dest?
-        beq     HalfAligned_2                           ; if so, skip ahead
-
-        subs    r2, r2, #1                              ; decrement count
-        ldrb    r3, [r1], #1                            ; fetch byte
-        strb    r3, [r0], #1                            ; store it
-        beq     CopyExit                                ; stop if done
-        tst     r0, #3                                  ; word aligned now?
-        beq     WordAligned_2                           ; if so, skip ahead
-
-HalfAligned_2
-        cmp     r2, #2                                  ; do we have at least 2 bytes left?
-        blo     CopyFinalBytes                          ; if not, copy bytes
-        subs    r2, r2, #2                              ; decrement count
-        ldrh    r3, [r1], #2                            ; fetch halfword
-        strh    r3, [r0], #2                            ; store it
-        beq     CopyExit                                ; stop if done
-
-WordAligned_2
-        subs    r2, r2, #6                              ; at least 6 bytes remaining?
-        blt     WordLoopEnd_2                           ; if so, skip the main loop
-        ldrh    r12, [r1], #2                           ; preload a halfword of source
-        subs    r2, r2, #2                              ; count these 2 bytes
-WordLoop_2
-        subs    r2, r2, #4                              ; decrement count
-        ldr     r3, [r1], #4                            ; fetch word
-        orr     r12, r12, r3, lsl #16                   ; copy low 16 bits to upper 16 of r12
-        str     r12, [r0], #4                           ; store it
-        lsr     r12, r3, #16                            ; copy upper 16 bits to lower 16 of r12
-        bge     WordLoop_2                              ; stop if done
-        strh    r12, [r0], #2                           ; store the extra halfword to the dest
-WordLoopEnd_2
-        adds    r2, r2, #6                              ; recover the extra 6 we subtracted
-        beq     CopyExit                                ; stop if that's everything
-        b       CopyFinalHalfwords                      ; otherwise, copy remainder
-
-
-;
-; Source and destination are misaligned by 1 byte
-;
-        
-CopyMisalignedByte
-        cmp     r3, #1                                  ; misaligned by a byte?
-        bne     CopyMisalignedByte3                     ; if not, skip
-
-        tst     r0, #3                                  ; dword aligned at the dest?
-        beq     WordAligned_1                           ; if so, skip ahead
-ByteAlign_1
-        subs    r2, r2, #1                              ; decrement count
-        ldrb    r3, [r1], #1                            ; fetch byte
-        strb    r3, [r0], #1                            ; store it
-        beq     CopyExit                                ; stop if done
-        tst     r0, #3                                  ; word aligned now?
-        bne     ByteAlign_1                             ; if not, keep copying bytes
-
-WordAligned_1
-        subs    r2, r2, #5                              ; at least 5 bytes remaining?
-        blt     WordLoopEnd_1                           ; if so, skip the main loop
-        ldrb    r12, [r1], #1                           ; preload a byte of source
-        subs    r2, r2, #1                              ; count this byte
-WordLoop_1
-        subs    r2, r2, #4                              ; decrement count
-        ldr     r3, [r1], #4                            ; fetch word
-        orr     r12, r12, r3, lsl #8                    ; copy low 24 bits to upper 24 of r12
-        str     r12, [r0], #4                           ; store it
-        lsr     r12, r3, #24                            ; copy upper 8 bits to lower 8 of r12
-        bge     WordLoop_1                              ; stop if done
-        strb    r12, [r0], #1                           ; store the extra byte to the dest
-WordLoopEnd_1
-        adds    r2, r2, #5                              ; recover the extra 5 we subtracted
-        beq     CopyExit                                ; stop if that's everything
-        b       CopyFinalBytes                          ; otherwise, copy remainder
-
-
-;
-; Source and destination are misaligned by 3 bytes
-;
-        
-CopyMisalignedByte3
-        tst     r0, #3                                  ; dword aligned at the dest?
-        beq     WordAligned_3                           ; if so, skip ahead
-ByteAlign_3
-        subs    r2, r2, #1                              ; decrement count
-        ldrb    r3, [r1], #1                            ; fetch byte
-        strb    r3, [r0], #1                            ; store it
-        beq     CopyExit                                ; stop if done
-        tst     r0, #3                                  ; word aligned now?
-        bne     ByteAlign_3                             ; if not, keep copying bytes
-
-WordAligned_3
-        subs    r2, r2, #7                              ; at least 7 bytes remaining?
-        blt     WordLoopEnd_3                           ; if so, skip the main loop
-        ldrb    r12, [r1], #1                           ; preload a byte of source
-        ldrh    r3, [r1], #2                            ; preload a halfword of source
-        orr     r12, r12, r3, lsl #8                    ; OR in the halfword
-        subs    r2, r2, #3                              ; count these 3 bytes
-WordLoop_3
-        subs    r2, r2, #4                              ; decrement count
-        ldr     r3, [r1], #4                            ; fetch word
-        orr     r12, r12, r3, lsl #24                   ; copy low 8 bits to upper 8 of r12
-        str     r12, [r0], #4                           ; store it
-        lsr     r12, r3, #8                             ; copy upper 24 bits to lower 24 of r12
-        bge     WordLoop_3                              ; stop if done
-        strh    r12, [r0], #2                           ; store the extra halfword to the dest
-        lsr     r12, r12, #16                           ; down to the final byte
-        strb    r12, [r0], #1                           ; store the extra byte to the dest
-WordLoopEnd_3
-        adds    r2, r2, #7                              ; recover the extra 7 we subtracted
-        beq     CopyExit                                ; stop if that's everything
-        b       CopyFinalBytes                          ; otherwise, copy remainder
-
-        LEAF_END _memcpy_strict_align
-
-        END
index f2c2811..76bfa61 100644 (file)
@@ -685,7 +685,7 @@ void QCALLTYPE ExceptionNative::GetMessageFromNativeResources(ExceptionMessageKi
     END_QCALL;
 }
 
-void QCALLTYPE MemoryNative::Clear(void *dst, size_t length)
+void QCALLTYPE Buffer::Clear(void *dst, size_t length)
 {
     QCALL_CONTRACT;
 
@@ -714,11 +714,12 @@ void QCALLTYPE MemoryNative::Clear(void *dst, size_t length)
     memset(dst, 0, length);
 }
 
-FCIMPL3(VOID, MemoryNative::BulkMoveWithWriteBarrier, void *dst, void *src, size_t byteCount)
+FCIMPL3(VOID, Buffer::BulkMoveWithWriteBarrier, void *dst, void *src, size_t byteCount)
 {
     FCALL_CONTRACT;
 
-    InlinedMemmoveGCRefsHelper(dst, src, byteCount);
+    if (dst != src && byteCount != 0)
+        InlinedMemmoveGCRefsHelper(dst, src, byteCount);
 
     FC_GC_POLL();
 }
index cc48e88..5b6d7a9 100644 (file)
@@ -64,25 +64,18 @@ public:
     static FCDECL0(UINT32, GetExceptionCount);
 };
 
-class MemoryNative
-{
-public:
-    static void QCALLTYPE Clear(void *dst, size_t length);
-    static FCDECL3(VOID, BulkMoveWithWriteBarrier, void *dst, void *src, size_t byteCount);
-};
-
 //
 // Buffer
 //
-class Buffer {
+class Buffer
+{
 public:
-
-    // BlockCopy
-    // This method from one primitive array to another based
-    //      upon an offset into each an a byte count.
     static FCDECL1(FC_BOOL_RET, IsPrimitiveTypeArray, ArrayBase *arrayUNSAFE);
 
+    static FCDECL3(VOID, BulkMoveWithWriteBarrier, void *dst, void *src, size_t byteCount);
+
     static void QCALLTYPE MemMove(void *dst, void *src, size_t length);
+    static void QCALLTYPE Clear(void *dst, size_t length);
 };
 
 #define MIN_GC_MEMORYPRESSURE_THRESHOLD 100000
index 8a5a1d2..21b0ff8 100644 (file)
@@ -740,9 +740,8 @@ FCFuncEnd()
 
 FCFuncStart(gBufferFuncs)
     FCFuncElement("IsPrimitiveTypeArray", Buffer::IsPrimitiveTypeArray)
-#ifdef _TARGET_ARM_
-    FCFuncElement("Memcpy", FCallMemcpy)
-#endif
+    QCFuncElement("__ZeroMemory", Buffer::Clear)
+    FCFuncElement("BulkMoveWithWriteBarrier", Buffer::BulkMoveWithWriteBarrier)
     QCFuncElement("__Memmove", Buffer::MemMove)
 FCFuncEnd()
 
@@ -1109,11 +1108,6 @@ FCFuncStart(gRuntimeClassFuncs)
 FCFuncEnd()
 #endif // ifdef FEATURE_COMINTEROP
 
-FCFuncStart(gRuntimeImportsFuncs)
-    QCFuncElement("RhZeroMemory", MemoryNative::Clear)
-    FCFuncElement("RhBulkMoveWithWriteBarrier", MemoryNative::BulkMoveWithWriteBarrier)
-FCFuncEnd()
-
 FCFuncStart(gWeakReferenceFuncs)
     FCFuncElement("Create", WeakReferenceNative::Create)
     FCFuncElement("Finalize", WeakReferenceNative::Finalize)
@@ -1175,7 +1169,6 @@ FCFuncStart(gPalOleAut32Funcs)
     QCFuncElement("SysAllocStringByteLen", SysAllocStringByteLen)
     QCFuncElement("SysAllocStringLen", SysAllocStringLen)
     QCFuncElement("SysFreeString", SysFreeString)
-    QCFuncElement("SysStringLen", SysStringLen)
 FCFuncEnd()
 #endif
 
@@ -1299,7 +1292,6 @@ FCClassElement("RuntimeClass", "System.Runtime.InteropServices.WindowsRuntime",
 #endif // FEATURE_COMINTEROP
 FCClassElement("RuntimeFieldHandle", "System", gCOMFieldHandleNewFuncs)
 FCClassElement("RuntimeHelpers", "System.Runtime.CompilerServices", gRuntimeHelpers)
-FCClassElement("RuntimeImports", "System.Runtime", gRuntimeImportsFuncs)
 FCClassElement("RuntimeMethodHandle", "System", gRuntimeMethodHandle)
 FCClassElement("RuntimeModule", "System.Reflection", gCOMModuleFuncs)
 FCClassElement("RuntimeType", "System", gSystem_RuntimeType)
index d3fc6ea..dafc105 100644 (file)
@@ -6653,10 +6653,6 @@ EXTERN_C void JIT_WriteBarrier_Debug();
 EXTERN_C void JIT_WriteBarrier_Debug_End();
 #endif
 
-#ifdef _TARGET_ARM_
-EXTERN_C void FCallMemcpy_End();
-#endif
-
 #ifdef VSD_STUB_CAN_THROW_AV
 //Return TRUE if pContext->Pc is in VirtualStub
 BOOL IsIPinVirtualStub(PCODE f_IP)
@@ -6717,10 +6713,6 @@ bool IsIPInMarkedJitHelper(UINT_PTR uControlPc)
     CHECK_RANGE(JIT_WriteBarrier_Debug)
 #endif
 
-#ifdef _TARGET_ARM_
-    CHECK_RANGE(FCallMemcpy)
-#endif
-
     return false;
 }
 #endif // FEATURE_EH_FUNCLETS
index 413b929..521afb7 100644 (file)
@@ -5563,31 +5563,6 @@ EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame);
 
 //========================================================================
 //
-//      JIT HELPERS IMPLEMENTED AS FCALLS
-//
-//========================================================================
-
-#ifdef _TARGET_ARM_
-// This function is used from the FCallMemcpy for GC polling
-EXTERN_C VOID FCallMemCpy_GCPoll()
-{
-    FC_INNER_PROLOG(FCallMemcpy);
-    Thread  *thread = GetThread();
-    // CommonTripThread does this check, but doing this to avoid raising the frames
-    if (thread->CatchAtSafePointOpportunistic()) 
-    {
-        HELPER_METHOD_FRAME_BEGIN_0();
-        CommonTripThread();
-        HELPER_METHOD_FRAME_END();
-    }
-    FC_INNER_EPILOG();
-}
-#endif // _TARGET_ARM_
-
-//========================================================================
-//
 //      JIT HELPERS INITIALIZATION
 //
 //========================================================================
index 84942d9..cce0190 100644 (file)
@@ -13,9 +13,9 @@ internal static partial class Interop
         internal const uint CRYPTPROTECTMEMORY_SAME_PROCESS = 0;
 
         [DllImport(Libraries.Crypt32, CharSet = CharSet.Unicode, SetLastError = true)]
-        internal static extern bool CryptProtectMemory(SafeBSTRHandle pData, uint cbData, uint dwFlags);
+        internal static extern bool CryptProtectMemory(SafeBuffer pData, uint cbData, uint dwFlags);
 
         [DllImport(Libraries.Crypt32, CharSet = CharSet.Unicode, SetLastError = true)]
-        internal static extern bool CryptUnprotectMemory(SafeBSTRHandle pData, uint cbData, uint dwFlags);
+        internal static extern bool CryptUnprotectMemory(SafeBuffer pData, uint cbData, uint dwFlags);
     }
 }
index a7c09b2..ac94599 100644 (file)
@@ -11,9 +11,6 @@ internal static partial class Interop
     internal static partial class OleAut32
     {
         [DllImport(Libraries.OleAut32, CharSet = CharSet.Unicode)]
-        internal static extern SafeBSTRHandle SysAllocStringLen(IntPtr src, uint len);
-
-        [DllImport(Libraries.OleAut32, CharSet = CharSet.Unicode)]
         internal static extern IntPtr SysAllocStringLen(string? src, int len);
     }
 }
diff --git a/src/libraries/System.Private.CoreLib/src/Interop/Windows/OleAut32/Interop.SysStringLen.cs b/src/libraries/System.Private.CoreLib/src/Interop/Windows/OleAut32/Interop.SysStringLen.cs
deleted file mode 100644 (file)
index a80821b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using System.Security;
-
-internal static partial class Interop
-{
-    internal static partial class OleAut32
-    {
-        [DllImport(Libraries.OleAut32)]
-        internal static extern uint SysStringLen(SafeBSTRHandle bstr);
-
-        [DllImport(Libraries.OleAut32)]
-        internal static extern uint SysStringLen(IntPtr bstr);
-    }
-}
index f3056ec..caa3d1d 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Interop.Errors.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysStringLen.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CloseHandle.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Constants.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.EventWaitHandle.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_IntPtr.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Variables.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\Win32Marshal.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Security\SafeBSTRHandle.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Mutex.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Semaphore.Windows.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\EventWaitHandle.Windows.cs" />
index 78d8273..3320579 100644 (file)
@@ -115,13 +115,6 @@ namespace System
             Unsafe.Add<byte>(ref array.GetRawArrayData(), index) = value;
         }
 
-        // This is currently used by System.IO.UnmanagedMemoryStream
-        internal static unsafe void ZeroMemory(byte* dest, long len)
-        {
-            Debug.Assert((ulong)(len) == (nuint)(len));
-            ZeroMemory(dest, (nuint)(len));
-        }
-
         // This method has different signature for x64 and other platforms and is done for performance reasons.
         internal static unsafe void ZeroMemory(byte* dest, nuint len)
         {
@@ -338,16 +331,10 @@ namespace System
             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>());
-                }
+                BulkMoveWithWriteBarrier(
+                    ref Unsafe.As<T, byte>(ref destination),
+                    ref Unsafe.As<T, byte>(ref source),
+                    elementCount * (nuint)Unsafe.SizeOf<T>());
             }
         }
 
index 6484e34..de03abd 100644 (file)
@@ -8,6 +8,13 @@ using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
 
+#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
 namespace System.IO
 {
     /*
@@ -620,7 +627,7 @@ namespace System.IO
             {
                 unsafe
                 {
-                    Buffer.ZeroMemory(_mem + len, value - len);
+                    Buffer.ZeroMemory(_mem + len, (nuint)(value - len));
                 }
             }
             Interlocked.Exchange(ref _length, value);
@@ -690,7 +697,7 @@ namespace System.IO
                 // zero any memory in the middle.
                 if (pos > len)
                 {
-                    Buffer.ZeroMemory(_mem + len, pos - len);
+                    Buffer.ZeroMemory(_mem + len, (nuint)(pos - len));
                 }
 
                 // set length after zeroing memory to avoid race condition of accessing unzeroed memory
@@ -831,7 +838,7 @@ namespace System.IO
                     {
                         unsafe
                         {
-                            Buffer.ZeroMemory(_mem + len, pos - len);
+                            Buffer.ZeroMemory(_mem + len, (nuint)(pos - len));
                         }
                     }
 
index 0d99bab..d4058c3 100644 (file)
@@ -806,7 +806,7 @@ namespace System
                 Debug.Assert(unchecked((uint)(maxResultLength)) <= MaxBlockCount);
 
                 // Zero out result internal blocks.
-                Buffer.ZeroMemory((byte*)(result.GetBlocksPointer()), maxResultLength * sizeof(uint));
+                Buffer.ZeroMemory((byte*)result.GetBlocksPointer(), (uint)maxResultLength * sizeof(uint));
 
                 int smallIndex = 0;
                 int resultStartIndex = 0;
@@ -1122,7 +1122,7 @@ namespace System
                 var result = new BigInteger(0);
                 Multiply(ref this, ref value, ref result);
 
-                Buffer.Memcpy((byte*)(GetBlocksPointer()), (byte*)(result.GetBlocksPointer()), (result._length) * sizeof(uint));
+                Buffer.Memcpy((byte*)GetBlocksPointer(), (byte*)result.GetBlocksPointer(), result._length * sizeof(uint));
                 _length = result._length;
             }
 
@@ -1189,7 +1189,7 @@ namespace System
             public void SetValue(ref BigInteger rhs)
             {
                 int rhsLength = rhs._length;
-                Buffer.Memcpy((byte*)(GetBlocksPointer()), (byte*)(rhs.GetBlocksPointer()), rhsLength * sizeof(uint));
+                Buffer.Memcpy((byte*)GetBlocksPointer(), (byte*)rhs.GetBlocksPointer(), rhsLength * sizeof(uint));
                 _length = rhsLength;
             }
 
@@ -1229,7 +1229,7 @@ namespace System
                     _length += (int)(blocksToShift);
 
                     // Zero the remaining low blocks
-                    Buffer.ZeroMemory((byte*)(GetBlocksPointer()), blocksToShift * sizeof(uint));
+                    Buffer.ZeroMemory((byte*)GetBlocksPointer(), blocksToShift * sizeof(uint));
                 }
                 else
                 {
@@ -1262,7 +1262,7 @@ namespace System
                     _blocks[writeIndex - 1] = block << (int)(remainingBitsToShift);
 
                     // Zero the remaining low blocks
-                    Buffer.ZeroMemory((byte*)(GetBlocksPointer()), blocksToShift * sizeof(uint));
+                    Buffer.ZeroMemory((byte*)GetBlocksPointer(), blocksToShift * sizeof(uint));
 
                     // Check if the terminating block has no set bits
                     if (_blocks[_length - 1] == 0)
index c0e9bd6..63c7905 100644 (file)
@@ -31,7 +31,7 @@ namespace System.Runtime.InteropServices
 
         private static int GetSystemMaxDBCSCharSize() => 3;
 
-        private static bool IsWin32Atom(IntPtr ptr) => false;
+        private static bool IsNullOrWin32Atom(IntPtr ptr) => ptr == IntPtr.Zero;
 
         internal static unsafe int StringToAnsiString(string s, byte* buffer, int bufferLength, bool bestFit = false, bool throwOnUnmappableChar = false)
         {
@@ -48,5 +48,19 @@ namespace System.Runtime.InteropServices
 
             return convertedBytes;
         }
+
+        // Returns number of bytes required to convert given string to Ansi string. The return value includes null terminator.
+        internal static unsafe int GetAnsiStringByteCount(ReadOnlySpan<char> chars)
+        {
+            int byteLength = Encoding.UTF8.GetByteCount(chars);
+            return checked(byteLength + 1);
+        }
+
+        // Converts given string to Ansi string. The destination buffer must be large enough to hold the converted value, including null terminator.
+        internal static unsafe void GetAnsiStringBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
+        {
+            int actualByteLength = Encoding.UTF8.GetBytes(chars, bytes);
+            bytes[actualByteLength] = 0;
+        }
     }
 }
index f4027d0..9889030 100644 (file)
@@ -41,10 +41,8 @@ namespace System.Runtime.InteropServices
         // Win32 has the concept of Atoms, where a pointer can either be a pointer
         // or an int.  If it's less than 64K, this is guaranteed to NOT be a
         // pointer since the bottom 64K bytes are reserved in a process' page table.
-        // We should be careful about deallocating this stuff.  Extracted to
-        // a function to avoid C# problems with lack of support for IntPtr.
-        // We have 2 of these methods for slightly different semantics for NULL.
-        private static bool IsWin32Atom(IntPtr ptr)
+        // We should be careful about deallocating this stuff.
+        private static bool IsNullOrWin32Atom(IntPtr ptr)
         {
             const long HIWORDMASK = unchecked((long)0xffffffffffff0000L);
 
@@ -82,5 +80,52 @@ namespace System.Runtime.InteropServices
             buffer[nb] = 0;
             return nb;
         }
+
+        // Returns number of bytes required to convert given string to Ansi string. The return value includes null terminator.
+        internal static unsafe int GetAnsiStringByteCount(ReadOnlySpan<char> chars)
+        {
+            int byteLength;
+
+            if (chars.Length == 0)
+            {
+                byteLength = 0;
+            }
+            else
+            {
+                fixed (char* pChars = chars)
+                {
+                    byteLength = Interop.Kernel32.WideCharToMultiByte(
+                        Interop.Kernel32.CP_ACP, Interop.Kernel32.WC_NO_BEST_FIT_CHARS, pChars, chars.Length, null, 0, IntPtr.Zero, IntPtr.Zero);
+                    if (byteLength <= 0)
+                        throw new ArgumentException();
+                }
+            }
+
+            return checked(byteLength + 1);
+        }
+
+        // Converts given string to Ansi string. The destination buffer must be large enough to hold the converted value, including null terminator.
+        internal static unsafe void GetAnsiStringBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
+        {
+            int byteLength;
+
+            if (chars.Length == 0)
+            {
+                byteLength = 0;
+            }
+            else
+            {
+                fixed (char* pChars = chars)
+                fixed (byte* pBytes = bytes)
+                {
+                    byteLength = Interop.Kernel32.WideCharToMultiByte(
+                       Interop.Kernel32.CP_ACP, Interop.Kernel32.WC_NO_BEST_FIT_CHARS, pChars, chars.Length, pBytes, bytes.Length, IntPtr.Zero, IntPtr.Zero);
+                    if (byteLength <= 0)
+                        throw new ArgumentException();
+                }
+            }
+
+            bytes[byteLength] = 0;
+        }
     }
 }
index ba6f9bf..4eaef53 100644 (file)
@@ -40,7 +40,7 @@ namespace System.Runtime.InteropServices
 
         public static unsafe string? PtrToStringAnsi(IntPtr ptr)
         {
-            if (ptr == IntPtr.Zero || IsWin32Atom(ptr))
+            if (IsNullOrWin32Atom(ptr))
             {
                 return null;
             }
@@ -64,7 +64,7 @@ namespace System.Runtime.InteropServices
 
         public static unsafe string? PtrToStringUni(IntPtr ptr)
         {
-            if (ptr == IntPtr.Zero || IsWin32Atom(ptr))
+            if (IsNullOrWin32Atom(ptr))
             {
                 return null;
             }
@@ -88,7 +88,7 @@ namespace System.Runtime.InteropServices
 
         public static unsafe string? PtrToStringUTF8(IntPtr ptr)
         {
-            if (ptr == IntPtr.Zero || IsWin32Atom(ptr))
+            if (IsNullOrWin32Atom(ptr))
             {
                 return null;
             }
@@ -915,13 +915,13 @@ namespace System.Runtime.InteropServices
 
         public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
 
-        public static void ZeroFreeBSTR(IntPtr s)
+        public static unsafe void ZeroFreeBSTR(IntPtr s)
         {
             if (s == IntPtr.Zero)
             {
                 return;
             }
-            RuntimeImports.RhZeroMemory(s, (UIntPtr)SysStringByteLen(s));
+            Buffer.ZeroMemory((byte*)s, SysStringByteLen(s));
             FreeBSTR(s);
         }
 
@@ -936,7 +936,7 @@ namespace System.Runtime.InteropServices
             {
                 return;
             }
-            RuntimeImports.RhZeroMemory(s, (UIntPtr)(string.wcslen((char*)s) * 2));
+            Buffer.ZeroMemory((byte*)s, (nuint)string.wcslen((char*)s) * sizeof(char));
             FreeCoTaskMem(s);
         }
 
@@ -946,7 +946,7 @@ namespace System.Runtime.InteropServices
             {
                 return;
             }
-            RuntimeImports.RhZeroMemory(s, (UIntPtr)string.strlen((byte*)s));
+            Buffer.ZeroMemory((byte*)s, (nuint)string.strlen((byte*)s));
             FreeCoTaskMem(s);
         }
 
@@ -956,7 +956,7 @@ namespace System.Runtime.InteropServices
             {
                 return;
             }
-            RuntimeImports.RhZeroMemory(s, (UIntPtr)string.strlen((byte*)s));
+            Buffer.ZeroMemory((byte*)s, (nuint)string.strlen((byte*)s));
             FreeHGlobal(s);
         }
 
@@ -966,7 +966,7 @@ namespace System.Runtime.InteropServices
             {
                 return;
             }
-            RuntimeImports.RhZeroMemory(s, (UIntPtr)(string.wcslen((char*)s) * 2));
+            Buffer.ZeroMemory((byte*)s, (nuint)string.wcslen((char*)s) * sizeof(char));
             FreeHGlobal(s);
         }
 
diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/SafeBSTRHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Security/SafeBSTRHandle.cs
deleted file mode 100644 (file)
index ceaf903..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace System.Security
-{
-    internal sealed class SafeBSTRHandle : SafeBuffer
-    {
-        internal SafeBSTRHandle() : base(true) { }
-
-        internal static SafeBSTRHandle Allocate(uint lenInChars)
-        {
-            ulong lenInBytes = (ulong)lenInChars * sizeof(char);
-            SafeBSTRHandle bstr = Interop.OleAut32.SysAllocStringLen(IntPtr.Zero, lenInChars);
-            if (bstr.IsInvalid) // SysAllocStringLen returns a NULL ptr when there's insufficient memory
-            {
-                throw new OutOfMemoryException();
-            }
-            bstr.Initialize(lenInBytes);
-            return bstr;
-        }
-
-        protected override bool ReleaseHandle()
-        {
-            RuntimeImports.RhZeroMemory(handle, (UIntPtr)Marshal.SysStringByteLen(handle));
-            Interop.OleAut32.SysFreeString(handle);
-            return true;
-        }
-
-        internal unsafe void ClearBuffer()
-        {
-            byte* bufferPtr = null;
-            try
-            {
-                AcquirePointer(ref bufferPtr);
-                RuntimeImports.RhZeroMemory((IntPtr)bufferPtr, (UIntPtr)Marshal.SysStringByteLen((IntPtr)bufferPtr));
-            }
-            finally
-            {
-                if (bufferPtr != null)
-                {
-                    ReleasePointer();
-                }
-            }
-        }
-
-        internal unsafe uint Length => Interop.OleAut32.SysStringLen(this);
-
-        internal static unsafe void Copy(SafeBSTRHandle source, SafeBSTRHandle target, uint bytesToCopy)
-        {
-            if (bytesToCopy == 0)
-            {
-                return;
-            }
-
-            byte* sourcePtr = null, targetPtr = null;
-            try
-            {
-                source.AcquirePointer(ref sourcePtr);
-                target.AcquirePointer(ref targetPtr);
-
-                Debug.Assert(source.ByteLength >= bytesToCopy, "Source buffer is too small.");
-                Buffer.MemoryCopy(sourcePtr, targetPtr, target.ByteLength, bytesToCopy);
-            }
-            finally
-            {
-                if (targetPtr != null)
-                {
-                    target.ReleasePointer();
-                }
-                if (sourcePtr != null)
-                {
-                    source.ReleasePointer();
-                }
-            }
-        }
-    }
-}
index 82b3833..d3fbd9b 100644 (file)
@@ -20,307 +20,19 @@ namespace System.Security
 
     public sealed partial class SecureString
     {
-        private UnmanagedBuffer? _buffer;
-
-        internal SecureString(SecureString str)
-        {
-            // Allocate enough space to store the provided string
-            EnsureCapacity(str._decryptedLength);
-            _decryptedLength = str._decryptedLength;
-
-            // Copy the string into the newly allocated space
-            if (_decryptedLength > 0)
-            {
-                Debug.Assert(str._buffer != null && _buffer != null); ;
-                UnmanagedBuffer.Copy(str._buffer, _buffer, (ulong)(str._decryptedLength * sizeof(char)));
-            }
-        }
-
-        private unsafe void InitializeSecureString(char* value, int length)
-        {
-            // Allocate enough space to store the provided string
-            EnsureCapacity(length);
-            _decryptedLength = length;
-            if (length == 0)
-            {
-                return;
-            }
-
-            Debug.Assert(_buffer != null);
-            // Copy the string into the newly allocated space
-            byte* ptr = null;
-            try
-            {
-                _buffer.AcquirePointer(ref ptr);
-                Buffer.MemoryCopy(value, ptr, _buffer.ByteLength, (ulong)(length * sizeof(char)));
-            }
-            finally
-            {
-                if (ptr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-        }
-
-        private void DisposeCore()
-        {
-            if (_buffer != null && !_buffer.IsInvalid)
-            {
-                _buffer.Dispose();
-                _buffer = null;
-            }
-        }
-
-        private void ClearCore()
+        private static int GetAlignedByteSize(int length)
         {
-            _decryptedLength = 0;
-            Debug.Assert(_buffer != null);
-            _buffer.Clear();
+            return Math.Max(length, 1) * sizeof(char);
         }
 
-        private unsafe void AppendCharCore(char c)
+        private void ProtectMemory()
         {
-            // Make sure we have enough space for the new character, then write it at the end.
-            EnsureCapacity(_decryptedLength + 1);
-            Debug.Assert(_buffer != null);
-            _buffer.Write((ulong)(_decryptedLength * sizeof(char)), c);
-            _decryptedLength++;
+            _encrypted = true;
         }
 
-        private unsafe void InsertAtCore(int index, char c)
+        private void UnprotectMemory()
         {
-            // Make sure we have enough space for the new character, then shift all of the characters above it and insert it.
-            EnsureCapacity(_decryptedLength + 1);
-            byte* ptr = null;
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref ptr);
-                ptr += index * sizeof(char);
-                long bytesToShift = (_decryptedLength - index) * sizeof(char);
-                Buffer.MemoryCopy(ptr, ptr + sizeof(char), bytesToShift, bytesToShift);
-                *((char*)ptr) = c;
-                ++_decryptedLength;
-            }
-            finally
-            {
-                if (ptr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-        }
-
-        private unsafe void RemoveAtCore(int index)
-        {
-            // Shift down all values above the specified index, then null out the empty space at the end.
-            byte* ptr = null;
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref ptr);
-                ptr += index * sizeof(char);
-                long bytesToShift = (_decryptedLength - index - 1) * sizeof(char);
-                Buffer.MemoryCopy(ptr + sizeof(char), ptr, bytesToShift, bytesToShift);
-                *((char*)(ptr + bytesToShift)) = (char)0;
-                --_decryptedLength;
-            }
-            finally
-            {
-                if (ptr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-        }
-
-        private void SetAtCore(int index, char c)
-        {
-            // Overwrite the character at the specified index
-            Debug.Assert(_buffer != null);
-            _buffer.Write((ulong)(index * sizeof(char)), c);
-        }
-
-        internal unsafe IntPtr MarshalToBSTRCore()
-        {
-            int length = _decryptedLength;
-            IntPtr ptr = IntPtr.Zero;
-            IntPtr result = IntPtr.Zero;
-            byte* bufferPtr = null;
-            Debug.Assert(_buffer != null);
-
-            try
-            {
-                _buffer.AcquirePointer(ref bufferPtr);
-                int resultByteLength = (length + 1) * sizeof(char);
-
-                ptr = Marshal.AllocBSTR(length);
-
-                Buffer.MemoryCopy(bufferPtr, (byte*)ptr, resultByteLength, length * sizeof(char));
-
-                result = ptr;
-            }
-            finally
-            {
-                // If we failed for any reason, free the new buffer
-                if (result == IntPtr.Zero && ptr != IntPtr.Zero)
-                {
-                    RuntimeImports.RhZeroMemory(ptr, (UIntPtr)(length * sizeof(char)));
-                    Marshal.FreeBSTR(ptr);
-                }
-
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-            return result;
-        }
-
-        internal unsafe IntPtr MarshalToStringCore(bool globalAlloc, bool unicode)
-        {
-            int length = _decryptedLength;
-
-            byte* bufferPtr = null;
-            IntPtr stringPtr = IntPtr.Zero, result = IntPtr.Zero;
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref bufferPtr);
-                if (unicode)
-                {
-                    int resultLength = (length + 1) * sizeof(char);
-                    stringPtr = globalAlloc ? Marshal.AllocHGlobal(resultLength) : Marshal.AllocCoTaskMem(resultLength);
-                    Buffer.MemoryCopy(
-                        source: bufferPtr,
-                        destination: (byte*)stringPtr.ToPointer(),
-                        destinationSizeInBytes: resultLength,
-                        sourceBytesToCopy: length * sizeof(char));
-                    *(length + (char*)stringPtr) = '\0';
-                }
-                else
-                {
-                    int resultLength = Encoding.UTF8.GetByteCount((char*)bufferPtr, length) + 1;
-                    stringPtr = globalAlloc ? Marshal.AllocHGlobal(resultLength) : Marshal.AllocCoTaskMem(resultLength);
-                    int encodedLength = Encoding.UTF8.GetBytes((char*)bufferPtr, length, (byte*)stringPtr, resultLength);
-                    Debug.Assert(encodedLength + 1 == resultLength, $"Expected encoded length to match result, got {encodedLength} != {resultLength}");
-                    *(resultLength - 1 + (byte*)stringPtr) = 0;
-                }
-
-                result = stringPtr;
-            }
-            finally
-            {
-                // If there was a failure, such that result isn't initialized,
-                // release the string if we had one.
-                if (stringPtr != IntPtr.Zero && result == IntPtr.Zero)
-                {
-                    RuntimeImports.RhZeroMemory(stringPtr, (UIntPtr)(length * sizeof(char)));
-                    MarshalFree(stringPtr, globalAlloc);
-                }
-
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-
-            return result;
-        }
-
-        // -----------------------------
-        // ---- PAL layer ends here ----
-        // -----------------------------
-
-        private void EnsureCapacity(int capacity)
-        {
-            // Make sure the requested capacity doesn't exceed SecureString's defined limit
-            if (capacity > MaxLength)
-            {
-                throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_Capacity);
-            }
-
-            // If we already have enough space allocated, we're done
-            if (_buffer != null && (capacity * sizeof(char)) <= (int)_buffer.ByteLength)
-            {
-                return;
-            }
-
-            // We need more space, so allocate a new buffer, copy all our data into it,
-            // and then swap the new for the old.
-            UnmanagedBuffer newBuffer = UnmanagedBuffer.Allocate(capacity * sizeof(char));
-            if (_buffer != null)
-            {
-                UnmanagedBuffer.Copy(_buffer, newBuffer, _buffer.ByteLength);
-                _buffer.Dispose();
-            }
-            _buffer = newBuffer;
-        }
-
-        /// <summary>SafeBuffer for managing memory meant to be kept confidential.</summary>
-        private sealed class UnmanagedBuffer : SafeBuffer
-        {
-            internal UnmanagedBuffer() : base(true) { }
-
-            internal static UnmanagedBuffer Allocate(int bytes)
-            {
-                Debug.Assert(bytes >= 0);
-                UnmanagedBuffer buffer = new UnmanagedBuffer();
-                buffer.SetHandle(Marshal.AllocHGlobal(bytes));
-                buffer.Initialize((ulong)bytes);
-                return buffer;
-            }
-
-            internal unsafe void Clear()
-            {
-                byte* ptr = null;
-                try
-                {
-                    AcquirePointer(ref ptr);
-                    RuntimeImports.RhZeroMemory((IntPtr)ptr, (UIntPtr)ByteLength);
-                }
-                finally
-                {
-                    if (ptr != null)
-                    {
-                        ReleasePointer();
-                    }
-                }
-            }
-
-            internal static unsafe void Copy(UnmanagedBuffer source, UnmanagedBuffer destination, ulong bytesLength)
-            {
-                if (bytesLength == 0)
-                {
-                    return;
-                }
-
-                byte* srcPtr = null, dstPtr = null;
-                try
-                {
-                    source.AcquirePointer(ref srcPtr);
-                    destination.AcquirePointer(ref dstPtr);
-                    Buffer.MemoryCopy(srcPtr, dstPtr, destination.ByteLength, bytesLength);
-                }
-                finally
-                {
-                    if (dstPtr != null)
-                    {
-                        destination.ReleasePointer();
-                    }
-                    if (srcPtr != null)
-                    {
-                        source.ReleasePointer();
-                    }
-                }
-            }
-
-            protected override unsafe bool ReleaseHandle()
-            {
-                Marshal.FreeHGlobal(handle);
-                return true;
-            }
+            _encrypted = false;
         }
     }
 }
index abf9f16..9e226ec 100644 (file)
@@ -11,271 +11,12 @@ namespace System.Security
 {
     public sealed partial class SecureString
     {
-        internal SecureString(SecureString str)
+        private static int GetAlignedByteSize(int length)
         {
-            Debug.Assert(str != null, "Expected non-null SecureString");
-            Debug.Assert(str._buffer != null, "Expected other SecureString's buffer to be non-null");
-            Debug.Assert(str._encrypted, "Expected to be used only on encrypted SecureStrings");
+            int byteSize = Math.Max(length, 1) * sizeof(char);
 
-            AllocateBuffer(str._buffer.Length);
-            Debug.Assert(_buffer != null);
-            SafeBSTRHandle.Copy(str._buffer, _buffer, str._buffer.Length * sizeof(char));
-
-            _decryptedLength = str._decryptedLength;
-            _encrypted = str._encrypted;
-        }
-
-        private unsafe void InitializeSecureString(char* value, int length)
-        {
-            Debug.Assert(length >= 0, $"Expected non-negative length, got {length}");
-
-            AllocateBuffer((uint)length);
-            _decryptedLength = length;
-
-            byte* bufferPtr = null;
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref bufferPtr);
-                Buffer.MemoryCopy((byte*)value, bufferPtr, (long)_buffer.ByteLength, length * sizeof(char));
-            }
-            finally
-            {
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-
-            ProtectMemory();
-        }
-
-        private void AppendCharCore(char c)
-        {
-            UnprotectMemory();
-            try
-            {
-                EnsureCapacity(_decryptedLength + 1);
-                Debug.Assert(_buffer != null);
-                _buffer.Write<char>((uint)_decryptedLength * sizeof(char), c);
-                _decryptedLength++;
-            }
-            finally
-            {
-                ProtectMemory();
-            }
-        }
-
-        private void ClearCore()
-        {
-            _decryptedLength = 0;
-            Debug.Assert(_buffer != null);
-            _buffer.ClearBuffer();
-        }
-
-        private void DisposeCore()
-        {
-            if (_buffer != null)
-            {
-                _buffer.Dispose();
-                _buffer = null;
-            }
-        }
-
-        private unsafe void InsertAtCore(int index, char c)
-        {
-            byte* bufferPtr = null;
-            UnprotectMemory();
-            Debug.Assert(_buffer != null);
-            try
-            {
-                EnsureCapacity(_decryptedLength + 1);
-
-                _buffer.AcquirePointer(ref bufferPtr);
-                char* pBuffer = (char*)bufferPtr;
-
-                for (int i = _decryptedLength; i > index; i--)
-                {
-                    pBuffer[i] = pBuffer[i - 1];
-                }
-                pBuffer[index] = c;
-                ++_decryptedLength;
-            }
-            finally
-            {
-                ProtectMemory();
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-        }
-
-        private unsafe void RemoveAtCore(int index)
-        {
-            byte* bufferPtr = null;
-            UnprotectMemory();
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref bufferPtr);
-                char* pBuffer = (char*)bufferPtr;
-
-                for (int i = index; i < _decryptedLength - 1; i++)
-                {
-                    pBuffer[i] = pBuffer[i + 1];
-                }
-                pBuffer[--_decryptedLength] = (char)0;
-            }
-            finally
-            {
-                ProtectMemory();
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-        }
-
-        private void SetAtCore(int index, char c)
-        {
-            UnprotectMemory();
-            try
-            {
-                Debug.Assert(_buffer != null);
-                _buffer.Write<char>((uint)index * sizeof(char), c);
-            }
-            finally
-            {
-                ProtectMemory();
-            }
-        }
-
-        internal unsafe IntPtr MarshalToBSTRCore()
-        {
-            int length = _decryptedLength;
-            IntPtr ptr = IntPtr.Zero;
-            IntPtr result = IntPtr.Zero;
-            byte* bufferPtr = null;
-
-            UnprotectMemory();
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref bufferPtr);
-                int resultByteLength = (length + 1) * sizeof(char);
-
-                ptr = Marshal.AllocBSTR(length);
-
-                Buffer.MemoryCopy(bufferPtr, (byte*)ptr, resultByteLength, length * sizeof(char));
-
-                result = ptr;
-            }
-            finally
-            {
-                ProtectMemory();
-
-                // If we failed for any reason, free the new buffer
-                if (result == IntPtr.Zero && ptr != IntPtr.Zero)
-                {
-                    RuntimeImports.RhZeroMemory(ptr, (UIntPtr)(length * sizeof(char)));
-                    Marshal.FreeBSTR(ptr);
-                }
-
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-            return result;
-        }
-
-        internal unsafe IntPtr MarshalToStringCore(bool globalAlloc, bool unicode)
-        {
-            int length = _decryptedLength;
-            IntPtr ptr = IntPtr.Zero;
-            IntPtr result = IntPtr.Zero;
-            byte* bufferPtr = null;
-
-            UnprotectMemory();
-            Debug.Assert(_buffer != null);
-            try
-            {
-                _buffer.AcquirePointer(ref bufferPtr);
-                if (unicode)
-                {
-                    int resultByteLength = (length + 1) * sizeof(char);
-                    ptr = globalAlloc ? Marshal.AllocHGlobal(resultByteLength) : Marshal.AllocCoTaskMem(resultByteLength);
-                    Buffer.MemoryCopy(bufferPtr, (byte*)ptr, resultByteLength, length * sizeof(char));
-                    *(length + (char*)ptr) = '\0';
-                }
-                else
-                {
-                    uint defaultChar = '?';
-                    int resultByteLength = 1 + Interop.Kernel32.WideCharToMultiByte(
-                        Interop.Kernel32.CP_ACP, Interop.Kernel32.WC_NO_BEST_FIT_CHARS, (char*)bufferPtr, length, null, 0, (IntPtr)(&defaultChar), IntPtr.Zero);
-                    ptr = globalAlloc ? Marshal.AllocHGlobal(resultByteLength) : Marshal.AllocCoTaskMem(resultByteLength);
-                    Interop.Kernel32.WideCharToMultiByte(
-                        Interop.Kernel32.CP_ACP, Interop.Kernel32.WC_NO_BEST_FIT_CHARS, (char*)bufferPtr, length, (byte*)ptr, resultByteLength - 1, (IntPtr)(&defaultChar), IntPtr.Zero);
-                    *(resultByteLength - 1 + (byte*)ptr) = 0;
-                }
-                result = ptr;
-            }
-            finally
-            {
-                ProtectMemory();
-
-                // If we failed for any reason, free the new buffer
-                if (result == IntPtr.Zero && ptr != IntPtr.Zero)
-                {
-                    RuntimeImports.RhZeroMemory(ptr, (UIntPtr)(length * sizeof(char)));
-                    MarshalFree(ptr, globalAlloc);
-                }
-
-                if (bufferPtr != null)
-                {
-                    _buffer.ReleasePointer();
-                }
-            }
-            return result;
-        }
-
-        // -----------------------------
-        // ---- PAL layer ends here ----
-        // -----------------------------
-
-        private const int BlockSize = (int)Interop.Crypt32.CRYPTPROTECTMEMORY_BLOCK_SIZE / sizeof(char);
-        private SafeBSTRHandle? _buffer;
-        private bool _encrypted;
-
-        private void AllocateBuffer(uint size)
-        {
-            _buffer = SafeBSTRHandle.Allocate(GetAlignedSize(size));
-        }
-
-        private static uint GetAlignedSize(uint size) =>
-            size == 0 || size % BlockSize != 0 ?
-                BlockSize + ((size / BlockSize) * BlockSize) :
-                size;
-
-        private void EnsureCapacity(int capacity)
-        {
-            if (capacity > MaxLength)
-            {
-                throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_Capacity);
-            }
-
-            Debug.Assert(_buffer != null);
-            if (((uint)capacity * sizeof(char)) <= _buffer.ByteLength)
-            {
-                return;
-            }
-
-            SafeBSTRHandle oldBuffer = _buffer;
-            SafeBSTRHandle newBuffer = SafeBSTRHandle.Allocate(GetAlignedSize((uint)capacity));
-            SafeBSTRHandle.Copy(oldBuffer, newBuffer, (uint)_decryptedLength * sizeof(char));
-            _buffer = newBuffer;
-            oldBuffer.Dispose();
+            const int blockSize = (int)Interop.Crypt32.CRYPTPROTECTMEMORY_BLOCK_SIZE;
+            return ((byteSize + (blockSize - 1)) / blockSize) * blockSize;
         }
 
         private void ProtectMemory()
@@ -285,7 +26,7 @@ namespace System.Security
 
             if (_decryptedLength != 0 &&
                 !_encrypted &&
-                !Interop.Crypt32.CryptProtectMemory(_buffer, _buffer.Length * sizeof(char), Interop.Crypt32.CRYPTPROTECTMEMORY_SAME_PROCESS))
+                !Interop.Crypt32.CryptProtectMemory(_buffer, (uint)_buffer.ByteLength, Interop.Crypt32.CRYPTPROTECTMEMORY_SAME_PROCESS))
             {
                 throw new CryptographicException(Marshal.GetLastWin32Error());
             }
@@ -300,7 +41,7 @@ namespace System.Security
 
             if (_decryptedLength != 0 &&
                 _encrypted &&
-                !Interop.Crypt32.CryptUnprotectMemory(_buffer, _buffer.Length * sizeof(char), Interop.Crypt32.CRYPTPROTECTMEMORY_SAME_PROCESS))
+                !Interop.Crypt32.CryptUnprotectMemory(_buffer, (uint)_buffer.ByteLength, Interop.Crypt32.CRYPTPROTECTMEMORY_SAME_PROCESS))
             {
                 throw new CryptographicException(Marshal.GetLastWin32Error());
             }
index c9a1eba..35deaba 100644 (file)
@@ -12,12 +12,14 @@ namespace System.Security
     {
         private const int MaxLength = 65536;
         private readonly object _methodLock = new object();
-        private bool _readOnly;
+        private UnmanagedBuffer? _buffer;
         private int _decryptedLength;
+        private bool _encrypted;
+        private bool _readOnly;
 
-        public unsafe SecureString()
+        public SecureString()
         {
-            InitializeSecureString(null, 0);
+            Initialize(ReadOnlySpan<char>.Empty);
         }
 
         [CLSCompliant(false)]
@@ -36,7 +38,38 @@ namespace System.Security
                 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_Length);
             }
 
-            InitializeSecureString(value, length);
+            Initialize(new ReadOnlySpan<char>(value, length));
+        }
+
+        private void Initialize(ReadOnlySpan<char> value)
+        {
+            _buffer = UnmanagedBuffer.Allocate(GetAlignedByteSize(value.Length));
+            _decryptedLength = value.Length;
+
+            SafeBuffer? bufferToRelease = null;
+            try
+            {
+                Span<char> span = AcquireSpan(ref bufferToRelease);
+                value.CopyTo(span);
+            }
+            finally
+            {
+                ProtectMemory();
+                bufferToRelease?.DangerousRelease();
+            }
+        }
+
+        private SecureString(SecureString str)
+        {
+            Debug.Assert(str._buffer != null, "Expected other SecureString's buffer to be non-null");
+            Debug.Assert(str._encrypted, "Expected to be used only on encrypted SecureStrings");
+
+            _buffer = UnmanagedBuffer.Allocate((int)str._buffer.ByteLength);
+            Debug.Assert(_buffer != null);
+            UnmanagedBuffer.Copy(str._buffer, _buffer, str._buffer.ByteLength);
+
+            _decryptedLength = str._decryptedLength;
+            _encrypted = str._encrypted;
         }
 
         public int Length
@@ -48,13 +81,52 @@ namespace System.Security
             }
         }
 
+        private void EnsureCapacity(int capacity)
+        {
+            if (capacity > MaxLength)
+            {
+                throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_Capacity);
+            }
+
+            Debug.Assert(_buffer != null);
+            if ((uint)capacity * sizeof(char) <= _buffer.ByteLength)
+            {
+                return;
+            }
+
+            UnmanagedBuffer oldBuffer = _buffer;
+            UnmanagedBuffer newBuffer = UnmanagedBuffer.Allocate(GetAlignedByteSize(capacity));
+            UnmanagedBuffer.Copy(oldBuffer, newBuffer, (uint)_decryptedLength * sizeof(char));
+            _buffer = newBuffer;
+            oldBuffer.Dispose();
+        }
+
         public void AppendChar(char c)
         {
             lock (_methodLock)
             {
                 EnsureNotDisposed();
                 EnsureNotReadOnly();
-                AppendCharCore(c);
+
+                Debug.Assert(_buffer != null);
+
+                SafeBuffer? bufferToRelease = null;
+
+                try
+                {
+                    UnprotectMemory();
+
+                    EnsureCapacity(_decryptedLength + 1);
+
+                    Span<char> span = AcquireSpan(ref bufferToRelease);
+                    span[_decryptedLength] = c;
+                    _decryptedLength++;
+                }
+                finally
+                {
+                    ProtectMemory();
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
@@ -65,7 +137,21 @@ namespace System.Security
             {
                 EnsureNotDisposed();
                 EnsureNotReadOnly();
-                ClearCore();
+
+                Debug.Assert(_buffer != null);
+
+                _decryptedLength = 0;
+
+                SafeBuffer? bufferToRelease = null;
+                try
+                {
+                    Span<char> span = AcquireSpan(ref bufferToRelease);
+                    span.Clear();
+                }
+                finally
+                {
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
@@ -83,7 +169,11 @@ namespace System.Security
         {
             lock (_methodLock)
             {
-                DisposeCore();
+                if (_buffer != null)
+                {
+                    _buffer.Dispose();
+                    _buffer = null;
+                }
             }
         }
 
@@ -99,7 +189,26 @@ namespace System.Security
                 EnsureNotDisposed();
                 EnsureNotReadOnly();
 
-                InsertAtCore(index, c);
+                Debug.Assert(_buffer != null);
+
+                SafeBuffer? bufferToRelease = null;
+
+                try
+                {
+                    UnprotectMemory();
+
+                    EnsureCapacity(_decryptedLength + 1);
+
+                    Span<char> span = AcquireSpan(ref bufferToRelease);
+                    span.Slice(index, _decryptedLength - index).CopyTo(span.Slice(index + 1));
+                    span[index] = c;
+                    _decryptedLength++;
+                }
+                finally
+                {
+                    ProtectMemory();
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
@@ -119,15 +228,31 @@ namespace System.Security
         {
             lock (_methodLock)
             {
-                EnsureNotDisposed();
-                EnsureNotReadOnly();
-
                 if (index < 0 || index >= _decryptedLength)
                 {
                     throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_IndexString);
                 }
 
-                RemoveAtCore(index);
+                EnsureNotDisposed();
+                EnsureNotReadOnly();
+
+                Debug.Assert(_buffer != null);
+
+                SafeBuffer? bufferToRelease = null;
+
+                try
+                {
+                    UnprotectMemory();
+
+                    Span<char> span = AcquireSpan(ref bufferToRelease);
+                    span.Slice(index + 1, _decryptedLength - (index + 1)).CopyTo(span.Slice(index));
+                    _decryptedLength--;
+                }
+                finally
+                {
+                    ProtectMemory();
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
@@ -139,15 +264,41 @@ namespace System.Security
                 {
                     throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_IndexString);
                 }
-                Debug.Assert(index <= int.MaxValue / sizeof(char));
 
                 EnsureNotDisposed();
                 EnsureNotReadOnly();
 
-                SetAtCore(index, c);
+                Debug.Assert(_buffer != null);
+
+                SafeBuffer? bufferToRelease = null;
+
+                try
+                {
+                    UnprotectMemory();
+
+                    Span<char> span = AcquireSpan(ref bufferToRelease);
+                    span[index] = c;
+                }
+                finally
+                {
+                    ProtectMemory();
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
+        private unsafe Span<char> AcquireSpan(ref SafeBuffer? bufferToRelease)
+        {
+            SafeBuffer buffer = _buffer!;
+
+            bool ignore = false;
+            buffer.DangerousAddRef(ref ignore);
+
+            bufferToRelease = buffer;
+
+            return new Span<char>((byte*)buffer.DangerousGetHandle(), (int)(buffer.ByteLength / 2));
+        }
+
         private void EnsureNotReadOnly()
         {
             if (_readOnly)
@@ -164,12 +315,41 @@ namespace System.Security
             }
         }
 
-        internal IntPtr MarshalToBSTR()
+        internal unsafe IntPtr MarshalToBSTR()
         {
             lock (_methodLock)
             {
                 EnsureNotDisposed();
-                return MarshalToBSTRCore();
+
+                UnprotectMemory();
+
+                SafeBuffer? bufferToRelease = null;
+                IntPtr ptr = IntPtr.Zero;
+                int length = 0;
+                try
+                {
+                    Span<char> span = AcquireSpan(ref bufferToRelease);
+
+                    length = _decryptedLength;
+                    ptr = Marshal.AllocBSTR(length);
+                    span.Slice(0, length).CopyTo(new Span<char>((void*)ptr, length));
+
+                    IntPtr result = ptr;
+                    ptr = IntPtr.Zero;
+                    return result;
+                }
+                finally
+                {
+                    // If we failed for any reason, free the new buffer
+                    if (ptr != IntPtr.Zero)
+                    {
+                        new Span<char>((void*)ptr, length).Clear();
+                        Marshal.FreeBSTR(ptr);
+                    }
+
+                    ProtectMemory();
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
@@ -178,19 +358,122 @@ namespace System.Security
             lock (_methodLock)
             {
                 EnsureNotDisposed();
-                return MarshalToStringCore(globalAlloc, unicode);
+
+                UnprotectMemory();
+
+                SafeBuffer? bufferToRelease = null;
+                IntPtr ptr = IntPtr.Zero;
+                int byteLength = 0;
+                try
+                {
+                    Span<char> span = AcquireSpan(ref bufferToRelease).Slice(0, _decryptedLength);
+
+                    if (unicode)
+                    {
+                        byteLength = (span.Length + 1) * sizeof(char);
+                    }
+                    else
+                    {
+                        byteLength = Marshal.GetAnsiStringByteCount(span);
+                    }
+
+                    if (globalAlloc)
+                    {
+                        ptr = Marshal.AllocHGlobal(byteLength);
+                    }
+                    else
+                    {
+                        ptr = Marshal.AllocCoTaskMem(byteLength);
+                    }
+
+                    if (unicode)
+                    {
+                        Span<char> resultSpan = new Span<char>((void*)ptr, byteLength / sizeof(char));
+                        span.CopyTo(resultSpan);
+                        resultSpan[resultSpan.Length - 1] = '\0';
+                    }
+                    else
+                    {
+                        Marshal.GetAnsiStringBytes(span, new Span<byte>((void*)ptr, byteLength));
+                    }
+
+                    IntPtr result = ptr;
+                    ptr = IntPtr.Zero;
+                    return result;
+                }
+                finally
+                {
+                    // If we failed for any reason, free the new buffer
+                    if (ptr != IntPtr.Zero)
+                    {
+                        new Span<byte>((void*)ptr, byteLength).Clear();
+
+                        if (globalAlloc)
+                        {
+                            Marshal.FreeHGlobal(ptr);
+                        }
+                        else
+                        {
+                            Marshal.FreeCoTaskMem(ptr);
+                        }
+                    }
+
+                    ProtectMemory();
+                    bufferToRelease?.DangerousRelease();
+                }
             }
         }
 
-        private static void MarshalFree(IntPtr ptr, bool globalAlloc)
+        /// <summary>SafeBuffer for managing memory meant to be kept confidential.</summary>
+        private sealed class UnmanagedBuffer : SafeBuffer
         {
-            if (globalAlloc)
+            // A local copy of byte length to be able to access it in ReleaseHandle without the risk of throwing exceptions
+            private int _byteLength;
+
+            private UnmanagedBuffer() : base(true) { }
+
+            public static UnmanagedBuffer Allocate(int byteLength)
             {
-                Marshal.FreeHGlobal(ptr);
+                Debug.Assert(byteLength >= 0);
+                UnmanagedBuffer buffer = new UnmanagedBuffer();
+                buffer.SetHandle(Marshal.AllocHGlobal(byteLength));
+                buffer.Initialize((ulong)byteLength);
+                buffer._byteLength = byteLength;
+                return buffer;
             }
-            else
+
+            internal static unsafe void Copy(UnmanagedBuffer source, UnmanagedBuffer destination, ulong bytesLength)
+            {
+                if (bytesLength == 0)
+                {
+                    return;
+                }
+
+                byte* srcPtr = null, dstPtr = null;
+                try
+                {
+                    source.AcquirePointer(ref srcPtr);
+                    destination.AcquirePointer(ref dstPtr);
+                    Buffer.MemoryCopy(srcPtr, dstPtr, destination.ByteLength, bytesLength);
+                }
+                finally
+                {
+                    if (dstPtr != null)
+                    {
+                        destination.ReleasePointer();
+                    }
+                    if (srcPtr != null)
+                    {
+                        source.ReleasePointer();
+                    }
+                }
+            }
+
+            protected override unsafe bool ReleaseHandle()
             {
-                Marshal.FreeCoTaskMem(ptr);
+                new Span<byte>((void*)handle, _byteLength).Clear();
+                Marshal.FreeHGlobal(handle);
+                return true;
             }
         }
     }
index 9f178f5..79b7347 100644 (file)
@@ -315,7 +315,7 @@ namespace System
                         else
                         {
                             // Find bitflag offset of first match and add to current offset
-                            return (int)(offset + (BitOperations.TrailingZeroCount(matches) / sizeof(char)));
+                            return (int)(offset + ((uint)BitOperations.TrailingZeroCount(matches) / sizeof(char)));
                         }
                     }
 
@@ -341,7 +341,7 @@ namespace System
 
                             // Find bitflag offset of first match and add to current offset,
                             // flags are in bytes so divide for chars
-                            return (int)(offset + (BitOperations.TrailingZeroCount(matches) / sizeof(char)));
+                            return (int)(offset + ((uint)BitOperations.TrailingZeroCount(matches) / sizeof(char)));
                         } while (lengthToExamine > 0);
                     }
 
@@ -365,7 +365,7 @@ namespace System
                         {
                             // Find bitflag offset of first match and add to current offset,
                             // flags are in bytes so divide for chars
-                            return (int)(offset + (BitOperations.TrailingZeroCount(matches) / sizeof(char)));
+                            return (int)(offset + ((uint)BitOperations.TrailingZeroCount(matches) / sizeof(char)));
                         }
                     }
 
@@ -404,7 +404,7 @@ namespace System
 
                             // Find bitflag offset of first match and add to current offset,
                             // flags are in bytes so divide for chars
-                            return (int)(offset + (BitOperations.TrailingZeroCount(matches) / sizeof(char)));
+                            return (int)(offset + ((uint)BitOperations.TrailingZeroCount(matches) / sizeof(char)));
                         } while (lengthToExamine > 0);
                     }
 
index 220f79e..d558758 100644 (file)
@@ -24,7 +24,7 @@ namespace System
                 return;
 
 #if AMD64 || ARM64
-            // The exact matrix on when RhZeroMemory is faster than InitBlockUnaligned is very complex. The factors to consider include
+            // The exact matrix on when ZeroMemory is faster than InitBlockUnaligned is very complex. The factors to consider include
             // type of hardware and memory aligment. This threshold was chosen as a good balance accross different configurations.
             if (byteLength > 768)
                 goto PInvoke;
@@ -336,7 +336,7 @@ namespace System
 #endif
 
         PInvoke:
-            RuntimeImports.RhZeroMemory(ref b, byteLength);
+            Buffer._ZeroMemory(ref b, byteLength);
         }
 
         public static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength)