From da7b00b4fb57321773e5a8f5bed1efcc46108307 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 25 Feb 2023 09:35:45 -0800
Subject: [PATCH 01/30] initial port from the prototype
---
src/coreclr/inc/corinfo.h | 2 +-
.../tools/Common/JitInterface/CorInfoImpl.cs | 12 +++
.../tools/Common/JitInterface/CorInfoTypes.cs | 2 +-
.../Common/MetadataFieldLayoutAlgorithm.cs | 45 +++++++++
.../Utilities/GCPointerMap.Algorithm.cs | 44 +++++++--
src/coreclr/vm/class.h | 12 ++-
src/coreclr/vm/jitinterface.cpp | 4 +
src/coreclr/vm/methodtablebuilder.cpp | 96 ++++++++++++++-----
src/coreclr/vm/methodtablebuilder.h | 1 +
9 files changed, 181 insertions(+), 37 deletions(-)
diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 28531e00bee5f5..b405a6edfaa17c 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -852,7 +852,7 @@ enum CorInfoFlag
CORINFO_FLG_ARRAY = 0x00080000, // class is an array class (initialized differently)
CORINFO_FLG_OVERLAPPING_FIELDS = 0x00100000, // struct or class has fields that overlap (aka union)
CORINFO_FLG_INTERFACE = 0x00200000, // it is an interface
- CORINFO_FLG_DONT_DIG_FIELDS = 0x00400000, // don't ask field info, AOT can't rely on it (used for types outside of AOT compilation version bubble)
+ CORINFO_FLG_DONT_DIG_FIELDS = 0x00400000, // don't ask field info (used for types outside of AOT compilation version bubble and value arrays)
CORINFO_FLG_CUSTOMLAYOUT = 0x00800000, // does this struct have custom layout?
CORINFO_FLG_CONTAINS_GC_PTR = 0x01000000, // does the class contain a gc ptr ?
CORINFO_FLG_DELEGATE = 0x02000000, // is this a subclass of delegate or multicast delegate ?
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index fbb17f280b5e56..90004d1fda84c9 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -2043,6 +2043,18 @@ private uint getClassAttribsInternal(TypeDesc type)
result |= CorInfoFlag.CORINFO_FLG_ABSTRACT;
}
+ // TODO: VS disable struct promotion for valArr
+ //if (type is InstantiatedType it)
+ //{
+ // if (it.Name == "ValueArray`2" && it.Namespace == "System")
+ // {
+ // if (it.Instantiation[1] is ArrayType arr && arr.Rank > 1)
+ // {
+ // result |= CorInfoFlag.CORINFO_FLG_DONT_DIG_FIELDS;
+ // }
+ // }
+ //}
+
#if READYTORUN
if (!_compilation.CompilationModuleGroup.VersionsWithType(type))
{
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
index a3d920666ed494..f1b57271461b50 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
@@ -602,7 +602,7 @@ public enum CorInfoFlag : uint
CORINFO_FLG_ARRAY = 0x00080000, // class is an array class (initialized differently)
CORINFO_FLG_OVERLAPPING_FIELDS = 0x00100000, // struct or class has fields that overlap (aka union)
CORINFO_FLG_INTERFACE = 0x00200000, // it is an interface
- CORINFO_FLG_DONT_DIG_FIELDS = 0x00400000, // don't try to ask about fields outside of AOT compilation version bubble
+ CORINFO_FLG_DONT_DIG_FIELDS = 0x00400000, // don't try to ask about fields outside of AOT compilation version bubble or value arrays
CORINFO_FLG_CUSTOMLAYOUT = 0x00800000, // does this struct have custom layout?
CORINFO_FLG_CONTAINS_GC_PTR = 0x01000000, // does the class contain a gc ptr ?
CORINFO_FLG_DELEGATE = 0x02000000, // is this a subclass of delegate or multicast delegate ?
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
index f3b7b9442f5bbe..645efdd873c4b4 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
@@ -358,6 +358,28 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
layoutMetadata.Size,
out instanceByteSizeAndAlignment);
+ // TODO: VS adjust size
+ //if (type is InstantiatedType it)
+ //{
+ // if (it.Name == "ValueArray`2" && it.Namespace == "System")
+ // {
+ // if (it.Instantiation[1] is ArrayType arr)
+ // {
+ // int repeat = arr.Rank;
+
+ // if (!instanceSizeAndAlignment.Size.IsIndeterminate)
+ // {
+ // instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
+ // }
+
+ // if (!instanceByteSizeAndAlignment.Size.IsIndeterminate)
+ // {
+ // instanceByteSizeAndAlignment.Size = new LayoutInt(instanceByteSizeAndAlignment.Size.AsInt * repeat);
+ // }
+ // }
+ // }
+ //}
+
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
{
IsAutoLayoutOrHasAutoLayoutFields = hasAutoLayoutField,
@@ -746,6 +768,29 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
classLayoutSize: 0,
byteCount: out instanceByteSizeAndAlignment);
+ // TODO: VS adjust size
+ //if (type is InstantiatedType it)
+ //{
+ // if (it.Name == "ValueArray`2" && it.Namespace == "System")
+ // {
+ // if (it.Instantiation[1] is ArrayType arr)
+ // {
+ // int repeat = arr.Rank;
+
+ // if (!instanceSizeAndAlignment.Size.IsIndeterminate)
+ // {
+ // instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
+ // }
+
+ // if (!instanceByteSizeAndAlignment.Size.IsIndeterminate)
+ // {
+ // instanceByteSizeAndAlignment.Size = new LayoutInt(instanceByteSizeAndAlignment.Size.AsInt * repeat);
+ // }
+ // }
+ // }
+ //}
+
+
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
{
IsAutoLayoutOrHasAutoLayoutFields = true,
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs
index eca01c4b3a4587..28eb4a25eef12d 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs
@@ -14,21 +14,36 @@ public static GCPointerMap FromInstanceLayout(DefType type)
{
Debug.Assert(type.ContainsGCPointers);
- GCPointerMapBuilder builder = new GCPointerMapBuilder(type.InstanceByteCount.AsInt, type.Context.Target.PointerSize);
- FromInstanceLayoutHelper(ref builder, type);
+ int pointerSize = type.Context.Target.PointerSize;
+ GCPointerMapBuilder builder = new GCPointerMapBuilder(type.InstanceByteCount.AsInt, pointerSize);
+ FromInstanceLayoutHelper(ref builder, type, pointerSize);
return builder.ToGCMap();
}
- private static void FromInstanceLayoutHelper(ref GCPointerMapBuilder builder, DefType type)
+ private static void FromInstanceLayoutHelper(ref GCPointerMapBuilder builder, DefType type, int pointerSize)
{
if (!type.IsValueType && type.HasBaseType)
{
DefType baseType = type.BaseType;
GCPointerMapBuilder baseLayoutBuilder = builder.GetInnerBuilder(0, baseType.InstanceByteCount.AsInt);
- FromInstanceLayoutHelper(ref baseLayoutBuilder, baseType);
+ FromInstanceLayoutHelper(ref baseLayoutBuilder, baseType, pointerSize);
}
+ int repeat = 1;
+
+ //TODO: VS compute repeat
+ //if (type is InstantiatedType it)
+ //{
+ // if (it.Name == "ValueArray`2" && it.Namespace == "System")
+ // {
+ // if (it.Instantiation[1] is ArrayType arr)
+ // {
+ // repeat = arr.Rank;
+ // }
+ // }
+ //}
+
foreach (FieldDesc field in type.GetFields())
{
if (field.IsStatic)
@@ -37,16 +52,23 @@ private static void FromInstanceLayoutHelper(ref GCPointerMapBuilder builder, De
TypeDesc fieldType = field.FieldType;
if (fieldType.IsGCPointer)
{
- builder.MarkGCPointer(field.Offset.AsInt);
+ for (int i = 0; i < repeat; i++)
+ {
+ builder.MarkGCPointer(field.Offset.AsInt + pointerSize * i);
+ }
}
else if (fieldType.IsValueType)
{
var fieldDefType = (DefType)fieldType;
if (fieldDefType.ContainsGCPointers)
{
- GCPointerMapBuilder innerBuilder =
- builder.GetInnerBuilder(field.Offset.AsInt, fieldDefType.InstanceByteCount.AsInt);
- FromInstanceLayoutHelper(ref innerBuilder, fieldDefType);
+ for (int i = 0; i < repeat; i++)
+ {
+ int fieldSize = fieldDefType.InstanceByteCount.AsInt;
+ GCPointerMapBuilder innerBuilder =
+ builder.GetInnerBuilder(field.Offset.AsInt + fieldSize * i, fieldSize);
+ FromInstanceLayoutHelper(ref innerBuilder, fieldDefType, pointerSize);
+ }
}
}
}
@@ -76,9 +98,10 @@ public static GCPointerMap FromStaticLayout(DefType type)
var fieldDefType = (DefType)fieldType;
if (fieldDefType.ContainsGCPointers)
{
+ int pointerSize = type.Context.Target.PointerSize;
GCPointerMapBuilder innerBuilder =
builder.GetInnerBuilder(field.Offset.AsInt, fieldDefType.InstanceByteCount.AsInt);
- FromInstanceLayoutHelper(ref innerBuilder, fieldDefType);
+ FromInstanceLayoutHelper(ref innerBuilder, fieldDefType, pointerSize);
}
}
}
@@ -109,9 +132,10 @@ public static GCPointerMap FromThreadStaticLayout(DefType type)
var fieldDefType = (DefType)fieldType;
if (fieldDefType.ContainsGCPointers)
{
+ int pointerSize = type.Context.Target.PointerSize;
GCPointerMapBuilder innerBuilder =
builder.GetInnerBuilder(field.Offset.AsInt, fieldDefType.InstanceByteCount.AsInt);
- FromInstanceLayoutHelper(ref innerBuilder, fieldDefType);
+ FromInstanceLayoutHelper(ref innerBuilder, fieldDefType, pointerSize);
}
}
}
diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h
index 22ef2b9919cc19..0ee0e5352dfb38 100644
--- a/src/coreclr/vm/class.h
+++ b/src/coreclr/vm/class.h
@@ -1384,6 +1384,16 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
LIMITED_METHOD_CONTRACT;
m_VMFlags |= (DWORD)VMFLAG_HAS_FIELDS_WHICH_MUST_BE_INITED;
}
+ BOOL HasValueArrayFlagSet()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_VMFlags & VMFLAG_VALUE_ARRAY);
+ }
+ void SetValueArrayFlag()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_VMFlags |= (DWORD)VMFLAG_VALUE_ARRAY;
+ }
void SetCannotBeBlittedByObjectCloner()
{
/* no op */
@@ -1723,7 +1733,7 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
VMFLAG_BESTFITMAPPING = 0x00004000, // BestFitMappingAttribute.Value
VMFLAG_THROWONUNMAPPABLECHAR = 0x00008000, // BestFitMappingAttribute.ThrowOnUnmappableChar
- // unused = 0x00010000,
+ VMFLAG_VALUE_ARRAY = 0x00010000,
VMFLAG_NO_GUID = 0x00020000,
VMFLAG_HASNONPUBLICFIELDS = 0x00040000,
VMFLAG_HAS_CUSTOM_FIELD_ALIGNMENT = 0x00080000,
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 8e888542fecfdc..30d7145bc8020c 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -3552,6 +3552,10 @@ uint32_t CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
}
if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverlaidField())
ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
+
+ if (pClass->HasValueArrayFlagSet())
+ ret |= CORINFO_FLG_DONT_DIG_FIELDS;
+
if (VMClsHnd.IsCanonicalSubtype())
ret |= CORINFO_FLG_SHAREDINST;
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index 35a7ddb0360a6d..9b8cfa1853eb00 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -1694,6 +1694,25 @@ MethodTableBuilder::BuildMethodTableThrowing(
&pByValueClassCache, bmtMFDescs, bmtFP,
&totalDeclaredFieldSize);
+ // TODO: VS detect valArr
+ //if (!bmtGenericsInfo->fContainsGenericVariables &&
+ // g_pValueArrayClass != NULL &&
+ // g_pValueArrayClass->GetCl() == GetCl() &&
+ // g_pValueArrayClass->GetModule() == bmtInternal->pType->GetModule())
+ //{
+ // TypeHandle lengthMarker = bmtGenericsInfo->GetInstantiation()[1];
+ // if (lengthMarker.IsArray())
+ // {
+ // DWORD rank = lengthMarker.GetRank();
+ // if (rank > 1)
+ // {
+ // bmtFP->NumValueArrayElements = rank;
+ // // there is no scenario when tearing a value array into pieces is desirable.
+ // GetHalfBakedClass()->SetValueArrayFlag();
+ // }
+ // }
+ //}
+
// Place regular static fields
PlaceRegularStaticFields();
@@ -1713,6 +1732,11 @@ MethodTableBuilder::BuildMethodTableThrowing(
_ASSERTE(HasLayout());
+ if (bmtFP->NumValueArrayElements)
+ {
+ GetLayoutInfo()->m_cbManagedSize *= bmtFP->NumValueArrayElements;
+ }
+
bmtFP->NumInstanceFieldBytes = GetLayoutInfo()->m_cbManagedSize;
// For simple Blittable types we still need to check if they have any overlapping
@@ -8318,6 +8342,16 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach
BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
}
+ if (bmtFP->NumValueArrayElements > 0)
+ {
+ dwNumInstanceFieldBytes *= bmtFP->NumValueArrayElements;
+
+ if (pFieldDescList[0].IsByValue())
+ {
+ dwNumGCPointerSeries *= bmtFP->NumValueArrayElements;
+ }
+ }
+
bmtFP->NumInstanceFieldBytes = dwNumInstanceFieldBytes;
bmtFP->NumGCPointerSeries = dwNumGCPointerSeries;
@@ -11494,12 +11528,19 @@ VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCac
}
+ DWORD repeat = 1;
+ if (bmtFP->NumValueArrayElements > 0)
+ {
+ _ASSERTE(bmtEnumFields->dwNumInstanceFields == 1);
+ repeat = bmtFP->NumValueArrayElements;
+ }
+
// Build the pointer series map for this pointers in this instance
pSeries = ((CGCDesc*)pMT)->GetLowestSeries();
if (bmtFP->NumInstanceGCPointerFields)
{
// See gcdesc.h for an explanation of why we adjust by subtracting BaseSize
- pSeries->SetSeriesSize( (size_t) (bmtFP->NumInstanceGCPointerFields * TARGET_POINTER_SIZE) - (size_t) pMT->GetBaseSize());
+ pSeries->SetSeriesSize((size_t)(bmtFP->NumInstanceGCPointerFields * repeat * TARGET_POINTER_SIZE) - (size_t)pMT->GetBaseSize());
pSeries->SetSeriesOffset(bmtFP->GCPointerFieldStart + OBJECT_SIZE);
pSeries++;
}
@@ -11509,44 +11550,51 @@ VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCac
{
if (pFieldDescList[i].IsByValue())
{
- MethodTable *pByValueMT = pByValueClassCache[i];
+ MethodTable* pByValueMT = pByValueClassCache[i];
if (pByValueMT->ContainsPointers())
{
// Offset of the by value class in the class we are building, does NOT include Object
DWORD dwCurrentOffset = pFieldDescList[i].GetOffset_NoLogging();
+ DWORD dwElementSize = pByValueMT->GetBaseSize() - OBJECT_BASESIZE;
- // The by value class may have more than one pointer series
- CGCDescSeries * pByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetLowestSeries();
- SIZE_T dwNumByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
-
- for (SIZE_T j = 0; j < dwNumByValueSeries; j++)
+ for (DWORD r = 0; r < repeat; r++)
{
- size_t cbSeriesSize;
- size_t cbSeriesOffset;
+ // The by value class may have more than one pointer series
+ CGCDescSeries* pByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetLowestSeries();
+ SIZE_T dwNumByValueSeries = CGCDesc::GetCGCDescFromMT(pByValueMT)->GetNumSeries();
- _ASSERTE(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
+ for (SIZE_T j = 0; j < dwNumByValueSeries; j++)
+ {
+ size_t cbSeriesSize;
+ size_t cbSeriesOffset;
+
+ _ASSERTE(pSeries <= CGCDesc::GetCGCDescFromMT(pMT)->GetHighestSeries());
- cbSeriesSize = pByValueSeries->GetSeriesSize();
+ cbSeriesSize = pByValueSeries->GetSeriesSize();
- // Add back the base size of the by value class, since it's being transplanted to this class
- cbSeriesSize += pByValueMT->GetBaseSize();
+ // Add back the base size of the by value class, since it's being transplanted to this class
+ cbSeriesSize += pByValueMT->GetBaseSize();
- // Subtract the base size of the class we're building
- cbSeriesSize -= pMT->GetBaseSize();
+ // Subtract the base size of the class we're building
+ cbSeriesSize -= pMT->GetBaseSize();
- // Set current series we're building
- pSeries->SetSeriesSize(cbSeriesSize);
+ // Set current series we're building
+ pSeries->SetSeriesSize(cbSeriesSize);
- // Get offset into the value class of the first pointer field (includes a +Object)
- cbSeriesOffset = pByValueSeries->GetSeriesOffset();
+ // Get offset into the value class of the first pointer field (includes a +Object)
+ cbSeriesOffset = pByValueSeries->GetSeriesOffset();
- // Add it to the offset of the by value class in our class
- cbSeriesOffset += dwCurrentOffset;
+ // Add element N offset
+ cbSeriesOffset += r * dwElementSize;
- pSeries->SetSeriesOffset(cbSeriesOffset); // Offset of field
- pSeries++;
- pByValueSeries++;
+ // Add it to the offset of the by value class in our class
+ cbSeriesOffset += dwCurrentOffset;
+
+ pSeries->SetSeriesOffset(cbSeriesOffset); // Offset of field
+ pSeries++;
+ pByValueSeries++;
+ }
}
}
}
diff --git a/src/coreclr/vm/methodtablebuilder.h b/src/coreclr/vm/methodtablebuilder.h
index 739a8e530f1320..e1361707051ce7 100644
--- a/src/coreclr/vm/methodtablebuilder.h
+++ b/src/coreclr/vm/methodtablebuilder.h
@@ -2011,6 +2011,7 @@ class MethodTableBuilder
DWORD NumInstanceGCPointerFields; // does not include inherited pointer fields
DWORD NumGCPointerSeries;
DWORD NumInstanceFieldBytes;
+ DWORD NumValueArrayElements;
bool fIsByRefLikeType;
bool fHasFixedAddressValueTypes;
From 170a306a29aaafa3f9504b7e3f3e89a3454dea5e Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 25 Feb 2023 18:44:52 -0800
Subject: [PATCH 02/30] parse the attribute in MT builder
---
src/coreclr/vm/methodtablebuilder.cpp | 61 ++++++++++++++++++---------
src/coreclr/vm/siginfo.cpp | 8 +++-
src/coreclr/vm/wellknownattributes.h | 3 ++
3 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index 9b8cfa1853eb00..8dc637b8fe61fa 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -1694,24 +1694,44 @@ MethodTableBuilder::BuildMethodTableThrowing(
&pByValueClassCache, bmtMFDescs, bmtFP,
&totalDeclaredFieldSize);
- // TODO: VS detect valArr
- //if (!bmtGenericsInfo->fContainsGenericVariables &&
- // g_pValueArrayClass != NULL &&
- // g_pValueArrayClass->GetCl() == GetCl() &&
- // g_pValueArrayClass->GetModule() == bmtInternal->pType->GetModule())
- //{
- // TypeHandle lengthMarker = bmtGenericsInfo->GetInstantiation()[1];
- // if (lengthMarker.IsArray())
- // {
- // DWORD rank = lengthMarker.GetRank();
- // if (rank > 1)
- // {
- // bmtFP->NumValueArrayElements = rank;
- // // there is no scenario when tearing a value array into pieces is desirable.
- // GetHalfBakedClass()->SetValueArrayFlag();
- // }
- // }
- //}
+ if (IsValueClass())
+ {
+ const void* pVal; // The custom value.
+ ULONG cbVal; // Size of the custom value.
+ HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
+ WellKnownAttribute::InlineArrayAttribute,
+ &pVal, &cbVal);
+
+ if (hr != S_FALSE)
+ {
+ if (bmtEnumFields->dwNumInstanceFields != 1)
+ {
+ // TODO: diagnostics, must have one field.
+ BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
+ }
+
+ if (cbVal >= (sizeof(INT32) + 2))
+ {
+ INT32 repeat = GET_UNALIGNED_VAL32((byte*)pVal + 2);
+ if (repeat > 0)
+ {
+ bmtFP->NumValueArrayElements = repeat;
+ GetHalfBakedClass()->SetValueArrayFlag();
+ }
+ else
+ {
+ // TODO: diagnostics, repeat must be > 0
+ BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
+ }
+
+ if (HasExplicitFieldOffsetLayout())
+ {
+ // TODO: diagnostics, must not have explicit offsets
+ BuildMethodTableThrowException(IDS_CLASSLOAD_GENERAL);
+ }
+ }
+ }
+ }
// Place regular static fields
PlaceRegularStaticFields();
@@ -8342,8 +8362,9 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach
BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
}
- if (bmtFP->NumValueArrayElements > 0)
+ if (bmtFP->NumValueArrayElements > 1)
{
+ // TODO: VS validate that size < FIELD_OFFSET_LAST_REAL_OFFSET
dwNumInstanceFieldBytes *= bmtFP->NumValueArrayElements;
if (pFieldDescList[0].IsByValue())
@@ -11529,7 +11550,7 @@ VOID MethodTableBuilder::HandleGCForValueClasses(MethodTable ** pByValueClassCac
}
DWORD repeat = 1;
- if (bmtFP->NumValueArrayElements > 0)
+ if (bmtFP->NumValueArrayElements > 1)
{
_ASSERTE(bmtEnumFields->dwNumInstanceFields == 1);
repeat = bmtFP->NumValueArrayElements;
diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp
index 0a15fbb91488fe..3815ae4f70c31f 100644
--- a/src/coreclr/vm/siginfo.cpp
+++ b/src/coreclr/vm/siginfo.cpp
@@ -4846,6 +4846,9 @@ class ByRefPointerOffsetsReporter
_ASSERTE(pMT != nullptr);
_ASSERTE(pMT->IsByRefLike());
+ int repeat = 1; // TODO: VS fetch val arr repeat
+ UINT repeatSize = 0; // TODO: VS fetch actual repeat size
+
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc* pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
@@ -4859,7 +4862,10 @@ class ByRefPointerOffsetsReporter
}
else if (pFD->IsByRef())
{
- Report(baseOffset + pFD->GetOffset());
+ for (int i = 0; i < repeat; i++)
+ {
+ Report(baseOffset + (repeatSize * i) + pFD->GetOffset());
+ }
}
}
}
diff --git a/src/coreclr/vm/wellknownattributes.h b/src/coreclr/vm/wellknownattributes.h
index f1ac8a69767505..837f75c2ac083b 100644
--- a/src/coreclr/vm/wellknownattributes.h
+++ b/src/coreclr/vm/wellknownattributes.h
@@ -36,6 +36,7 @@ enum class WellKnownAttribute : DWORD
WinRTMarshalingBehaviorAttribute,
PreserveBaseOverridesAttribute,
ObjectiveCTrackedTypeAttribute,
+ InlineArrayAttribute,
CountOfWellKnownAttributes
};
@@ -104,6 +105,8 @@ inline const char *GetWellKnownAttributeName(WellKnownAttribute attribute)
return "System.Runtime.CompilerServices.PreserveBaseOverridesAttribute";
case WellKnownAttribute::ObjectiveCTrackedTypeAttribute:
return "System.Runtime.InteropServices.ObjectiveC.ObjectiveCTrackedTypeAttribute";
+ case WellKnownAttribute::InlineArrayAttribute:
+ return "System.Runtime.CompilerServices.InlineArrayAttribute";
case WellKnownAttribute::CountOfWellKnownAttributes:
default:
break; // Silence compiler warnings
From bb1c3db399f3eeedbb0ec020d4cd8c5084e18ecd Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 25 Feb 2023 18:56:36 -0800
Subject: [PATCH 03/30] validate replicated size
---
src/coreclr/vm/methodtablebuilder.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index 8dc637b8fe61fa..84c15a5a4c0eb3 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -8364,8 +8364,12 @@ VOID MethodTableBuilder::PlaceInstanceFields(MethodTable ** pByValueClassCach
if (bmtFP->NumValueArrayElements > 1)
{
- // TODO: VS validate that size < FIELD_OFFSET_LAST_REAL_OFFSET
- dwNumInstanceFieldBytes *= bmtFP->NumValueArrayElements;
+ INT64 extendedSize = (INT64)dwNumInstanceFieldBytes * (INT64)bmtFP->NumValueArrayElements;
+ if (extendedSize > FIELD_OFFSET_LAST_REAL_OFFSET) {
+ BuildMethodTableThrowException(IDS_CLASSLOAD_FIELDTOOLARGE);
+ }
+
+ dwNumInstanceFieldBytes = (DWORD)extendedSize;
if (pFieldDescList[0].IsByValue())
{
From 0a4cd782d542a3963a78bf439dc7af0f7f2598fd Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sun, 26 Feb 2023 11:01:39 -0800
Subject: [PATCH 04/30] aot changes
---
.../tools/Common/JitInterface/CorInfoImpl.cs | 15 +----
.../Common/InstantiatedType.Metadata.cs | 5 ++
.../TypeSystem/Common/InstantiatedType.cs | 3 +
.../Common/MetadataFieldLayoutAlgorithm.cs | 65 +++++++------------
.../Common/TypeSystem/Common/MetadataType.cs | 7 ++
.../Common/TypeSystem/Common/TypeDesc.cs | 11 ++++
.../Common/TypeSystem/Common/TypeFlags.cs | 7 +-
.../Utilities/GCPointerMap.Algorithm.cs | 16 ++---
.../tools/Common/TypeSystem/Ecma/EcmaType.cs | 20 ++++++
.../ReadyToRun/GCRefMapBuilder.cs | 23 ++++++-
src/coreclr/vm/siginfo.cpp | 39 +++++++----
11 files changed, 127 insertions(+), 84 deletions(-)
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 90004d1fda84c9..064a1a60fba26f 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -2027,6 +2027,9 @@ private uint getClassAttribsInternal(TypeDesc type)
if (type.IsIntrinsic)
result |= CorInfoFlag.CORINFO_FLG_INTRINSIC_TYPE;
+ if (type.IsValueArray)
+ result |= CorInfoFlag.CORINFO_FLG_DONT_DIG_FIELDS;
+
if (metadataType != null)
{
if (metadataType.ContainsGCPointers)
@@ -2043,18 +2046,6 @@ private uint getClassAttribsInternal(TypeDesc type)
result |= CorInfoFlag.CORINFO_FLG_ABSTRACT;
}
- // TODO: VS disable struct promotion for valArr
- //if (type is InstantiatedType it)
- //{
- // if (it.Name == "ValueArray`2" && it.Namespace == "System")
- // {
- // if (it.Instantiation[1] is ArrayType arr && arr.Rank > 1)
- // {
- // result |= CorInfoFlag.CORINFO_FLG_DONT_DIG_FIELDS;
- // }
- // }
- //}
-
#if READYTORUN
if (!_compilation.CompilationModuleGroup.VersionsWithType(type))
{
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.Metadata.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.Metadata.cs
index d917b342e56a4b..13c82bb314bba5 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.Metadata.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.Metadata.cs
@@ -86,6 +86,11 @@ public override bool HasCustomAttribute(string attributeNamespace, string attrib
return _typeDef.HasCustomAttribute(attributeNamespace, attributeName);
}
+ public override int GetValueArrayLength()
+ {
+ return _typeDef.GetValueArrayLength();
+ }
+
public override MetadataType GetNestedType(string name)
{
// Return the result from the typical type definition.
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs
index 0df6089d42320d..ab97f2a9b415e5 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs
@@ -106,6 +106,9 @@ protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
if (_typeDef.IsByRefLike)
flags |= TypeFlags.IsByRefLike;
+ if (_typeDef.IsValueArray)
+ flags |= TypeFlags.IsValueArray;
+
AddComputedIntrinsicFlag(ref flags);
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
index 645efdd873c4b4..bafdcf50304e8b 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-
using Debug = System.Diagnostics.Debug;
namespace Internal.TypeSystem
@@ -358,27 +357,11 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
layoutMetadata.Size,
out instanceByteSizeAndAlignment);
- // TODO: VS adjust size
- //if (type is InstantiatedType it)
- //{
- // if (it.Name == "ValueArray`2" && it.Namespace == "System")
- // {
- // if (it.Instantiation[1] is ArrayType arr)
- // {
- // int repeat = arr.Rank;
-
- // if (!instanceSizeAndAlignment.Size.IsIndeterminate)
- // {
- // instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
- // }
-
- // if (!instanceByteSizeAndAlignment.Size.IsIndeterminate)
- // {
- // instanceByteSizeAndAlignment.Size = new LayoutInt(instanceByteSizeAndAlignment.Size.AsInt * repeat);
- // }
- // }
- // }
- //}
+ // value array cannot have explicit layout
+ if(type.IsValueArray)
+ {
+ ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
+ }
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
{
@@ -768,28 +751,24 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
classLayoutSize: 0,
byteCount: out instanceByteSizeAndAlignment);
- // TODO: VS adjust size
- //if (type is InstantiatedType it)
- //{
- // if (it.Name == "ValueArray`2" && it.Namespace == "System")
- // {
- // if (it.Instantiation[1] is ArrayType arr)
- // {
- // int repeat = arr.Rank;
-
- // if (!instanceSizeAndAlignment.Size.IsIndeterminate)
- // {
- // instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
- // }
-
- // if (!instanceByteSizeAndAlignment.Size.IsIndeterminate)
- // {
- // instanceByteSizeAndAlignment.Size = new LayoutInt(instanceByteSizeAndAlignment.Size.AsInt * repeat);
- // }
- // }
- // }
- //}
+ if (type.IsValueArray)
+ {
+ int repeat = type.GetValueArrayLength();
+
+ // UNDONE: VS validate resulting size.
+ // UNDONE: VS validate repeat > 0.
+
+ if (!instanceSizeAndAlignment.Size.IsIndeterminate)
+ {
+ instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
+ }
+
+ if (!instanceByteSizeAndAlignment.Size.IsIndeterminate)
+ {
+ instanceByteSizeAndAlignment.Size = new LayoutInt(instanceByteSizeAndAlignment.Size.AsInt * repeat);
+ }
+ }
ComputedInstanceFieldLayout computedLayout = new ComputedInstanceFieldLayout
{
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataType.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataType.cs
index 72b0aeadba86c4..eff3f996d83f54 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataType.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataType.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Diagnostics;
namespace Internal.TypeSystem
{
@@ -90,6 +91,12 @@ public virtual bool IsModuleType
/// doesn't exist.
///
public abstract MetadataType GetNestedType(string name);
+
+ public virtual int GetValueArrayLength()
+ {
+ Debug.Assert(this.IsValueArray);
+ return 1;
+ }
}
public struct ClassLayoutMetadata
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs
index ae83551e2bd0e3..8600be5ab7438d 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs
@@ -676,6 +676,17 @@ public bool IsByRefLike
}
}
+ ///
+ /// Gets a value indicating whether this is a value array type
+ ///
+ public bool IsValueArray
+ {
+ get
+ {
+ return (GetTypeFlags(TypeFlags.IsValueArray | TypeFlags.AttributeCacheComputed) & TypeFlags.IsValueArray) != 0;
+ }
+ }
+
///
/// Gets a value indicating whether this type implements IDynamicInterfaceCastable
///
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeFlags.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeFlags.cs
index 6331f50a891b28..526ea27a197f3e 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/TypeFlags.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeFlags.cs
@@ -57,10 +57,11 @@ public enum TypeFlags
HasFinalizer = 0x2000,
IsByRefLike = 0x04000,
- AttributeCacheComputed = 0x08000,
+ IsValueArray = 0x08000,
IsIntrinsic = 0x10000,
+ AttributeCacheComputed = 0x20000,
- IsIDynamicInterfaceCastable = 0x20000,
- IsIDynamicInterfaceCastableComputed = 0x40000,
+ IsIDynamicInterfaceCastable = 0x40000,
+ IsIDynamicInterfaceCastableComputed = 0x80000,
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs
index 28eb4a25eef12d..bfac78495a22fb 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs
@@ -31,18 +31,10 @@ private static void FromInstanceLayoutHelper(ref GCPointerMapBuilder builder, De
}
int repeat = 1;
-
- //TODO: VS compute repeat
- //if (type is InstantiatedType it)
- //{
- // if (it.Name == "ValueArray`2" && it.Namespace == "System")
- // {
- // if (it.Instantiation[1] is ArrayType arr)
- // {
- // repeat = arr.Rank;
- // }
- // }
- //}
+ if (type.IsValueArray)
+ {
+ repeat = ((MetadataType)type).GetValueArrayLength();
+ }
foreach (FieldDesc field in type.GetFields())
{
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs
index 348b2f6e79c5a8..332b8dd758e068 100644
--- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
@@ -260,6 +261,13 @@ protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
if (stringComparer.Equals(nameHandle, "IntrinsicAttribute") &&
stringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices"))
flags |= TypeFlags.IsIntrinsic;
+
+ if (isValueType &&
+ stringComparer.Equals(nameHandle, "InlineArrayAttribute") &&
+ stringComparer.Equals(namespaceHandle, "System.Runtime.CompilerServices"))
+ {
+ flags |= TypeFlags.IsValueArray;
+ }
}
}
}
@@ -525,6 +533,18 @@ public override bool HasCustomAttribute(string attributeNamespace, string attrib
attributeNamespace, attributeName).IsNil;
}
+ public override int GetValueArrayLength()
+ {
+ Debug.Assert(this.IsValueArray);
+
+ var attr = MetadataReader.GetCustomAttribute(MetadataReader.GetCustomAttributeHandle(_typeDefinition.GetCustomAttributes(),
+ "System.Runtime.CompilerServices", "InlineArrayAttribute"));
+
+ var value = attr.DecodeValue(new CustomAttributeTypeProvider(_module)).FixedArguments[0].Value;
+
+ return value is int intValue ? intValue : 0;
+ }
+
public override ClassLayoutMetadata GetClassLayout()
{
TypeLayout layout = _typeDefinition.GetLayout();
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs
index 8f9478897a7464..86d079b1c5e704 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs
@@ -4,7 +4,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
-
+using System.Linq;
+using System.Xml.Linq;
using Internal.TypeSystem;
// The GCRef map is used to encode GC type of arguments for callsites. Logically, it is sequence where pos is
@@ -280,12 +281,30 @@ private void GcScanValueType(TypeDesc type, in ArgDestination argDest, int delta
Debug.Assert(type is DefType);
DefType defType = (DefType)type;
+ bool isValArray = defType.IsValueArray;
foreach (FieldDesc field in defType.GetFields())
{
if (field.IsStatic)
continue;
- GcScanRoots(field.FieldType, in argDest, delta + field.Offset.AsInt, frame, topLevel: false);
+ if (isValArray)
+ {
+ var elementSize = field.FieldType.GetElementSize().AsInt;
+ var totalSize = defType.InstanceFieldSize.AsInt;
+
+ for (int offset = 0; offset < totalSize; offset += elementSize)
+ {
+ GcScanRoots(field.FieldType, in argDest, delta + offset, frame, topLevel: false);
+ }
+
+ // there is only one formal instance field in a value array
+ Debug.Assert(field.Offset.AsInt == 0);
+ break;
+ }
+ else
+ {
+ GcScanRoots(field.FieldType, in argDest, delta + field.Offset.AsInt, frame, topLevel: false);
+ }
}
}
diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp
index 3815ae4f70c31f..d8c325b792393a 100644
--- a/src/coreclr/vm/siginfo.cpp
+++ b/src/coreclr/vm/siginfo.cpp
@@ -4840,32 +4840,47 @@ class ByRefPointerOffsetsReporter
WRAPPER_NO_CONTRACT;
}
+ void Find(FieldDesc* pFD, SIZE_T baseOffset)
+ {
+ if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
+ {
+ PTR_MethodTable pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
+ if (pFieldMT->IsByRefLike())
+ {
+ Find(pFieldMT, baseOffset + pFD->GetOffset());
+ }
+ }
+ else if (pFD->IsByRef())
+ {
+ Report(baseOffset + pFD->GetOffset());
+ }
+ }
+
void Find(PTR_MethodTable pMT, SIZE_T baseOffset)
{
WRAPPER_NO_CONTRACT;
_ASSERTE(pMT != nullptr);
_ASSERTE(pMT->IsByRefLike());
- int repeat = 1; // TODO: VS fetch val arr repeat
- UINT repeatSize = 0; // TODO: VS fetch actual repeat size
-
+ bool isValArray = pMT->GetClass()->HasValueArrayFlagSet();
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc* pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
- if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
+ if(isValArray)
{
- PTR_MethodTable pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
- if (pFieldMT->IsByRefLike())
+ DWORD elementSize = pFD->GetSize();
+ DWORD totalSize = pMT->GetNumInstanceFieldBytes();
+ for (DWORD offset = 0; offset < totalSize; offset += elementSize)
{
- Find(pFieldMT, baseOffset + pFD->GetOffset());
+ Find(pFD, baseOffset + offset);
}
+
+ // there is only one instance field
+ break;
}
- else if (pFD->IsByRef())
+ else
{
- for (int i = 0; i < repeat; i++)
- {
- Report(baseOffset + (repeatSize * i) + pFD->GetOffset());
- }
+ Find(pFD, baseOffset);
}
}
}
From 6eeb887f40f48819b7f5a403554ff8826a010e07 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Mon, 27 Feb 2023 14:31:17 -0800
Subject: [PATCH 05/30] refmap
---
src/coreclr/vm/jitinterface.cpp | 50 ++++++++++++++++++++++++---------
src/coreclr/vm/siginfo.cpp | 4 +--
2 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 30d7145bc8020c..2e2f6fc05c0970 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -2162,31 +2162,53 @@ static unsigned MarkGCField(BYTE* gcPtrs, CorInfoGCType type)
return 0;
}
-/*********************************************************************/
-static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
+static unsigned ComputeGCLayout(MethodTable* pMT, BYTE* gcPtrs);
+
+static unsigned ComputeGCLayout(FieldDesc* pFD, BYTE* gcPtrs)
+{
+ unsigned result = 0;
+ if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
+ {
+ MethodTable* pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
+ result += ComputeGCLayout(pFieldMT, gcPtrs);
+ }
+ else if (pFD->IsObjRef())
+ {
+ result += MarkGCField(gcPtrs, TYPE_GC_REF);
+ }
+ else if (pFD->IsByRef())
+ {
+ result += MarkGCField(gcPtrs, TYPE_GC_BYREF);
+ }
+
+ return result;
+}
+
+static unsigned ComputeGCLayout(MethodTable* pMT, BYTE* gcPtrs)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsValueType());
unsigned result = 0;
+ bool isValueArray = pMT->GetClass()->HasValueArrayFlagSet();
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
- int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
-
- if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
+ if (isValueArray)
{
- MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
- result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
- }
- else if (pFD->IsObjRef())
- {
- result += MarkGCField(gcPtrs + fieldStartIndex, TYPE_GC_REF);
+ _ASSERTE(pFD->GetOffset() == 0);
+ DWORD totalSize = pMT->GetNumInstanceFieldBytes();
+ DWORD elementSize = pFD->GetSize();
+ for (DWORD offset = 0; offset < totalSize; offset += elementSize)
+ {
+ result += ComputeGCLayout(pFD, gcPtrs + (offset / TARGET_POINTER_SIZE));
+ }
}
- else if (pFD->IsByRef())
+ else
{
- result += MarkGCField(gcPtrs + fieldStartIndex, TYPE_GC_BYREF);
+ int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
+ result += ComputeGCLayout(pFD, gcPtrs + fieldStartIndex);
}
}
return result;
@@ -2229,7 +2251,7 @@ unsigned CEEInfo::getClassGClayoutStatic(TypeHandle VMClsHnd, BYTE* gcPtrs)
{
memset(gcPtrs, TYPE_GC_NONE,
(VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
- // ByRefLike structs can be included as fields in other value types.
+ // ByRefLike structs can contain byref fields or other ByRefLike structs
result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
}
else
diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp
index d8c325b792393a..8d3a60c245370c 100644
--- a/src/coreclr/vm/siginfo.cpp
+++ b/src/coreclr/vm/siginfo.cpp
@@ -4868,15 +4868,13 @@ class ByRefPointerOffsetsReporter
{
if(isValArray)
{
+ _ASSERTE(pFD->GetOffset() == 0);
DWORD elementSize = pFD->GetSize();
DWORD totalSize = pMT->GetNumInstanceFieldBytes();
for (DWORD offset = 0; offset < totalSize; offset += elementSize)
{
Find(pFD, baseOffset + offset);
}
-
- // there is only one instance field
- break;
}
else
{
From f0d156b921246367c0dcedae833b60ad2219451b Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Mon, 27 Feb 2023 14:47:27 -0800
Subject: [PATCH 06/30] validate total size in ilc
---
.../Common/MetadataFieldLayoutAlgorithm.cs | 26 ++++++++++++++-----
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
index bafdcf50304e8b..3ce2fc0eb6bedf 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
@@ -755,18 +755,30 @@ protected ComputedInstanceFieldLayout ComputeAutoFieldLayout(MetadataType type,
{
int repeat = type.GetValueArrayLength();
- // UNDONE: VS validate resulting size.
- // UNDONE: VS validate repeat > 0.
-
-
- if (!instanceSizeAndAlignment.Size.IsIndeterminate)
+ if (repeat <= 0)
{
- instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
+ ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}
if (!instanceByteSizeAndAlignment.Size.IsIndeterminate)
{
- instanceByteSizeAndAlignment.Size = new LayoutInt(instanceByteSizeAndAlignment.Size.AsInt * repeat);
+ long size = instanceByteSizeAndAlignment.Size.AsInt;
+ size *= repeat;
+
+ // matching the max size validation in MethodTableBuilder
+ // see: FIELD_OFFSET_LAST_REAL_OFFSET
+ const int maxSize = ((1 << 27) - 1) - 6;
+ if (size > maxSize)
+ {
+ ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadValueClassTooLarge, type);
+ }
+
+ instanceByteSizeAndAlignment.Size = new LayoutInt((int)size);
+ }
+
+ if (!instanceSizeAndAlignment.Size.IsIndeterminate)
+ {
+ instanceSizeAndAlignment.Size = new LayoutInt(instanceSizeAndAlignment.Size.AsInt * repeat);
}
}
From 470aee2c7535cdc8934639d0f9969b62f2c4ab0c Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Mon, 27 Feb 2023 16:05:49 -0800
Subject: [PATCH 07/30] add the actual attribute
---
.../System.Private.CoreLib.Shared.projitems | 1 +
.../CompilerServices/InlineArrayAttribute.cs | 19 +++++++++++++++++++
.../System.Runtime/ref/System.Runtime.cs | 7 +++++++
3 files changed, 27 insertions(+)
create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/InlineArrayAttribute.cs
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 6f2d52f360447d..35dbe01116bbcd 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -808,6 +808,7 @@
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/InlineArrayAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/InlineArrayAttribute.cs
new file mode 100644
index 00000000000000..eb966ca090d5b0
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/InlineArrayAttribute.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.ComponentModel;
+
+namespace System.Runtime.CompilerServices
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
+ public sealed class InlineArrayAttribute : Attribute
+ {
+ public InlineArrayAttribute(int length)
+ {
+ Length = length;
+ }
+
+ public int Length { get; }
+ }
+}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 53f5e047b232a0..6a18583fdb46da 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -12498,6 +12498,13 @@ public sealed partial class InterpolatedStringHandlerAttribute : System.Attribut
{
public InterpolatedStringHandlerAttribute() { }
}
+ [AttributeUsage(System.AttributeTargets.Struct, AllowMultiple = false)]
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
+ public sealed partial class InlineArrayAttribute : System.Attribute
+ {
+ public InlineArrayAttribute(int length) { }
+ public int Length { get { throw null; } }
+ }
[System.AttributeUsageAttribute(System.AttributeTargets.Struct)]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public sealed partial class IsByRefLikeAttribute : System.Attribute
From 78ab52308dfd12c8f81ad6bd886d6383853e98e3 Mon Sep 17 00:00:00 2001
From: Vladimir Sadov
Date: Tue, 28 Feb 2023 08:38:06 -0800
Subject: [PATCH 08/30] Apply suggestions from code review
Co-authored-by: Jan Kotas
---
.../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
index 3ce2fc0eb6bedf..fe679ec28802c6 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
@@ -358,7 +358,7 @@ protected ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataType ty
out instanceByteSizeAndAlignment);
// value array cannot have explicit layout
- if(type.IsValueArray)
+ if (type.IsValueArray)
{
ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}
From a452be746842901fa748ca1daf67552c195b44c2 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Tue, 28 Feb 2023 15:51:31 -0800
Subject: [PATCH 09/30] add a small use of InlineArray in CoreLib - to get some
crossgen coverage.
---
.../src/System/ParamsArray.cs | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs b/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
index 8e9d35f6b0076b..a4b5fd9bcdff2b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
@@ -7,8 +7,48 @@
// Suppress warnings for unused private fields
#pragma warning disable CS0169, CA1823, IDE0051, IDE0044
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
namespace System
{
+#if CORECLR || NATIVEAOT
+
+ [InlineArray(Length)]
+ internal struct TwoObjects
+ {
+ private const int Length = 2;
+ internal object? Arg0;
+
+ [UnscopedRef]
+ private ref object? this[int i] => ref Unsafe.Add(ref Arg0, i);
+
+ public TwoObjects(object? arg0, object? arg1)
+ {
+ this[0] = arg0;
+ this[1] = arg1;
+ }
+ }
+
+ [InlineArray(Length)]
+ internal struct ThreeObjects
+ {
+ private const int Length = 3;
+ internal object? Arg0;
+
+ [UnscopedRef]
+ private ref object? this[int i] => ref Unsafe.Add(ref Arg0, i);
+
+ public ThreeObjects(object? arg0, object? arg1, object? arg2)
+ {
+ this[0] = arg0;
+ this[1] = arg1;
+ this[2] = arg2;
+ }
+ }
+
+#else
+
internal struct TwoObjects
{
internal object? Arg0;
@@ -34,4 +74,5 @@ public ThreeObjects(object? arg0, object? arg1, object? arg2)
_arg2 = arg2;
}
}
+#endif
}
From 2801f508efcb1be0dd99a5ab038cd4a0d21693e6 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Wed, 1 Mar 2023 03:23:17 -0800
Subject: [PATCH 10/30] a few more uses in CorLib
---
.../Reflection/Emit/DynamicMethod.CoreCLR.cs | 4 +-
.../Reflection/RuntimeMethodInfo.CoreCLR.cs | 4 +-
.../src/System/Reflection/MethodBase.cs | 37 ++++++++++++-------
.../Reflection/RuntimeConstructorInfo.cs | 8 ++--
.../System/Reflection/RuntimeMethodInfo.cs | 4 +-
5 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs
index 2e4c5d034933e8..9633a784519a33 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.CoreCLR.cs
@@ -150,8 +150,8 @@ Signature LazyCreateSignature()
{
Debug.Assert(parameters != null);
StackAllocedArguments argStorage = default;
- Span