From 62462b38d79c1cd8bb888a5afab86ea8275fa789 Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Fri, 25 Sep 2020 16:42:54 -0700 Subject: [PATCH] SIngle-pass `CopyValueClassUnchecked` (#42654) * use memmoveGCRefs when copying structs with GC references * no need for a full fence when copying struct without GC references --- src/coreclr/src/vm/object.cpp | 78 +++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/src/coreclr/src/vm/object.cpp b/src/coreclr/src/vm/object.cpp index 5537573..fad929a 100644 --- a/src/coreclr/src/vm/object.cpp +++ b/src/coreclr/src/vm/object.cpp @@ -335,62 +335,36 @@ void STDCALL CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT) _ASSERTE(!pMT->IsArray()); // bunch of assumptions about arrays wrong. - // @todo Only call MemoryBarrier() if needed. - // Reflection is a known use case where this is required. - // Unboxing is a use case where this should not be required. - // - MemoryBarrier(); - - // Copy the bulk of the data, and any non-GC refs. - switch (pMT->GetNumInstanceFieldBytes()) + if (pMT->ContainsPointers()) { - case 1: - *(UINT8*)dest = *(UINT8*)src; - break; -#ifndef ALIGN_ACCESS - // we can hit an alignment fault if the value type has multiple - // smaller fields. Example: if there are two I4 fields, the - // value class can be aligned to 4-byte boundaries, yet the - // NumInstanceFieldBytes is 8 - case 2: - *(UINT16*)dest = *(UINT16*)src; - break; - case 4: - *(UINT32*)dest = *(UINT32*)src; - break; - case 8: - *(UINT64*)dest = *(UINT64*)src; - break; -#endif // !ALIGN_ACCESS - default: - memcpyNoGCRefs(dest, src, pMT->GetNumInstanceFieldBytes()); - break; + memmoveGCRefs(dest, src, pMT->GetNumInstanceFieldBytes()); } - - // Tell the GC about any copies. - if (pMT->ContainsPointers()) + else { - CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT); - CGCDescSeries* cur = map->GetHighestSeries(); - CGCDescSeries* last = map->GetLowestSeries(); - DWORD size = pMT->GetBaseSize(); - _ASSERTE(cur >= last); - do + switch (pMT->GetNumInstanceFieldBytes()) { - // offset to embedded references in this series must be - // adjusted by the VTable pointer, when in the unboxed state. - size_t offset = cur->GetSeriesOffset() - sizeof(void*); - OBJECTREF* srcPtr = (OBJECTREF*)(((BYTE*) src) + offset); - OBJECTREF* destPtr = (OBJECTREF*)(((BYTE*) dest) + offset); - OBJECTREF* srcPtrStop = (OBJECTREF*)((BYTE*) srcPtr + cur->GetSeriesSize() + size); - while (srcPtr < srcPtrStop) - { - SetObjectReference(destPtr, ObjectToOBJECTREF(*(Object**)srcPtr)); - srcPtr++; - destPtr++; - } - cur--; - } while (cur >= last); + case 1: + *(UINT8*)dest = *(UINT8*)src; + break; +#ifndef ALIGN_ACCESS + // we can hit an alignment fault if the value type has multiple + // smaller fields. Example: if there are two I4 fields, the + // value class can be aligned to 4-byte boundaries, yet the + // NumInstanceFieldBytes is 8 + case 2: + *(UINT16*)dest = *(UINT16*)src; + break; + case 4: + *(UINT32*)dest = *(UINT32*)src; + break; + case 8: + *(UINT64*)dest = *(UINT64*)src; + break; +#endif // !ALIGN_ACCESS + default: + memcpyNoGCRefs(dest, src, pMT->GetNumInstanceFieldBytes()); + break; + } } } -- 2.7.4