summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>2018-10-03 09:32:34 -0700
committerGitHub <noreply@github.com>2018-10-03 09:32:34 -0700
commit302630ed5a3730470e9ffeeebcd38c737c03963d (patch)
tree2e505233d6172d86cfdbb8fb29d6951e8d0cf244
parentb68296ce2c56188cf2a7bd263903e27c67717702 (diff)
downloadcoreclr-302630ed5a3730470e9ffeeebcd38c737c03963d.tar.gz
coreclr-302630ed5a3730470e9ffeeebcd38c737c03963d.tar.bz2
coreclr-302630ed5a3730470e9ffeeebcd38c737c03963d.zip
Marshal blittable structs via memcpy even if nested within non-blittable struct (#20194)
* Add regression test for dotnet/coreclr#18521. * Add custom marshaler for fixed buffers that acts as a scalar memory copy of the length of the fixed buffer. * Remove regression test. Moving it to a unit test in corefx. * Move attribute class name into classnames.h * Remove unreachable code left over from debugging. * Marshal fixed buffers by reusing the field marshaler of the single field to pretend that there are multiple fields consecutively in the structure. * Remove now-dead code paths. * Use initializers in FieldMarshaler_NestedValueClass constructor where appropriate. * Clean up IsFixedBuffer implementation. * Remove unused GC_PROTECTs. * Specifically check that the attribute exists, not just that there wasn't an error. * Fix missing else statement. * Add asserts so we don't corrupt the heap. * Add unit test for masked bug (incorrect native size of structure calculated). * Don't use new behavior on non-blittable fixed buffers. * Revert "Add unit test for masked bug (incorrect native size of structure calculated)." This reverts commit 496eef5906638c3c2696ede0d922a5e707447b4e. * Use memcpy instead of field emulation. * Remove unused forward-declared class. * Clean up code. Refactor one GetMethodTable call I missed. * Remove now-unneeded custom attribute includes. More diff cleanup. * Remove unneeded FixedBufferAttribute define.
-rw-r--r--src/vm/fieldmarshaler.cpp54
1 files changed, 37 insertions, 17 deletions
diff --git a/src/vm/fieldmarshaler.cpp b/src/vm/fieldmarshaler.cpp
index 50f12a838d..9cee183f4b 100644
--- a/src/vm/fieldmarshaler.cpp
+++ b/src/vm/fieldmarshaler.cpp
@@ -2036,7 +2036,6 @@ VOID LayoutUpdateNative(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, Metho
GCPROTECT_END();
}
-
VOID FmtClassUpdateNative(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
{
CONTRACTL
@@ -2115,7 +2114,7 @@ VOID FmtClassUpdateCLR(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData)
// all of the native fields even if one or more of the conversions fail.
//=======================================================================
VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE *pNativeData)
-{
+{
CONTRACTL
{
THROWS;
@@ -2128,8 +2127,8 @@ VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTa
// Don't try to destroy/free native the structure on exception, we may not own it. If we do own it and
// are supposed to destroy/free it, we do it upstack (e.g. in a helper called from the marshaling stub).
- FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
- UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
+ FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
+ UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
struct _gc
{
@@ -2137,10 +2136,10 @@ VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTa
OBJECTREF pOldCLRValue;
} gc;
- gc.pCLRValue = NULL;
+ gc.pCLRValue = NULL;
gc.pOldCLRValue = NULL;
- LPVOID scalar = NULL;
-
+ LPVOID scalar = NULL;
+
GCPROTECT_BEGIN(gc)
GCPROTECT_BEGININTERIOR(scalar)
{
@@ -2873,12 +2872,21 @@ VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateNativeImpl(const VOI
}
CONTRACTL_END;
+ MethodTable* pMT = GetMethodTable();
+
// would be better to detect this at class load time (that have a nested value
// class with no layout) but don't have a way to know
- if (! GetMethodTable()->GetLayoutInfo())
+ if (!pMT->GetLayoutInfo())
COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
- LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, GetMethodTable(), (BYTE*)pNative, ppCleanupWorkListOnStack);
+ if (pMT->IsBlittable())
+ {
+ memcpyNoGCRefs(pNative, (BYTE*)(*ppProtectedCLR) + startoffset, pMT->GetNativeSize());
+ }
+ else
+ {
+ LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, pMT, (BYTE*)pNative, ppCleanupWorkListOnStack);
+ }
}
@@ -2898,17 +2906,24 @@ VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateCLRImpl(const VOID *
}
CONTRACTL_END;
+ MethodTable* pMT = GetMethodTable();
+
// would be better to detect this at class load time (that have a nested value
// class with no layout) but don't have a way to know
- if (! GetMethodTable()->GetLayoutInfo())
+ if (!pMT->GetLayoutInfo())
COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
- LayoutUpdateCLR( (LPVOID*)ppProtectedCLR,
- startoffset,
- GetMethodTable(),
- (BYTE *)pNative);
-
-
+ if (pMT->IsBlittable())
+ {
+ memcpyNoGCRefs((BYTE*)(*ppProtectedCLR) + startoffset, pNative, pMT->GetNativeSize());
+ }
+ else
+ {
+ LayoutUpdateCLR((LPVOID*)ppProtectedCLR,
+ startoffset,
+ pMT,
+ (BYTE *)pNative);
+ }
}
@@ -2927,7 +2942,12 @@ VOID FieldMarshaler_NestedValueClass::DestroyNativeImpl(LPVOID pNativeValue) con
}
CONTRACTL_END;
- LayoutDestroyNative(pNativeValue, GetMethodTable());
+ MethodTable* pMT = GetMethodTable();
+
+ if (!pMT->IsBlittable())
+ {
+ LayoutDestroyNative(pNativeValue, pMT);
+ }
}
#endif // CROSSGEN_COMPILE