Add a fast path for byte[] to Buffer.BlockCopy
authorJan Kotas <jkotas@microsoft.com>
Wed, 10 Feb 2016 17:18:13 +0000 (09:18 -0800)
committerJan Kotas <jkotas@microsoft.com>
Thu, 11 Feb 2016 01:06:43 +0000 (17:06 -0800)
src/inc/dacvars.h
src/vm/appdomain.cpp
src/vm/comutilnative.cpp
src/vm/vars.cpp
src/vm/vars.hpp

index 310717b..f4c7523 100644 (file)
@@ -235,6 +235,7 @@ DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pPredefinedArrayTypes, ::g_pPr
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_ArgumentHandleMT, ::g_ArgumentHandleMT)
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_ArgIteratorMT, ::g_ArgIteratorMT)
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_TypedReferenceMT, ::g_TypedReferenceMT)
+DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pByteArrayMT, ::g_pByteArrayMT)
 
 #ifdef FEATURE_COMINTEROP
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pBaseCOMObject, ::g_pBaseCOMObject)
index f695cc2..9ab8c7d 100644 (file)
@@ -2918,6 +2918,10 @@ void SystemDomain::LoadBaseSystemClasses()
     _ASSERTE(g_pStringClass->GetBaseSize() == ObjSizeOf(StringObject)+sizeof(WCHAR));
     _ASSERTE(g_pStringClass->GetComponentSize() == 2);
 
+    // Used by Buffer::BlockCopy
+    g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
+        TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
+
 #ifndef CROSSGEN_COMPILE
     ECall::PopulateManagedStringConstructors();
 
index d8a0a0c..d405bda 100644 (file)
@@ -1402,7 +1402,6 @@ void QCALLTYPE ExceptionNative::GetMessageFromNativeResources(ExceptionMessageKi
     END_QCALL;
 }
 
-
 // BlockCopy
 // This method from one primitive array to another based
 //  upon an offset into each an a byte count.
@@ -1416,20 +1415,37 @@ FCIMPL5(VOID, Buffer::BlockCopy, ArrayBase *src, int srcOffset, ArrayBase *dst,
     if (src==NULL || dst==NULL)
         FCThrowArgumentNullVoid((src==NULL) ? W("src") : W("dst"));
 
-    // Size of the Arrays in bytes
-    SIZE_T srcLen = src->GetNumComponents() * src->GetComponentSize();
-    SIZE_T dstLen = srcLen;
+    SIZE_T srcLen, dstLen;
 
-    // We only want to allow arrays of primitives, no Objects.
-    const CorElementType srcET = src->GetArrayElementType();
-    if (!CorTypeInfo::IsPrimitiveType_NoThrow(srcET))
-        FCThrowArgumentVoid(W("src"), W("Arg_MustBePrimArray"));
+    //
+    // Use specialized fast path for byte arrays because of it is what Buffer::BlockCopy is 
+    // typically used for.
+    //
 
-    if (src != dst) {
-        const CorElementType dstET = dst->GetArrayElementType();
-        if (!CorTypeInfo::IsPrimitiveType_NoThrow(dstET))
-            FCThrowArgumentVoid(W("dest"), W("Arg_MustBePrimArray"));
-        dstLen = dst->GetNumComponents() * dst->GetComponentSize();
+    MethodTable * pByteArrayMT = g_pByteArrayMT;
+    _ASSERTE(pByteArrayMT != NULL);
+    if (src->GetMethodTable() == pByteArrayMT &&  dst->GetMethodTable() == pByteArrayMT)
+    {
+        srcLen = src->GetNumComponents();
+        dstLen = dst->GetNumComponents();
+    }
+    else
+    {
+        // Size of the Arrays in bytes
+        srcLen = src->GetNumComponents() * src->GetComponentSize();
+        dstLen = srcLen;
+
+        // We only want to allow arrays of primitives, no Objects.
+        const CorElementType srcET = src->GetArrayElementType();
+        if (!CorTypeInfo::IsPrimitiveType_NoThrow(srcET))
+            FCThrowArgumentVoid(W("src"), W("Arg_MustBePrimArray"));
+
+        if (src != dst) {
+            const CorElementType dstET = dst->GetArrayElementType();
+            if (!CorTypeInfo::IsPrimitiveType_NoThrow(dstET))
+                FCThrowArgumentVoid(W("dest"), W("Arg_MustBePrimArray"));
+            dstLen = dst->GetNumComponents() * dst->GetComponentSize();
+        }
     }
 
     if (srcOffset < 0 || dstOffset < 0 || count < 0) {
index 4e5d299..a425a67 100644 (file)
@@ -88,6 +88,8 @@ GPTR_IMPL(MethodTable,      g_ArgumentHandleMT);
 GPTR_IMPL(MethodTable,      g_ArgIteratorMT);
 GPTR_IMPL(MethodTable,      g_TypedReferenceMT);
 
+GPTR_IMPL(MethodTable,      g_pByteArrayMT);
+
 #ifdef FEATURE_COMINTEROP
 GPTR_IMPL(MethodTable,      g_pBaseCOMObject);
 GPTR_IMPL(MethodTable,      g_pBaseRuntimeClass);
index aa14488..faab0bc 100644 (file)
@@ -427,6 +427,8 @@ GPTR_DECL(MethodTable,      g_ArgumentHandleMT);
 GPTR_DECL(MethodTable,      g_ArgIteratorMT);
 GPTR_DECL(MethodTable,      g_TypedReferenceMT);
 
+GPTR_DECL(MethodTable,      g_pByteArrayMT);
+
 #ifdef FEATURE_COMINTEROP
 GPTR_DECL(MethodTable,      g_pBaseCOMObject);
 GPTR_DECL(MethodTable,      g_pBaseRuntimeClass);