From c4f7e13ea3b509b0510fd041c55f81d2f2da513c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Fri, 2 Feb 2024 12:49:11 +0100 Subject: [PATCH 01/11] [RISC-V] Skip ComputeReturnFlags in ArgIteratorTemplate::HasRetBuffArg ComputeReturnFlags on RISC-V is complicated due to ABI rules on enregistering small structs and it can even potentially trigger an unnecessary class load. So take a shortcut when we only need to check whether a struct is returned in a buffer. --- src/coreclr/vm/callingconvention.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 1c1f27ffc25293..79e5565cc668e0 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -419,7 +419,26 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE { WRAPPER_NO_CONTRACT; if (!(m_dwFlags & RETURN_FLAGS_COMPUTED)) + { +#ifdef TARGET_RISCV64 + // On RISC-V computing all return flags is complicated due to ABI rules on enregistering small structs + // so just check struct size and be done with it. + TypeHandle valueType; + switch (this->GetReturnType(&valueType)) + { + case ELEMENT_TYPE_TYPEDBYREF: + return (sizeof(TypedByRef) > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE); + case ELEMENT_TYPE_VALUETYPE: + assert(!valueType.IsNull()); + assert(!valueType.IsTypeDesc()); + return (valueType.GetSize() > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE); + default: + return false; + } +#else ComputeReturnFlags(); +#endif + } return (m_dwFlags & RETURN_HAS_RET_BUFFER); } From ff49a201e8b526d043a08b3fb3255d7fee2912d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Mon, 12 Feb 2024 12:17:30 +0100 Subject: [PATCH 02/11] Revert "[RISC-V] Skip ComputeReturnFlags in ArgIteratorTemplate::HasRetBuffArg" This reverts commit c4f7e13ea3b509b0510fd041c55f81d2f2da513c. --- src/coreclr/vm/callingconvention.h | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 79e5565cc668e0..1c1f27ffc25293 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -419,26 +419,7 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE { WRAPPER_NO_CONTRACT; if (!(m_dwFlags & RETURN_FLAGS_COMPUTED)) - { -#ifdef TARGET_RISCV64 - // On RISC-V computing all return flags is complicated due to ABI rules on enregistering small structs - // so just check struct size and be done with it. - TypeHandle valueType; - switch (this->GetReturnType(&valueType)) - { - case ELEMENT_TYPE_TYPEDBYREF: - return (sizeof(TypedByRef) > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE); - case ELEMENT_TYPE_VALUETYPE: - assert(!valueType.IsNull()); - assert(!valueType.IsTypeDesc()); - return (valueType.GetSize() > ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE); - default: - return false; - } -#else ComputeReturnFlags(); -#endif - } return (m_dwFlags & RETURN_HAS_RET_BUFFER); } From c1dd658772e6da40795e3a32f4293e5cabb7b976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Mon, 12 Feb 2024 14:23:42 +0100 Subject: [PATCH 03/11] [RISC-V] Call EnsureNativeLayoutInfoInitialized() for small structs during type load to avoid undue class loads from calling GetNativeLayoutInfo() in MethodTable::GetRiscV64PassStructInRegisterFlags during GC stackwalks --- src/coreclr/vm/class.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 6c0052636f6ae1..9f8993347f5589 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1222,6 +1222,17 @@ void ClassLoader::LoadExactParents(MethodTable* pMT) // We can now mark this type as having exact parents pMT->SetHasExactParent(); +#ifdef TARGET_RISCV64 + if (pMT->HasLayout() && + pMT->GetVerifierCorElementType() == ELEMENT_TYPE_VALUETYPE && + pMT->GetNumInstanceFieldBytes() <= ENREGISTERED_RETURNTYPE_MAXSIZE) + { + // To calculate how a small struct is enregistered RISC-V needs native layout info. + // Initializalize now so ArgIterator doesn't trigger undue class loads during GC stack walks. + pMT->EnsureNativeLayoutInfoInitialized(); + } +#endif + RETURN; } From 5e1d74583de8f2c9efdf67df54e071b4ece7e6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Mon, 12 Feb 2024 14:30:12 +0100 Subject: [PATCH 04/11] Remove stale comment --- src/coreclr/vm/classlayoutinfo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/classlayoutinfo.cpp b/src/coreclr/vm/classlayoutinfo.cpp index d982592de39eda..74dec16e2448b3 100644 --- a/src/coreclr/vm/classlayoutinfo.cpp +++ b/src/coreclr/vm/classlayoutinfo.cpp @@ -1023,7 +1023,6 @@ EEClassNativeLayoutInfo* EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetada { // The intrinsic Vector type has a special size. Copy the native size and alignment // from the managed size and alignment. - // Crossgen scenarios block Vector from even being loaded, so only do this check when not in crossgen. if (pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTORT))) { pNativeLayoutInfo->m_size = pEEClassLayoutInfo->GetManagedSize(); From 1168c379cba8569823851f585b1b8baf4eba7b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Mon, 12 Feb 2024 15:54:33 +0100 Subject: [PATCH 05/11] Typo in comment --- src/coreclr/vm/class.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 9f8993347f5589..3689416b145432 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1228,7 +1228,7 @@ void ClassLoader::LoadExactParents(MethodTable* pMT) pMT->GetNumInstanceFieldBytes() <= ENREGISTERED_RETURNTYPE_MAXSIZE) { // To calculate how a small struct is enregistered RISC-V needs native layout info. - // Initializalize now so ArgIterator doesn't trigger undue class loads during GC stack walks. + // Initialize now so ArgIterator doesn't trigger undue class loads during GC stack walks. pMT->EnsureNativeLayoutInfoInitialized(); } #endif From 0292f48e927efae208374be79c4e2e08e960571b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Fri, 8 Mar 2024 15:29:39 +0100 Subject: [PATCH 06/11] WiP: move EnsureNativeLayoutInfoInitialized() before SetHasExactParent() SetHasExactParent() is supposed to act like a barrier to ensure the native layout is loaded before other threads use it. --- src/coreclr/vm/appdomain.cpp | 12 ++++++++++++ src/coreclr/vm/appdomain.hpp | 8 ++++++++ src/coreclr/vm/class.cpp | 9 +++++---- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index feafd1f8abad6d..d605e067bbf5c4 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1379,6 +1379,18 @@ void SystemDomain::LoadBaseSystemClasses() g_pCastHelpers = CoreLibBinder::GetClass(CLASS__CASTHELPERS); + #ifdef TARGET_RISCV64 + // Used by EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetadataThrowing for comparison, + // preload now to avoid full loads during GC stack walks. + CoreLibBinder::GetClass(CLASS__VECTORT); + CoreLibBinder::GetClass(CLASS__INT128); + CoreLibBinder::GetClass(CLASS__UINT128); + CoreLibBinder::GetClass(CLASS__VECTOR64T); + CoreLibBinder::GetClass(CLASS__VECTOR128T); + CoreLibBinder::GetClass(CLASS__VECTOR256T); + CoreLibBinder::GetClass(CLASS__VECTOR512T); + #endif + #ifdef FEATURE_COMINTEROP if (g_pConfig->IsBuiltInCOMSupported()) { diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 5924e4f4b9fb53..a69396337deeea 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -2416,6 +2416,14 @@ class SystemDomain : public BaseDomain return System()->m_pSystemAssembly != NULL; } + static BOOL IsSystemActive() + { + WRAPPER_NO_CONTRACT; + + Assembly* sa = SystemAssembly(); + return sa != nullptr && sa->GetDomainAssembly()->IsActive(); + } + #ifndef DACCESS_COMPILE static GlobalStringLiteralMap *GetGlobalStringLiteralMap() { diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 3689416b145432..1c512447eb1819 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1219,13 +1219,11 @@ void ClassLoader::LoadExactParents(MethodTable* pMT) } #endif // FEATURE_METADATA_UPDATER - // We can now mark this type as having exact parents - pMT->SetHasExactParent(); - #ifdef TARGET_RISCV64 if (pMT->HasLayout() && pMT->GetVerifierCorElementType() == ELEMENT_TYPE_VALUETYPE && - pMT->GetNumInstanceFieldBytes() <= ENREGISTERED_RETURNTYPE_MAXSIZE) + pMT->GetNumInstanceFieldBytes() <= ENREGISTERED_RETURNTYPE_MAXSIZE && + SystemDomain::IsSystemActive()) { // To calculate how a small struct is enregistered RISC-V needs native layout info. // Initialize now so ArgIterator doesn't trigger undue class loads during GC stack walks. @@ -1233,6 +1231,9 @@ void ClassLoader::LoadExactParents(MethodTable* pMT) } #endif + // We can now mark this type as having exact parents + pMT->SetHasExactParent(); + RETURN; } From 3d730d27d0d39a0051f6972bb73ef540c1dbb783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 13 Mar 2024 08:27:31 +0100 Subject: [PATCH 07/11] Remove initializing native layout info for small structs during type load Managed->managed calling convention should not depend on native info which is used for interop marshalling with unmanaged code which is above the type loader. --- src/coreclr/vm/appdomain.cpp | 12 ------------ src/coreclr/vm/appdomain.hpp | 8 -------- src/coreclr/vm/class.cpp | 12 ------------ 3 files changed, 32 deletions(-) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index d605e067bbf5c4..feafd1f8abad6d 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1379,18 +1379,6 @@ void SystemDomain::LoadBaseSystemClasses() g_pCastHelpers = CoreLibBinder::GetClass(CLASS__CASTHELPERS); - #ifdef TARGET_RISCV64 - // Used by EEClassNativeLayoutInfo::CollectNativeLayoutFieldMetadataThrowing for comparison, - // preload now to avoid full loads during GC stack walks. - CoreLibBinder::GetClass(CLASS__VECTORT); - CoreLibBinder::GetClass(CLASS__INT128); - CoreLibBinder::GetClass(CLASS__UINT128); - CoreLibBinder::GetClass(CLASS__VECTOR64T); - CoreLibBinder::GetClass(CLASS__VECTOR128T); - CoreLibBinder::GetClass(CLASS__VECTOR256T); - CoreLibBinder::GetClass(CLASS__VECTOR512T); - #endif - #ifdef FEATURE_COMINTEROP if (g_pConfig->IsBuiltInCOMSupported()) { diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index a69396337deeea..5924e4f4b9fb53 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -2416,14 +2416,6 @@ class SystemDomain : public BaseDomain return System()->m_pSystemAssembly != NULL; } - static BOOL IsSystemActive() - { - WRAPPER_NO_CONTRACT; - - Assembly* sa = SystemAssembly(); - return sa != nullptr && sa->GetDomainAssembly()->IsActive(); - } - #ifndef DACCESS_COMPILE static GlobalStringLiteralMap *GetGlobalStringLiteralMap() { diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 1c512447eb1819..6c0052636f6ae1 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -1219,18 +1219,6 @@ void ClassLoader::LoadExactParents(MethodTable* pMT) } #endif // FEATURE_METADATA_UPDATER -#ifdef TARGET_RISCV64 - if (pMT->HasLayout() && - pMT->GetVerifierCorElementType() == ELEMENT_TYPE_VALUETYPE && - pMT->GetNumInstanceFieldBytes() <= ENREGISTERED_RETURNTYPE_MAXSIZE && - SystemDomain::IsSystemActive()) - { - // To calculate how a small struct is enregistered RISC-V needs native layout info. - // Initialize now so ArgIterator doesn't trigger undue class loads during GC stack walks. - pMT->EnsureNativeLayoutInfoInitialized(); - } -#endif - // We can now mark this type as having exact parents pMT->SetHasExactParent(); From d543f74d943b275d3825b2a0787232bc7bee11d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 13 Mar 2024 08:49:38 +0100 Subject: [PATCH 08/11] Don't use native layout in GetRiscV64PassStructInRegisterFlags unless we're calculating flags for a native value type --- src/coreclr/vm/methodtable.cpp | 46 +++++++++------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 41307b3d1a8f23..9f746d85dd2536 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3420,18 +3420,12 @@ bool MethodTable::IsRiscV64OnlyOneField(MethodTable * pMT) { TypeHandle th(pMT); - bool useNativeLayout = false; - bool ret = false; - MethodTable* pMethodTable = nullptr; + bool ret = false; if (!th.IsTypeDesc()) { - pMethodTable = th.AsMethodTable(); - if (pMethodTable->HasLayout()) - { - useNativeLayout = true; - } - else if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) + MethodTable* pMethodTable = th.AsMethodTable(); + if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) { DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); @@ -3454,20 +3448,13 @@ bool MethodTable::IsRiscV64OnlyOneField(MethodTable * pMT) } } } - goto _End_arg; } } else { _ASSERTE(th.IsNativeValueType()); + MethodTable* pMethodTable = th.AsNativeValueType(); - useNativeLayout = true; - pMethodTable = th.AsNativeValueType(); - } - _ASSERTE(pMethodTable != nullptr); - - if (useNativeLayout) - { if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) { DWORD numIntroducedFields = pMethodTable->GetNativeLayoutInfo()->GetNumFields(); @@ -3526,18 +3513,12 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) { TypeHandle th(cls); - bool useNativeLayout = false; int size = STRUCT_NO_FLOAT_FIELD; - MethodTable* pMethodTable = nullptr; if (!th.IsTypeDesc()) { - pMethodTable = th.AsMethodTable(); - if (pMethodTable->HasLayout()) - { - useNativeLayout = true; - } - else if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) + MethodTable* pMethodTable = th.AsMethodTable(); + if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) { DWORD numIntroducedFields = pMethodTable->GetNumIntroducedInstanceFields(); @@ -3584,6 +3565,11 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) goto _End_arg; } + if (pFieldFirst->GetSize() > pFieldSecond->GetOffset()) + { + goto _End_arg; + } + CorElementType fieldType = pFieldFirst[0].GetFieldType(); if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) { @@ -3701,21 +3687,13 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) size |= STRUCT_SECOND_FIELD_SIZE_IS8; } } - - goto _End_arg; } } else { _ASSERTE(th.IsNativeValueType()); + MethodTable* pMethodTable = th.AsNativeValueType(); - useNativeLayout = true; - pMethodTable = th.AsNativeValueType(); - } - _ASSERTE(pMethodTable != nullptr); - - if (useNativeLayout) - { if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) { DWORD numIntroducedFields = pMethodTable->GetNativeLayoutInfo()->GetNumFields(); From 5ec4cb73c894a30a77712f1e96aeb3bae5ebc00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 13 Mar 2024 12:41:03 +0100 Subject: [PATCH 09/11] Remove redundant assertions, AsNativeValueType() has the same --- src/coreclr/vm/methodtable.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 93f859f9449eb0..0bbc835b3e178f 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3452,7 +3452,6 @@ bool MethodTable::IsRiscV64OnlyOneField(MethodTable * pMT) } else { - _ASSERTE(th.IsNativeValueType()); MethodTable* pMethodTable = th.AsNativeValueType(); if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) @@ -3691,7 +3690,6 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) } else { - _ASSERTE(th.IsNativeValueType()); MethodTable* pMethodTable = th.AsNativeValueType(); if (th.GetSize() <= 16 /*MAX_PASS_MULTIREG_BYTES*/) From 0f2006a6b935dc2ec5bb55f2bacf7c5fa82cbf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 14 Mar 2024 09:00:05 +0100 Subject: [PATCH 10/11] Cover implied repeated fields, a.k.a fixed arrays, in when calculating small struct flags from non-native layout --- src/coreclr/vm/methodtable.cpp | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 0bbc835b3e178f..320ffdb77529fa 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3527,6 +3527,44 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) CorElementType fieldType = pFieldStart[0].GetFieldType(); + // InlineArray types and fixed buffer types have implied repeated fields. + // Checking if a type is an InlineArray type is cheap, so we'll do that first. + bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); + + if (hasImpliedRepeatedFields) + { + numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); + if (numIntroducedFields > 2) + { + goto _End_arg; + } + + if (fieldType == ELEMENT_TYPE_R4) + { + if (numIntroducedFields == 1) + { + size = STRUCT_FLOAT_FIELD_ONLY_ONE; + } + else if (numIntroducedFields == 2) + { + size = STRUCT_FLOAT_FIELD_ONLY_TWO; + } + goto _End_arg; + } + else if (fieldType == ELEMENT_TYPE_R8) + { + if (numIntroducedFields == 1) + { + size = STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8; + } + else if (numIntroducedFields == 2) + { + size = STRUCT_FIELD_TWO_DOUBLES; + } + goto _End_arg; + } + } + if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) { if (fieldType == ELEMENT_TYPE_R4) From 10aacbc964f54ae9320c987d60540580cb256151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 14 Mar 2024 10:02:09 +0100 Subject: [PATCH 11/11] Cover implied repeated fields, a.k.a fixed arrays, also in non-native branch of IsRiscV64OnlyOneField --- src/coreclr/vm/methodtable.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 320ffdb77529fa..8683e3ce672b5a 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -3435,6 +3435,19 @@ bool MethodTable::IsRiscV64OnlyOneField(MethodTable * pMT) CorElementType fieldType = pFieldStart[0].GetFieldType(); + // InlineArray types and fixed buffer types have implied repeated fields. + // Checking if a type is an InlineArray type is cheap, so we'll do that first. + bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(pMethodTable); + + if (hasImpliedRepeatedFields) + { + numIntroducedFields = pMethodTable->GetNumInstanceFieldBytes() / pFieldStart->GetSize(); + if (numIntroducedFields != 1) + { + goto _End_arg; + } + } + if (CorTypeInfo::IsPrimitiveType_NoThrow(fieldType)) { ret = true;