From 5e38fd471ca84e598685bba8df500cd014e6320d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 23 Feb 2024 16:03:48 -0800 Subject: [PATCH 01/13] Start implementing the algorithm in the CoreCLR type system. --- src/coreclr/inc/corinfo.h | 9 +++++++- src/coreclr/vm/methodtable.cpp | 39 ++++++++++++++++++++++++++++++++++ src/coreclr/vm/methodtable.h | 4 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 5fad5e4b2429e4..883d8ebf72c616 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -356,6 +356,13 @@ enum StructFloatFieldInfoFlags STRUCT_HAS_8BYTES_FIELDS_MASK = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8), }; +struct CORINFO_SWIFT_LOWERING +{ + bool byReference; + CorInfoType loweredElements[4]; + size_t numLoweredElements; +}; + #include "corinfoinstructionset.h" // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) @@ -2061,7 +2068,7 @@ class ICorStaticInfo // Example of a scenario addressed by notifyMethodInfoUsage: // 1) Crossgen (with --opt-cross-module=MyLib) attempts to inline a call from MyLib.dll into MyApp.dll // and realizes that the call always throws. - // 2) JIT aborts the inlining attempt and marks the call as no-return instead. The code that follows the call is + // 2) JIT aborts the inlining attempt and marks the call as no-return instead. The code that follows the call is // replaced with a breakpoint instruction that is expected to be unreachable. // 3) MyLib is updated to a new version so it's no longer within the same version bubble with MyApp.dll // and the new version of the call no longer throws and does some work. diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 41307b3d1a8f23..297c81a04e43d1 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4026,6 +4026,45 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) } #endif +#if defined(TARGET_APPLE) +void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering) +{ + enum class SwiftIntervalTag : uint8_t + { + Empty, + Opaque, + Int64, + Float, + Double + }; + struct Interval + { + uint32_t m_offset; + uint32_t m_size; + SwiftIntervalTag m_tag; + }; + + // TODO: Reimplement the algorithm from SwiftPhysicalLowering in the managed type system here. + // Abstracting between out from the two field representations is too hard, + // so we'll just duplicate the code for now, especially as we aren't reusing it anywhere else. + + CQuickArray intervals; + // We'll have up to as many intervals as there are fields. + intervals.AllocThrows(GetNumInstanceFields()); + uint32_t numIntervals = 0; + + if (IsBlittable()) + { + // Use FieldDescs to calculate the layout + } + else + { + // Use NativeLayout to calculate the layout + EEClassNativeLayoutInfo* pNativeLayoutInfo = GetNativeLayoutInfo(); + } +} +#endif + #if !defined(DACCESS_COMPILE) //========================================================================================== void MethodTable::AllocateRegularStaticBoxes() diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 4984d010a71bba..de3bc0b852b82f 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -840,6 +840,10 @@ class MethodTable bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, EEClassNativeLayoutInfo const* nativeLayoutInfo); #endif // defined(UNIX_AMD64_ABI_ITF) +#if defined(TARGET_APPLE) + void GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering); +#endif // defined(TARGET_APPLE) + // Copy m_dwFlags from another method table void CopyFlags(MethodTable * pOldMT) { From fc93eb48d9bf0a7f6dcdc8b851ee4b9b69e69c91 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 4 Mar 2024 14:45:13 -0800 Subject: [PATCH 02/13] First pass implementing the CoreCLR side of the Swift physical lowering. --- src/coreclr/vm/methodtable.cpp | 301 +++++++++++++++++++++++++++++++-- src/coreclr/vm/methodtable.h | 2 +- 2 files changed, 285 insertions(+), 18 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 297c81a04e43d1..56ff05f65b76e0 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4027,9 +4027,9 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) #endif #if defined(TARGET_APPLE) -void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering) +namespace { - enum class SwiftIntervalTag : uint8_t + enum class SwiftPhysicalLoweringTag : uint8_t { Empty, Opaque, @@ -4037,31 +4037,298 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL Float, Double }; - struct Interval + + uint32_t GetAlignment(SwiftPhysicalLoweringTag tag) { - uint32_t m_offset; - uint32_t m_size; - SwiftIntervalTag m_tag; - }; + switch (tag) + { + case SwiftPhysicalLoweringTag::Int64: + return 8; + case SwiftPhysicalLoweringTag::Float: + return 4; + case SwiftPhysicalLoweringTag::Double: + return 8; + default: + return 1; + } + } + + void SetLoweringRange(CQuickArray& intervals, uint32_t start, uint32 size, SwiftPhysicalLoweringTag tag) + { + bool forceOpaque = false; + + if (!IS_ALIGNED(start, GetAlignment(tag))) + { + // If the start of the range is not aligned, we need to force the entire range to be opaque. + forceOpaque = true; + } + else + { + // Check if any of the range is non-empty. + // If so, we need to force this range to be opaque + // and extend the range mark the existing tag's range as opaque. + for (uint32_t i = 0; i < size; i++) + { + if (intervals[start + i] != SwiftPhysicalLoweringTag::Empty + && intervals[start + i] != tag + && intervals[start + i] != SwiftPhysicalLoweringTag::Opaque) + { + forceOpaque = true; + + // Extend out start to the beginning of the existing tag's range + // and extend size to the end of the existing tag's range (if non-opaque/empty). + start = (uint32_t)ALIGN_DOWN(start, GetAlignment(intervals[start + i])); + size = (uint32_t)ALIGN_UP(size + start, GetAlignment(intervals[start + i])) - start; + break; + } + } + + if (forceOpaque) + { + tag = SwiftPhysicalLoweringTag::Opaque; + } + + for (uint32_t i = 0; i < size; i++) + { + intervals[start + i] = tag; + } + } + } + + void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset = 0) + { + // Use FieldDescs to calculate the Swift intervals + FieldDesc *pFieldDescList = pMT->GetApproxFieldDescListRaw(); + for (uint32_t i = 0; i < pMT->GetNumIntroducedInstanceFields(); i++) + { + PTR_MethodTable fieldType = pFieldDescList[i].GetFieldTypeHandleThrowing().GetMethodTable(); + CorInfoType corType = fieldType->GetVerifierCorElementType(); + + uint32_t fieldOffset = offset + pFieldDescList[i].GetOffset(); - // TODO: Reimplement the algorithm from SwiftPhysicalLowering in the managed type system here. - // Abstracting between out from the two field representations is too hard, - // so we'll just duplicate the code for now, especially as we aren't reusing it anywhere else. + if (corType == ELEMENT_TYPE_VALUETYPE) + { + GetNativeSwiftPhysicalLowering(intervals, fieldType, fieldOffset); + continue; + } + + if (corType == ELEMENT_TYPE_R4) + { + SetLoweringRange(intervals, fieldOffset, 4, SwiftPhysicalLoweringTag::Float); + } + else if (corType == ELEMENT_TYPE_R8) + { + SetLoweringRange(intervals, fieldOffset, 8, SwiftPhysicalLoweringTag::Double); + } + else if (corType == ELEMENT_TYPE_I8 || corType == ELEMENT_TYPE_U8) + { + SetLoweringRange(intervals, fieldOffset, 8, SwiftPhysicalLoweringTag::Int64); + } + else + { + SetLoweringRange(intervals, fieldOffset, fieldType->GetNumInstanceFieldBytes(), SwiftPhysicalLoweringTag::Opaque); + } + } + } + + void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_EEClassNativeLayoutInfo pNativeLayoutInfo, uint32_t offset = 0) + { + // Use NativeLayout to calculate the Swift intervals + NativeFieldDescriptor* pNativeFieldDescs = pNativeLayoutInfo->GetNativeFieldDescriptors(); + for (uint32_t i = 0; i < pNativeLayoutInfo->GetNumFields(); i++) + { + NativeFieldDescriptor& nfd = pNativeFieldDescs[i]; + if (nfd.GetCategory() == NativeFieldCategory::NESTED) + { + PTR_MethodTable fieldType = nfd.GetNestedNativeMethodTable(); + for (uint32_t i = 0; i < nfd.GetNumElements(); i++) + { + if (fieldType.IsBlittable()) + { + GetNativeSwiftPhysicalLowering(intervals, fieldType, offset + nfd.GetOffset() + fieldType->GetNativeSize() * i); + } + else + { + GetNativeSwiftPhysicalLowering(intervals, fieldType.GetNativeLayoutInfo(), offset + nfd.GetOffset() + fieldType->GetNativeSize() * i); + } + } + } + else if (nfd.GetCategory() == NativeFieldCategory::FLOAT) + { + _ASSERTE(nfd.NativeSize() == 4 || nfd.NativeSize() == 8); + SetLoweringRange(intervals, offset + nfd.GetOffset(), nfd.NativeSize(), nfd.NativeSize() == 4 ? SwiftPhysicalLoweringTag::Float : SwiftPhysicalLoweringTag::Double); + } + else if (nfd.GetCategory() == NativeFieldCategory::INTEGER && nfd.NativeSize() == 8) + { + SetLoweringRange(intervals, offset + nfd.GetOffset(), nfd.NativeSize(), SwiftPhysicalLoweringTag::Int64); + } + else + { + SetLoweringRange(intervals, offset + nfd.GetOffset(), nfd.NativeSize(), SwiftPhysicalLoweringTag::Opaque); + } + } + } +} - CQuickArray intervals; - // We'll have up to as many intervals as there are fields. - intervals.AllocThrows(GetNumInstanceFields()); +void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering, bool useNativeLayout) +{ + // We'll build the intervals by scanning the fields byte-by-byte and then calculate the lowering intervals + // from that information. + CQuickArray loweringBytes; + intervals.AllocThrows(GetNumInstanceFieldBytes()); + memset(loweringBytes.Ptr(), SwiftPhysicalLoweringTag::Empty, loweringBytes.Size()); uint32_t numIntervals = 0; - if (IsBlittable()) + if (useNativeLayout && !IsBlittable()) { - // Use FieldDescs to calculate the layout + // Use NativeLayout to calculate the layout + GetNativeSwiftPhysicalLowering(loweringBytes, GetNativeLayoutInfo()); } else { - // Use NativeLayout to calculate the layout - EEClassNativeLayoutInfo* pNativeLayoutInfo = GetNativeLayoutInfo(); + GetNativeSwiftPhysicalLowering(loweringBytes, this); } + + struct SwiftLoweringInterval + { + uint32_t m_offset; + uint32_t m_size; + SwiftPhysicalLoweringTag m_tag; + }; + + // Build intervals from the byte sequences + CQuickArrayList intervals; + for (uint32_t i = 0; i < loweingBytes.Size(); ++i) + { + if (i == 0 || loweringBytes[i] != loweringBytes[i - 1]) + { + SwiftLoweringInterval interval; + interval.m_offset = i; + interval.m_size = 1; + interval.m_tag = loweringBytes[i]; + intervals.Push(interval); + } + else + { + intervals[intervals.Size() - 1].m_size++; + } + } + + // Now we have the intervals, we can calculate the lowering. + CorElementType elementTypes[4]; + uint32_t numElementTypes = 0; + size_t currentLoweredSize = 0; + + for (uint32_t i = 0; i < numIntervals; i++) + { + SwiftLoweringInterval& interval = intervals[i]; + + if (interval.m_tag == SwiftPhysicalLoweringTag::Empty) + { + continue; + } + + if (numElementTypes == 4) + { + // If we have more than for intervals, this type is passed by-reference in Swift. + pSwiftLowering->byReference = true; + return; + } + + switch (interval.m_tag) + { + case SwiftPhysicalLoweringTag::Int64: + currentLoweredSize = ALIGN_UP(currentLoweredSize, 8) + 8; + elementTypes[numElementTypes++] = CORINFO_TYPE_LONG; + break; + case SwiftPhysicalLoweringTag::Float: + currentLoweredSize = ALIGN_UP(currentLoweredSize, 4) + 4; + elementTypes[numElementTypes++] = CORINFO_TYPE_FLOAT; + break; + case SwiftPhysicalLoweringTag::Double: + currentLoweredSize = ALIGN_UP(currentLoweredSize, 8) + 8; + elementTypes[numElementTypes++] = CORINFO_TYPE_DOUBLE; + break; + case SwiftPhysicalLoweringTag::Opaque: + { + // We need to split the opaque ranges into integer parameters. + // As part of this splitting, we must ensure that we don't introduce alignment padding. + // This lowering algorithm should produce a lowered type sequence that would have the same padding for + // a naturally-aligned struct with the lowered fields as the original type has. + // This algorithm intends to split the opaque range into the least number of lowered elements that covers the entire range. + // The lowered range is allowed to extend past the end of the opaque range (including past the end of the struct), + // but not into the next non-empty interval. + // However, due to the properties of the lowering (the only non-8 byte elements of the lowering are 4-byte floats), + // we'll never encounter a scneario where we need would need to account for a correctly-aligned + // opaque range of > 4 bytes that we must not pad to 8 bytes. + + + // As long as we need to fill more than 4 bytes and the sequence is currently 8-byte aligned, we'll split into 8-byte integers. + // If we have more than 2 bytes but less than 4 and the sequence is 4-byte aligned, we'll use a 4-byte integer to represent the rest of the parameters. + // If we have 2 bytes and the sequence is 2-byte aligned, we'll use a 2-byte integer to represent the rest of the parameters. + // If we have 1 byte, we'll use a 1-byte integer to represent the rest of the parameters. + uint32_t remainingIntervalSize = interval.m_size; + while (remainingIntervalSize > 4 && IS_ALIGNED(currentLoweredSize, 8)) + { + if (numElementTypes == 4) + { + // If we have more than for intervals, this type is passed by-reference in Swift. + pSwiftLowering->byReference = true; + return; + } + + elementTypes[numElementTypes++] = CORINFO_TYPE_LONG; + currentLoweredSize += 8; + remainingIntervalSize -= 8; + } + + if (remainingIntervalSize > 2 && IS_ALIGNED(currentLoweredSize, 4)) + { + if (numElementTypes == 4) + { + // If we have more than for intervals, this type is passed by-reference in Swift. + pSwiftLowering->byReference = true; + return; + } + + elementTypes[numElementTypes++] = CORINFO_TYPE_INT; + currentLoweredSize += 4; + remainingIntervalSize -= 4; + } + + if (remainingIntervalSize > 1 && IS_ALIGNED(currentLoweredSize, 2)) + { + if (numElementTypes == 4) + { + // If we have more than for intervals, this type is passed by-reference in Swift. + pSwiftLowering->byReference = true; + return; + } + + elementTypes[numElementTypes++] = CORINFO_TYPE_SHORT; + currentLoweredSize += 2; + remainingIntervalSize -= 2; + } + + if (remainingIntervalSize == 1) + { + if (numElementTypes == 4) + { + // If we have more than for intervals, this type is passed by-reference in Swift. + pSwiftLowering->byReference = true; + return; + } + + elementTypes[numElementTypes++] = CORINFO_TYPE_BYTE; + currentLoweredSize += 1; + } + } + } + } + + memcpy(pSwiftLowering->loweredTypes, elementTypes, numElementTypes * sizeof(CorElementType)); + pSwiftLowering->numLoweredTypes = numElementTypes; + pSwiftLowering->byReference = false; } #endif diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index de3bc0b852b82f..9b21b70ab76201 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -841,7 +841,7 @@ class MethodTable #endif // defined(UNIX_AMD64_ABI_ITF) #if defined(TARGET_APPLE) - void GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering); + void GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering, bool useNativeLayout); #endif // defined(TARGET_APPLE) // Copy m_dwFlags from another method table From 869e6d06baeaa648b8d0fe9a0a602228f5237427 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 5 Mar 2024 16:34:10 -0800 Subject: [PATCH 03/13] Add InlineArray support and compile on all platforms (needed for altjit) --- src/coreclr/inc/corinfo.h | 16 +-- src/coreclr/vm/methodtable.cpp | 188 +++++++++++++++++++++------------ src/coreclr/vm/methodtable.h | 4 +- 3 files changed, 133 insertions(+), 75 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 883d8ebf72c616..2c0772f2a30f34 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -356,13 +356,6 @@ enum StructFloatFieldInfoFlags STRUCT_HAS_8BYTES_FIELDS_MASK = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8), }; -struct CORINFO_SWIFT_LOWERING -{ - bool byReference; - CorInfoType loweredElements[4]; - size_t numLoweredElements; -}; - #include "corinfoinstructionset.h" // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) @@ -581,7 +574,7 @@ enum CorInfoHelpFunc CORINFO_HELP_MEMSET, // Init block of memory CORINFO_HELP_MEMZERO, // Init block of memory with zeroes CORINFO_HELP_MEMCPY, // Copy block of memory - CORINFO_HELP_NATIVE_MEMSET, // Init block of memory using native memset (not safe for pDst being null, + CORINFO_HELP_NATIVE_MEMSET, // Init block of memory using native memset (not safe for pDst being null, // not safe for unbounded size, does not trigger GC) CORINFO_HELP_RUNTIMEHANDLE_METHOD, // determine a type/field/method handle at run-time @@ -1989,6 +1982,13 @@ enum class GetTypeLayoutResult Failure, }; +struct CORINFO_SWIFT_LOWERING +{ + bool byReference; + CorInfoType loweredElements[4]; + size_t numLoweredElements; +}; + #define SIZEOF__CORINFO_Object TARGET_POINTER_SIZE /* methTable */ #define CORINFO_Array_MaxLength 0x7FFFFFC7 diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 56ff05f65b76e0..8b6fcdb92beb47 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4026,7 +4026,7 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) } #endif -#if defined(TARGET_APPLE) +#if !defined(DACCESS_COMPILE) namespace { enum class SwiftPhysicalLoweringTag : uint8_t @@ -4053,7 +4053,7 @@ namespace } } - void SetLoweringRange(CQuickArray& intervals, uint32_t start, uint32 size, SwiftPhysicalLoweringTag tag) + void SetLoweringRange(CQuickArray& intervals, uint32_t start, uint32_t size, SwiftPhysicalLoweringTag tag) { bool forceOpaque = false; @@ -4095,76 +4095,127 @@ namespace } } - void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset = 0) - { - // Use FieldDescs to calculate the Swift intervals - FieldDesc *pFieldDescList = pMT->GetApproxFieldDescListRaw(); - for (uint32_t i = 0; i < pMT->GetNumIntroducedInstanceFields(); i++) - { - PTR_MethodTable fieldType = pFieldDescList[i].GetFieldTypeHandleThrowing().GetMethodTable(); - CorInfoType corType = fieldType->GetVerifierCorElementType(); - - uint32_t fieldOffset = offset + pFieldDescList[i].GetOffset(); + void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset = 0); + void GetNativeSwiftPhysicalLoweringForInlineArray(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset = 0); - if (corType == ELEMENT_TYPE_VALUETYPE) - { - GetNativeSwiftPhysicalLowering(intervals, fieldType, fieldOffset); - continue; - } + void GetNativeSwiftPhysicalLoweringForField(CQuickArray& intervals, FieldDesc* pFieldDesc, uint32_t offset = 0) + { + PTR_MethodTable fieldType = pFieldDesc->GetFieldTypeHandleThrowing().GetMethodTable(); + CorElementType corType = fieldType->GetVerifierCorElementType(); - if (corType == ELEMENT_TYPE_R4) - { - SetLoweringRange(intervals, fieldOffset, 4, SwiftPhysicalLoweringTag::Float); - } - else if (corType == ELEMENT_TYPE_R8) - { - SetLoweringRange(intervals, fieldOffset, 8, SwiftPhysicalLoweringTag::Double); - } - else if (corType == ELEMENT_TYPE_I8 || corType == ELEMENT_TYPE_U8) + if (corType == ELEMENT_TYPE_VALUETYPE) + { + if (fieldType->GetClass()->IsInlineArray()) { - SetLoweringRange(intervals, fieldOffset, 8, SwiftPhysicalLoweringTag::Int64); + GetNativeSwiftPhysicalLoweringForInlineArray(intervals, fieldType, offset); } else { - SetLoweringRange(intervals, fieldOffset, fieldType->GetNumInstanceFieldBytes(), SwiftPhysicalLoweringTag::Opaque); + GetNativeSwiftPhysicalLowering(intervals, fieldType, offset); } } + else if (corType == ELEMENT_TYPE_R4) + { + SetLoweringRange(intervals, offset, 4, SwiftPhysicalLoweringTag::Float); + } + else if (corType == ELEMENT_TYPE_R8) + { + SetLoweringRange(intervals, offset, 8, SwiftPhysicalLoweringTag::Double); + } + else if (corType == ELEMENT_TYPE_I8 || corType == ELEMENT_TYPE_U8) + { + SetLoweringRange(intervals, offset, 8, SwiftPhysicalLoweringTag::Int64); + } + else + { + SetLoweringRange(intervals, offset, fieldType->GetNumInstanceFieldBytes(), SwiftPhysicalLoweringTag::Opaque); + } + } + + void GetNativeSwiftPhysicalLoweringForInlineArray(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset) + { + _ASSERTE(pMT->GetClass()->IsInlineArray()); + FieldDesc* pElementField = pMT->GetApproxFieldDescListRaw(); + + // If the type is an inline array, we need to calculate the size based on the number of elements. + const void* pVal; // The custom value. + ULONG cbVal; // Size of the custom value. + HRESULT hr = pMT->GetCustomAttribute( + WellKnownAttribute::InlineArrayAttribute, + &pVal, &cbVal); + + _ASSERTE(hr == S_OK); + if (hr != S_OK) + { + return; + } + + // Validity of the InlineArray attribute is checked at type-load time, + // so we only assert here as we should have already checked this and failed + // type load if this condition is false. + _ASSERTE(cbVal >= (sizeof(INT32) + 2)); + if (cbVal <= (sizeof(INT32) + 2)) + { + return; + } + + + INT32 repeat = GET_UNALIGNED_VAL32((byte*)pVal + 2); + + // Use the one FieldDesc to calculate the Swift intervals + // Use FieldDescs to calculate the Swift intervals + PTR_FieldDesc pFieldDesc = pMT->GetApproxFieldDescListRaw(); + for (int32_t i = 0; i < repeat; i++) + { + GetNativeSwiftPhysicalLoweringForField(intervals, pFieldDesc, offset + pFieldDesc->GetOffset() + pFieldDesc->GetSize() * i); + } } - void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_EEClassNativeLayoutInfo pNativeLayoutInfo, uint32_t offset = 0) + void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset) + { + // Use FieldDescs to calculate the Swift intervals + PTR_FieldDesc pFieldDescList = pMT->GetApproxFieldDescListRaw(); + for (uint32_t i = 0; i < pMT->GetNumIntroducedInstanceFields(); i++) + { + PTR_FieldDesc pFieldDesc = pFieldDescList + i; + GetNativeSwiftPhysicalLoweringForField(intervals, pFieldDesc, offset + pFieldDesc->GetOffset()); + } + } + + void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, EEClassNativeLayoutInfo const* pNativeLayoutInfo, uint32_t offset = 0) { // Use NativeLayout to calculate the Swift intervals - NativeFieldDescriptor* pNativeFieldDescs = pNativeLayoutInfo->GetNativeFieldDescriptors(); + NativeFieldDescriptor const* pNativeFieldDescs = pNativeLayoutInfo->GetNativeFieldDescriptors(); for (uint32_t i = 0; i < pNativeLayoutInfo->GetNumFields(); i++) { - NativeFieldDescriptor& nfd = pNativeFieldDescs[i]; + NativeFieldDescriptor const& nfd = pNativeFieldDescs[i]; if (nfd.GetCategory() == NativeFieldCategory::NESTED) { PTR_MethodTable fieldType = nfd.GetNestedNativeMethodTable(); for (uint32_t i = 0; i < nfd.GetNumElements(); i++) { - if (fieldType.IsBlittable()) + if (fieldType->IsBlittable()) { - GetNativeSwiftPhysicalLowering(intervals, fieldType, offset + nfd.GetOffset() + fieldType->GetNativeSize() * i); + GetNativeSwiftPhysicalLowering(intervals, fieldType, offset + nfd.GetExternalOffset() + fieldType->GetNativeSize() * i); } else { - GetNativeSwiftPhysicalLowering(intervals, fieldType.GetNativeLayoutInfo(), offset + nfd.GetOffset() + fieldType->GetNativeSize() * i); + GetNativeSwiftPhysicalLowering(intervals, fieldType->GetNativeLayoutInfo(), offset + nfd.GetExternalOffset() + fieldType->GetNativeSize() * i); } } } else if (nfd.GetCategory() == NativeFieldCategory::FLOAT) { _ASSERTE(nfd.NativeSize() == 4 || nfd.NativeSize() == 8); - SetLoweringRange(intervals, offset + nfd.GetOffset(), nfd.NativeSize(), nfd.NativeSize() == 4 ? SwiftPhysicalLoweringTag::Float : SwiftPhysicalLoweringTag::Double); + SetLoweringRange(intervals, offset + nfd.GetExternalOffset(), nfd.NativeSize(), nfd.NativeSize() == 4 ? SwiftPhysicalLoweringTag::Float : SwiftPhysicalLoweringTag::Double); } else if (nfd.GetCategory() == NativeFieldCategory::INTEGER && nfd.NativeSize() == 8) { - SetLoweringRange(intervals, offset + nfd.GetOffset(), nfd.NativeSize(), SwiftPhysicalLoweringTag::Int64); + SetLoweringRange(intervals, offset + nfd.GetExternalOffset(), nfd.NativeSize(), SwiftPhysicalLoweringTag::Int64); } else { - SetLoweringRange(intervals, offset + nfd.GetOffset(), nfd.NativeSize(), SwiftPhysicalLoweringTag::Opaque); + SetLoweringRange(intervals, offset + nfd.GetExternalOffset(), nfd.NativeSize(), SwiftPhysicalLoweringTag::Opaque); } } } @@ -4174,19 +4225,24 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL { // We'll build the intervals by scanning the fields byte-by-byte and then calculate the lowering intervals // from that information. - CQuickArray loweringBytes; - intervals.AllocThrows(GetNumInstanceFieldBytes()); - memset(loweringBytes.Ptr(), SwiftPhysicalLoweringTag::Empty, loweringBytes.Size()); + CQuickArray loweredBytes; + loweredBytes.AllocThrows(GetNumInstanceFieldBytes()); + memset(loweredBytes.Ptr(), (uint8_t)SwiftPhysicalLoweringTag::Empty, loweredBytes.Size()); uint32_t numIntervals = 0; if (useNativeLayout && !IsBlittable()) { // Use NativeLayout to calculate the layout - GetNativeSwiftPhysicalLowering(loweringBytes, GetNativeLayoutInfo()); + ::GetNativeSwiftPhysicalLowering(loweredBytes, GetNativeLayoutInfo()); + } + else if (GetClass()->IsInlineArray()) + { + // Use InlineArray to calculate the layout + ::GetNativeSwiftPhysicalLoweringForInlineArray(loweredBytes, PTR_MethodTable(this)); } else { - GetNativeSwiftPhysicalLowering(loweringBytes, this); + ::GetNativeSwiftPhysicalLowering(loweredBytes, PTR_MethodTable(this)); } struct SwiftLoweringInterval @@ -4198,14 +4254,14 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL // Build intervals from the byte sequences CQuickArrayList intervals; - for (uint32_t i = 0; i < loweingBytes.Size(); ++i) + for (uint32_t i = 0; i < loweredBytes.Size(); ++i) { - if (i == 0 || loweringBytes[i] != loweringBytes[i - 1]) + if (i == 0 || loweredBytes[i] != loweredBytes[i - 1]) { SwiftLoweringInterval interval; interval.m_offset = i; interval.m_size = 1; - interval.m_tag = loweringBytes[i]; + interval.m_tag = loweredBytes[i]; intervals.Push(interval); } else @@ -4215,8 +4271,8 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL } // Now we have the intervals, we can calculate the lowering. - CorElementType elementTypes[4]; - uint32_t numElementTypes = 0; + CorInfoType loweredTypes[4]; + uint32_t numLoweredTypes = 0; size_t currentLoweredSize = 0; for (uint32_t i = 0; i < numIntervals; i++) @@ -4228,7 +4284,7 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL continue; } - if (numElementTypes == 4) + if (numLoweredTypes == 4) { // If we have more than for intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; @@ -4239,15 +4295,15 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL { case SwiftPhysicalLoweringTag::Int64: currentLoweredSize = ALIGN_UP(currentLoweredSize, 8) + 8; - elementTypes[numElementTypes++] = CORINFO_TYPE_LONG; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_LONG; break; case SwiftPhysicalLoweringTag::Float: currentLoweredSize = ALIGN_UP(currentLoweredSize, 4) + 4; - elementTypes[numElementTypes++] = CORINFO_TYPE_FLOAT; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_FLOAT; break; case SwiftPhysicalLoweringTag::Double: currentLoweredSize = ALIGN_UP(currentLoweredSize, 8) + 8; - elementTypes[numElementTypes++] = CORINFO_TYPE_DOUBLE; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_DOUBLE; break; case SwiftPhysicalLoweringTag::Opaque: { @@ -4270,67 +4326,69 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL uint32_t remainingIntervalSize = interval.m_size; while (remainingIntervalSize > 4 && IS_ALIGNED(currentLoweredSize, 8)) { - if (numElementTypes == 4) + if (numLoweredTypes == 4) { // If we have more than for intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; return; } - elementTypes[numElementTypes++] = CORINFO_TYPE_LONG; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_LONG; currentLoweredSize += 8; remainingIntervalSize -= 8; } - if (remainingIntervalSize > 2 && IS_ALIGNED(currentLoweredSize, 4)) + while (remainingIntervalSize > 2 && IS_ALIGNED(currentLoweredSize, 4)) { - if (numElementTypes == 4) + if (numLoweredTypes == 4) { // If we have more than for intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; return; } - elementTypes[numElementTypes++] = CORINFO_TYPE_INT; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_INT; currentLoweredSize += 4; remainingIntervalSize -= 4; } - if (remainingIntervalSize > 1 && IS_ALIGNED(currentLoweredSize, 2)) + while (remainingIntervalSize > 1 && IS_ALIGNED(currentLoweredSize, 2)) { - if (numElementTypes == 4) + if (numLoweredTypes == 4) { // If we have more than for intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; return; } - elementTypes[numElementTypes++] = CORINFO_TYPE_SHORT; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_SHORT; currentLoweredSize += 2; remainingIntervalSize -= 2; } - if (remainingIntervalSize == 1) + while (remainingIntervalSize > 1) { - if (numElementTypes == 4) + if (numLoweredTypes == 4) { // If we have more than for intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; return; } - elementTypes[numElementTypes++] = CORINFO_TYPE_BYTE; + loweredTypes[numLoweredTypes++] = CORINFO_TYPE_BYTE; currentLoweredSize += 1; + remainingIntervalSize -= 1; } } } } - memcpy(pSwiftLowering->loweredTypes, elementTypes, numElementTypes * sizeof(CorElementType)); - pSwiftLowering->numLoweredTypes = numElementTypes; + memcpy(pSwiftLowering->loweredElements, loweredTypes, numLoweredTypes * sizeof(CorElementType)); + pSwiftLowering->numLoweredElements = numLoweredTypes; pSwiftLowering->byReference = false; } -#endif + +#endif // !DACCESS_COMPILE #if !defined(DACCESS_COMPILE) //========================================================================================== diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 9b21b70ab76201..83057c623fba98 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -840,9 +840,9 @@ class MethodTable bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, EEClassNativeLayoutInfo const* nativeLayoutInfo); #endif // defined(UNIX_AMD64_ABI_ITF) -#if defined(TARGET_APPLE) +#if !defined(DACCESS_COMPILE) void GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering, bool useNativeLayout); -#endif // defined(TARGET_APPLE) +#endif // Copy m_dwFlags from another method table void CopyFlags(MethodTable * pOldMT) From fc47d41c5ff604fa96990ba60c81341079561936 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 7 Mar 2024 14:09:27 -0800 Subject: [PATCH 04/13] Fix interval merging algorithm to correctly split sequential intervals of non-opaque types and to merge opaque intervals --- src/coreclr/inc/corinfo.h | 1 + src/coreclr/vm/methodtable.cpp | 129 +++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 54 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 2c0772f2a30f34..b6dc3d6e4d23f3 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1986,6 +1986,7 @@ struct CORINFO_SWIFT_LOWERING { bool byReference; CorInfoType loweredElements[4]; + uint32_t offsets[4]; size_t numLoweredElements; }; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 8b6fcdb92beb47..f35d6049ca14ac 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4256,7 +4256,23 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL CQuickArrayList intervals; for (uint32_t i = 0; i < loweredBytes.Size(); ++i) { - if (i == 0 || loweredBytes[i] != loweredBytes[i - 1]) + // Don't create an interval for empty bytes + if (loweredBytes[i] == SwiftPhysicalLoweringTag::Empty) + { + continue; + } + + bool startNewInterval = + // We're at the start of the type + i == 0 + // We're starting a new float (as we're aligned) + || (IS_ALIGNED(i, 4) && loweredBytes[i] == SwiftPhysicalLoweringTag::Float) + // We're starting a new double or int64_t (as we're aligned) + || (IS_ALIGNED(i, 8) && (loweredBytes[i] == SwiftPhysicalLoweringTag::Double || loweredBytes[i] == SwiftPhysicalLoweringTag::Int64)) + // We've changed interval types + || loweredBytes[i] != loweredBytes[i - 1]; + + if (startNewInterval) { SwiftLoweringInterval interval; interval.m_offset = i; @@ -4270,19 +4286,42 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL } } - // Now we have the intervals, we can calculate the lowering. - CorInfoType loweredTypes[4]; - uint32_t numLoweredTypes = 0; - size_t currentLoweredSize = 0; + // Merge opaque intervals that are in the same pointer-sized block. + CQuickArrayList mergedIntervals; - for (uint32_t i = 0; i < numIntervals; i++) + for (uint32_t i = 0; i < intervals.Size(); ++i) { SwiftLoweringInterval& interval = intervals[i]; - if (interval.m_tag == SwiftPhysicalLoweringTag::Empty) + if (interval.m_tag == SwiftPhysicalLoweringTag::Opaque) { - continue; + // If we're at the start of the intervals, or the previous interval is not opaque, we need to start a new interval. + if (i == 0 || intervals[i - 1].m_tag != SwiftPhysicalLoweringTag::Opaque) + { + mergedIntervals.Push(interval); + } + // Otherwise, if the previous interval ends in the same pointer-sized block, we'll merge this interval into the previous one. + else if ((intervals[i - 1].m_offset + intervals[i - 1].m_size) / TARGET_POINTER_SIZE == interval.m_offset / TARGET_POINTER_SIZE) + { + SwiftLoweringInterval& lastInterval = mergedIntervals[mergedIntervals.Size() - 1]; + lastInterval.m_size = interval.m_offset + interval.m_size - lastInterval.m_offset; + } + } + else + { + // Non-opaque intervals are never merged at this point. + mergedIntervals.Push(interval); } + } + + // Now we have the intervals, we can calculate the lowering. + CorInfoType loweredTypes[4]; + uint32_t offsets[4]; + uint32_t numLoweredTypes = 0; + + for (uint32_t i = 0; i < numIntervals; i++, numLoweredTypes++) + { + SwiftLoweringInterval& interval = intervals[i]; if (numLoweredTypes == 4) { @@ -4291,19 +4330,18 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL return; } + offsets[numLoweredTypes] = interval.m_offset; + switch (interval.m_tag) { case SwiftPhysicalLoweringTag::Int64: - currentLoweredSize = ALIGN_UP(currentLoweredSize, 8) + 8; - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_LONG; + loweredTypes[numLoweredTypes] = CORINFO_TYPE_LONG; break; case SwiftPhysicalLoweringTag::Float: - currentLoweredSize = ALIGN_UP(currentLoweredSize, 4) + 4; - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_FLOAT; + loweredTypes[numLoweredTypes] = CORINFO_TYPE_FLOAT; break; case SwiftPhysicalLoweringTag::Double: - currentLoweredSize = ALIGN_UP(currentLoweredSize, 8) + 8; - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_DOUBLE; + loweredTypes[numLoweredTypes] = CORINFO_TYPE_DOUBLE; break; case SwiftPhysicalLoweringTag::Opaque: { @@ -4323,67 +4361,50 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL // If we have more than 2 bytes but less than 4 and the sequence is 4-byte aligned, we'll use a 4-byte integer to represent the rest of the parameters. // If we have 2 bytes and the sequence is 2-byte aligned, we'll use a 2-byte integer to represent the rest of the parameters. // If we have 1 byte, we'll use a 1-byte integer to represent the rest of the parameters. + uint32_t opaqueIntervalStart = interval.m_offset; uint32_t remainingIntervalSize = interval.m_size; - while (remainingIntervalSize > 4 && IS_ALIGNED(currentLoweredSize, 8)) + for (;remainingIntervalSize > 0; numLoweredTypes++) { if (numLoweredTypes == 4) { - // If we have more than for intervals, this type is passed by-reference in Swift. + // If we have more than four intervals and we still need to add another interval, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; return; } - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_LONG; - currentLoweredSize += 8; - remainingIntervalSize -= 8; - } + offsets[numLoweredTypes] = opaqueIntervalStart; - while (remainingIntervalSize > 2 && IS_ALIGNED(currentLoweredSize, 4)) - { - if (numLoweredTypes == 4) + if (remainingIntervalSize > 4 && IS_ALIGNED(opaqueIntervalStart, 8)) { - // If we have more than for intervals, this type is passed by-reference in Swift. - pSwiftLowering->byReference = true; - return; + loweredTypes[numLoweredTypes] = CORINFO_TYPE_LONG; + opaqueIntervalStart += 8; + remainingIntervalSize -= 8; } - - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_INT; - currentLoweredSize += 4; - remainingIntervalSize -= 4; - } - - while (remainingIntervalSize > 1 && IS_ALIGNED(currentLoweredSize, 2)) - { - if (numLoweredTypes == 4) + else if (remainingIntervalSize > 2 && IS_ALIGNED(opaqueIntervalStart, 4)) { - // If we have more than for intervals, this type is passed by-reference in Swift. - pSwiftLowering->byReference = true; - return; + loweredTypes[numLoweredTypes] = CORINFO_TYPE_INT; + opaqueIntervalStart += 4; + remainingIntervalSize -= 4; } - - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_SHORT; - currentLoweredSize += 2; - remainingIntervalSize -= 2; - } - - while (remainingIntervalSize > 1) - { - if (numLoweredTypes == 4) + else if (remainingIntervalSize > 1 && IS_ALIGNED(opaqueIntervalStart, 2)) { - // If we have more than for intervals, this type is passed by-reference in Swift. - pSwiftLowering->byReference = true; - return; + loweredTypes[numLoweredTypes] = CORINFO_TYPE_SHORT; + opaqueIntervalStart += 2; + remainingIntervalSize -= 2; + } + else if (remainingIntervalSize > 1) + { + loweredTypes[numLoweredTypes] = CORINFO_TYPE_BYTE; + opaqueIntervalStart += 1; + remainingIntervalSize -= 1; } - - loweredTypes[numLoweredTypes++] = CORINFO_TYPE_BYTE; - currentLoweredSize += 1; - remainingIntervalSize -= 1; } } } } memcpy(pSwiftLowering->loweredElements, loweredTypes, numLoweredTypes * sizeof(CorElementType)); + memcpy(pSwiftLowering->offsets, offsets, numLoweredTypes * sizeof(CorElementType)); pSwiftLowering->numLoweredElements = numLoweredTypes; pSwiftLowering->byReference = false; } From 171a75f1ae17a29a401812c518f195c861cb754b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 7 Mar 2024 14:10:22 -0800 Subject: [PATCH 05/13] Fix the final lowering step to loop over the interval array --- src/coreclr/vm/methodtable.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index f35d6049ca14ac..74036fd918314e 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4228,7 +4228,6 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL CQuickArray loweredBytes; loweredBytes.AllocThrows(GetNumInstanceFieldBytes()); memset(loweredBytes.Ptr(), (uint8_t)SwiftPhysicalLoweringTag::Empty, loweredBytes.Size()); - uint32_t numIntervals = 0; if (useNativeLayout && !IsBlittable()) { @@ -4319,9 +4318,9 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL uint32_t offsets[4]; uint32_t numLoweredTypes = 0; - for (uint32_t i = 0; i < numIntervals; i++, numLoweredTypes++) + for (uint32_t i = 0; i < mergedIntervals.Size(); i++, numLoweredTypes++) { - SwiftLoweringInterval& interval = intervals[i]; + SwiftLoweringInterval& interval = mergedIntervals[i]; if (numLoweredTypes == 4) { From 123750b436a777ca7b936cd95bbd03abd3884a4d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 7 Mar 2024 16:39:39 -0800 Subject: [PATCH 06/13] Additional fixes to the Swift algorithm. --- src/coreclr/vm/methodtable.cpp | 47 ++++++++++++++++------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 74036fd918314e..6178ab3fba8cc6 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4062,36 +4062,33 @@ namespace // If the start of the range is not aligned, we need to force the entire range to be opaque. forceOpaque = true; } - else + + // Check if any of the range is non-empty. + // If so, we need to force this range to be opaque + // and extend the range mark the existing tag's range as opaque. + for (uint32_t i = 0; i < size; i++) { - // Check if any of the range is non-empty. - // If so, we need to force this range to be opaque - // and extend the range mark the existing tag's range as opaque. - for (uint32_t i = 0; i < size; i++) + if (intervals[start + i] != SwiftPhysicalLoweringTag::Empty + && intervals[start + i] != tag) { - if (intervals[start + i] != SwiftPhysicalLoweringTag::Empty - && intervals[start + i] != tag - && intervals[start + i] != SwiftPhysicalLoweringTag::Opaque) - { - forceOpaque = true; + forceOpaque = true; - // Extend out start to the beginning of the existing tag's range - // and extend size to the end of the existing tag's range (if non-opaque/empty). - start = (uint32_t)ALIGN_DOWN(start, GetAlignment(intervals[start + i])); - size = (uint32_t)ALIGN_UP(size + start, GetAlignment(intervals[start + i])) - start; - break; - } + // Extend out start to the beginning of the existing tag's range + // and extend size to the end of the existing tag's range (if non-opaque/empty). + start = (uint32_t)ALIGN_DOWN(start, GetAlignment(intervals[start + i])); + size = (uint32_t)ALIGN_UP(size + start, GetAlignment(intervals[start + i])) - start; + break; } + } - if (forceOpaque) - { - tag = SwiftPhysicalLoweringTag::Opaque; - } + if (forceOpaque) + { + tag = SwiftPhysicalLoweringTag::Opaque; + } - for (uint32_t i = 0; i < size; i++) - { - intervals[start + i] = tag; - } + for (uint32_t i = 0; i < size; i++) + { + intervals[start + i] = tag; } } @@ -4403,7 +4400,7 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL } memcpy(pSwiftLowering->loweredElements, loweredTypes, numLoweredTypes * sizeof(CorElementType)); - memcpy(pSwiftLowering->offsets, offsets, numLoweredTypes * sizeof(CorElementType)); + memcpy(pSwiftLowering->offsets, offsets, numLoweredTypes * sizeof(uint32_t)); pSwiftLowering->numLoweredElements = numLoweredTypes; pSwiftLowering->byReference = false; } From 478d7bee4f33a08b55db3b3aa96b6fc69ce3c281 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 7 Mar 2024 19:03:04 -0800 Subject: [PATCH 07/13] Add missing case --- src/coreclr/vm/methodtable.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 6178ab3fba8cc6..0f3543feba4ea2 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4330,6 +4330,10 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL switch (interval.m_tag) { + case SwiftPhysicalLoweringTag::Empty: + _ASSERTE(!"Empty intervals should have been dropped during interval construction"); + break; + case SwiftPhysicalLoweringTag::Int64: loweredTypes[numLoweredTypes] = CORINFO_TYPE_LONG; break; From 5a2126c1cfdd126c0efe80b229e0c694b954d245 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Mar 2024 10:04:51 -0800 Subject: [PATCH 08/13] Move increment in the NativeAOT implementation --- src/coreclr/tools/Common/JitInterface/SwiftPhysicalLowering.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/SwiftPhysicalLowering.cs b/src/coreclr/tools/Common/JitInterface/SwiftPhysicalLowering.cs index 1a47536f67f9a5..f5d8afc33d3105 100644 --- a/src/coreclr/tools/Common/JitInterface/SwiftPhysicalLowering.cs +++ b/src/coreclr/tools/Common/JitInterface/SwiftPhysicalLowering.cs @@ -199,9 +199,9 @@ private List CreateConsolidatedIntervals() } else { + loweredTypes.Add((CorInfoType.CORINFO_TYPE_BYTE, opaqueIntervalStart)); opaqueIntervalStart++; remainingIntervalSize--; - loweredTypes.Add((CorInfoType.CORINFO_TYPE_BYTE, opaqueIntervalStart)); } } } From 9e53a9e9fc7d3b0103e7036214bff5f66a435ed0 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Mar 2024 13:47:33 -0800 Subject: [PATCH 09/13] Add contracts and PR feedback --- src/coreclr/vm/methodtable.cpp | 56 +++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 0f3543feba4ea2..33e363cebd7495 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4040,6 +4040,8 @@ namespace uint32_t GetAlignment(SwiftPhysicalLoweringTag tag) { + LIMITED_METHOD_CONTRACT; + switch (tag) { case SwiftPhysicalLoweringTag::Int64: @@ -4055,6 +4057,8 @@ namespace void SetLoweringRange(CQuickArray& intervals, uint32_t start, uint32_t size, SwiftPhysicalLoweringTag tag) { + STANDARD_VM_CONTRACT; + bool forceOpaque = false; if (!IS_ALIGNED(start, GetAlignment(tag))) @@ -4068,15 +4072,16 @@ namespace // and extend the range mark the existing tag's range as opaque. for (uint32_t i = 0; i < size; i++) { - if (intervals[start + i] != SwiftPhysicalLoweringTag::Empty - && intervals[start + i] != tag) + SwiftPhysicalLoweringTag currentTag = intervals[start + i]; + if (currentTag != SwiftPhysicalLoweringTag::Empty + && currentTag != tag) { forceOpaque = true; // Extend out start to the beginning of the existing tag's range // and extend size to the end of the existing tag's range (if non-opaque/empty). - start = (uint32_t)ALIGN_DOWN(start, GetAlignment(intervals[start + i])); - size = (uint32_t)ALIGN_UP(size + start, GetAlignment(intervals[start + i])) - start; + start = (uint32_t)ALIGN_DOWN(start, GetAlignment(currentTag)); + size = (uint32_t)ALIGN_UP(size + start, GetAlignment(currentTag)) - start; break; } } @@ -4086,10 +4091,7 @@ namespace tag = SwiftPhysicalLoweringTag::Opaque; } - for (uint32_t i = 0; i < size; i++) - { - intervals[start + i] = tag; - } + memset(&intervals[start], (uint8_t)tag, size); } void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset = 0); @@ -4097,6 +4099,8 @@ namespace void GetNativeSwiftPhysicalLoweringForField(CQuickArray& intervals, FieldDesc* pFieldDesc, uint32_t offset = 0) { + STANDARD_VM_CONTRACT; + PTR_MethodTable fieldType = pFieldDesc->GetFieldTypeHandleThrowing().GetMethodTable(); CorElementType corType = fieldType->GetVerifierCorElementType(); @@ -4131,6 +4135,7 @@ namespace void GetNativeSwiftPhysicalLoweringForInlineArray(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset) { + STANDARD_VM_CONTRACT; _ASSERTE(pMT->GetClass()->IsInlineArray()); FieldDesc* pElementField = pMT->GetApproxFieldDescListRaw(); @@ -4156,7 +4161,6 @@ namespace return; } - INT32 repeat = GET_UNALIGNED_VAL32((byte*)pVal + 2); // Use the one FieldDesc to calculate the Swift intervals @@ -4170,6 +4174,7 @@ namespace void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset) { + STANDARD_VM_CONTRACT; // Use FieldDescs to calculate the Swift intervals PTR_FieldDesc pFieldDescList = pMT->GetApproxFieldDescListRaw(); for (uint32_t i = 0; i < pMT->GetNumIntroducedInstanceFields(); i++) @@ -4181,6 +4186,7 @@ namespace void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, EEClassNativeLayoutInfo const* pNativeLayoutInfo, uint32_t offset = 0) { + STANDARD_VM_CONTRACT; // Use NativeLayout to calculate the Swift intervals NativeFieldDescriptor const* pNativeFieldDescs = pNativeLayoutInfo->GetNativeFieldDescriptors(); for (uint32_t i = 0; i < pNativeLayoutInfo->GetNumFields(); i++) @@ -4220,6 +4226,8 @@ namespace void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftLowering, bool useNativeLayout) { + STANDARD_VM_CONTRACT; + // We'll build the intervals by scanning the fields byte-by-byte and then calculate the lowering intervals // from that information. CQuickArray loweredBytes; @@ -4243,9 +4251,9 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL struct SwiftLoweringInterval { - uint32_t m_offset; - uint32_t m_size; - SwiftPhysicalLoweringTag m_tag; + uint32_t offset; + uint32_t size; + SwiftPhysicalLoweringTag tag; }; // Build intervals from the byte sequences @@ -4271,14 +4279,14 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL if (startNewInterval) { SwiftLoweringInterval interval; - interval.m_offset = i; - interval.m_size = 1; - interval.m_tag = loweredBytes[i]; + interval.offset = i; + interval.size = 1; + interval.tag = loweredBytes[i]; intervals.Push(interval); } else { - intervals[intervals.Size() - 1].m_size++; + intervals[intervals.Size() - 1].size++; } } @@ -4289,18 +4297,18 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL { SwiftLoweringInterval& interval = intervals[i]; - if (interval.m_tag == SwiftPhysicalLoweringTag::Opaque) + if (interval.tag == SwiftPhysicalLoweringTag::Opaque) { // If we're at the start of the intervals, or the previous interval is not opaque, we need to start a new interval. - if (i == 0 || intervals[i - 1].m_tag != SwiftPhysicalLoweringTag::Opaque) + if (i == 0 || intervals[i - 1].tag != SwiftPhysicalLoweringTag::Opaque) { mergedIntervals.Push(interval); } // Otherwise, if the previous interval ends in the same pointer-sized block, we'll merge this interval into the previous one. - else if ((intervals[i - 1].m_offset + intervals[i - 1].m_size) / TARGET_POINTER_SIZE == interval.m_offset / TARGET_POINTER_SIZE) + else if ((intervals[i - 1].offset + intervals[i - 1].size) / TARGET_POINTER_SIZE == interval.offset / TARGET_POINTER_SIZE) { SwiftLoweringInterval& lastInterval = mergedIntervals[mergedIntervals.Size() - 1]; - lastInterval.m_size = interval.m_offset + interval.m_size - lastInterval.m_offset; + lastInterval.size = interval.offset + interval.size - lastInterval.offset; } } else @@ -4326,9 +4334,9 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL return; } - offsets[numLoweredTypes] = interval.m_offset; + offsets[numLoweredTypes] = interval.offset; - switch (interval.m_tag) + switch (interval.tag) { case SwiftPhysicalLoweringTag::Empty: _ASSERTE(!"Empty intervals should have been dropped during interval construction"); @@ -4361,8 +4369,8 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL // If we have more than 2 bytes but less than 4 and the sequence is 4-byte aligned, we'll use a 4-byte integer to represent the rest of the parameters. // If we have 2 bytes and the sequence is 2-byte aligned, we'll use a 2-byte integer to represent the rest of the parameters. // If we have 1 byte, we'll use a 1-byte integer to represent the rest of the parameters. - uint32_t opaqueIntervalStart = interval.m_offset; - uint32_t remainingIntervalSize = interval.m_size; + uint32_t opaqueIntervalStart = interval.offset; + uint32_t remainingIntervalSize = interval.size; for (;remainingIntervalSize > 0; numLoweredTypes++) { if (numLoweredTypes == 4) From 581a50abe1df8881e527acf8132e73915109d9cd Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Mar 2024 17:08:42 -0800 Subject: [PATCH 10/13] Remove refs and fix spelling --- src/coreclr/vm/methodtable.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 33e363cebd7495..3f48a28549fa15 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4295,7 +4295,7 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL for (uint32_t i = 0; i < intervals.Size(); ++i) { - SwiftLoweringInterval& interval = intervals[i]; + SwiftLoweringInterval interval = intervals[i]; if (interval.tag == SwiftPhysicalLoweringTag::Opaque) { @@ -4325,11 +4325,11 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL for (uint32_t i = 0; i < mergedIntervals.Size(); i++, numLoweredTypes++) { - SwiftLoweringInterval& interval = mergedIntervals[i]; + SwiftLoweringInterval interval = mergedIntervals[i]; if (numLoweredTypes == 4) { - // If we have more than for intervals, this type is passed by-reference in Swift. + // If we have more than four intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; return; } From 3254d5186146c86468d43972b44f2c566602cd37 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Mar 2024 10:36:55 -0700 Subject: [PATCH 11/13] PR feedback --- src/coreclr/vm/methodtable.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 3f48a28549fa15..e88760896e6bca 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4029,7 +4029,7 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) #if !defined(DACCESS_COMPILE) namespace { - enum class SwiftPhysicalLoweringTag : uint8_t + enum class SwiftPhysicalLoweringTag { Empty, Opaque, @@ -4091,7 +4091,7 @@ namespace tag = SwiftPhysicalLoweringTag::Opaque; } - memset(&intervals[start], (uint8_t)tag, size); + memset(&intervals[start], (uint8_t)tag, sizeof(SwiftPhysicalLoweringTag) * size); } void GetNativeSwiftPhysicalLowering(CQuickArray& intervals, PTR_MethodTable pMT, uint32_t offset = 0); @@ -4149,7 +4149,7 @@ namespace _ASSERTE(hr == S_OK); if (hr != S_OK) { - return; + ThrowHR(hr); } // Validity of the InlineArray attribute is checked at type-load time, @@ -4232,7 +4232,7 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL // from that information. CQuickArray loweredBytes; loweredBytes.AllocThrows(GetNumInstanceFieldBytes()); - memset(loweredBytes.Ptr(), (uint8_t)SwiftPhysicalLoweringTag::Empty, loweredBytes.Size()); + memset(loweredBytes.Ptr(), (uint8_t)SwiftPhysicalLoweringTag::Empty, sizeof(SwiftPhysicalLoweringTag) * loweredBytes.Size()); if (useNativeLayout && !IsBlittable()) { From e586ebe522c66aca4334a407bfd67fef482ae3a0 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Mar 2024 11:15:56 -0700 Subject: [PATCH 12/13] Add back underlying type and add comment with rationale --- src/coreclr/vm/methodtable.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index e88760896e6bca..d4634faf49ea40 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4029,7 +4029,9 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) #if !defined(DACCESS_COMPILE) namespace { - enum class SwiftPhysicalLoweringTag + // Underlying type specified so we can use memset in the algorithm below + // to set a range of values to a particular tag. + enum class SwiftPhysicalLoweringTag : uint8_t { Empty, Opaque, From e6fd1af3b6735b63b8a27b43bd573277acf69241 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Mar 2024 15:12:55 -0700 Subject: [PATCH 13/13] Refactor out some constants --- src/coreclr/inc/corinfo.h | 6 ++++-- src/coreclr/vm/methodtable.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index b6dc3d6e4d23f3..4598496ac66845 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1982,11 +1982,13 @@ enum class GetTypeLayoutResult Failure, }; +#define MAX_SWIFT_LOWERED_ELEMENTS 4 + struct CORINFO_SWIFT_LOWERING { bool byReference; - CorInfoType loweredElements[4]; - uint32_t offsets[4]; + CorInfoType loweredElements[MAX_SWIFT_LOWERED_ELEMENTS]; + uint32_t offsets[MAX_SWIFT_LOWERED_ELEMENTS]; size_t numLoweredElements; }; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index d4634faf49ea40..b59a2d23d7d034 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4321,15 +4321,15 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL } // Now we have the intervals, we can calculate the lowering. - CorInfoType loweredTypes[4]; - uint32_t offsets[4]; + CorInfoType loweredTypes[MAX_SWIFT_LOWERED_ELEMENTS]; + uint32_t offsets[MAX_SWIFT_LOWERED_ELEMENTS]; uint32_t numLoweredTypes = 0; for (uint32_t i = 0; i < mergedIntervals.Size(); i++, numLoweredTypes++) { SwiftLoweringInterval interval = mergedIntervals[i]; - if (numLoweredTypes == 4) + if (numLoweredTypes == ARRAY_SIZE(loweredTypes)) { // If we have more than four intervals, this type is passed by-reference in Swift. pSwiftLowering->byReference = true; @@ -4375,7 +4375,7 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL uint32_t remainingIntervalSize = interval.size; for (;remainingIntervalSize > 0; numLoweredTypes++) { - if (numLoweredTypes == 4) + if (numLoweredTypes == ARRAY_SIZE(loweredTypes)) { // If we have more than four intervals and we still need to add another interval, this type is passed by-reference in Swift. pSwiftLowering->byReference = true;