Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 2bad545

Browse files
author
Lubomir Litchev
committed
Fix a bug in classification of structs with field holes.
There is a bug in classifying the register passing structs where field layout leaves holes in the struct layout.
1 parent f9fd9cf commit 2bad545

File tree

2 files changed

+29
-123
lines changed

2 files changed

+29
-123
lines changed

src/vm/methodtable.cpp

Lines changed: 25 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,121 +2509,7 @@ bool MethodTable::ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helpe
25092509
_ASSERTE(helperPtr->currentUniqueOffsetField < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT);
25102510
} // end per-field for loop
25112511

2512-
if (!helperPtr->inEmbeddedStruct)
2513-
{
2514-
_ASSERTE(nestingLevel == 0);
2515-
2516-
// We're at the top level of the recursion, and we're done looking at the fields.
2517-
// Now sort the fields by offset and set the output data.
2518-
2519-
int sortedFieldOrder[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
2520-
for (unsigned i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
2521-
{
2522-
sortedFieldOrder[i] = -1;
2523-
}
2524-
2525-
for (unsigned i = 0; i < helperPtr->currentUniqueOffsetField; i++)
2526-
{
2527-
_ASSERTE(helperPtr->fieldOffsets[i] < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT);
2528-
_ASSERTE(sortedFieldOrder[helperPtr->fieldOffsets[i]] == -1); // we haven't seen this field offset yet.
2529-
sortedFieldOrder[helperPtr->fieldOffsets[i]] = i;
2530-
}
2531-
2532-
// Set the layoutSizes (includes holes from alignment of the fields.)
2533-
int lastField = -1;
2534-
for (unsigned i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
2535-
{
2536-
int ordinal = sortedFieldOrder[i];
2537-
if (ordinal == -1)
2538-
{
2539-
continue;
2540-
}
2541-
2542-
if (lastField == -1)
2543-
{
2544-
lastField = ordinal;
2545-
continue;
2546-
}
2547-
2548-
helperPtr->fieldLayoutSizes[lastField] = helperPtr->fieldOffsets[ordinal] - helperPtr->fieldOffsets[lastField];
2549-
2550-
lastField = ordinal;
2551-
}
2552-
// Now the last field
2553-
_ASSERTE(lastField != -1); // if lastField==-1, then the struct has no fields!
2554-
helperPtr->fieldLayoutSizes[lastField] = helperPtr->structSize - helperPtr->fieldOffsets[lastField];
2555-
2556-
// Calculate the eightbytes and their types.
2557-
unsigned int accumulatedSizeForEightByte = 0;
2558-
unsigned int lastEightByteOffset = 0;
2559-
unsigned int currentEightByte = 0;
2560-
2561-
for (unsigned i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
2562-
{
2563-
int ordinal = sortedFieldOrder[i];
2564-
if (ordinal == -1)
2565-
{
2566-
continue;
2567-
}
2568-
2569-
if ((accumulatedSizeForEightByte + helperPtr->fieldLayoutSizes[ordinal]) > SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES)
2570-
{
2571-
// Save data for this eightbyte.
2572-
helperPtr->eightByteSizes[currentEightByte] = accumulatedSizeForEightByte;
2573-
helperPtr->eightByteOffsets[currentEightByte] = lastEightByteOffset;
2574-
2575-
// Set up for next eightbyte.
2576-
currentEightByte++;
2577-
_ASSERTE(currentEightByte < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2578-
2579-
lastEightByteOffset = helperPtr->fieldOffsets[ordinal];
2580-
accumulatedSizeForEightByte = 0;
2581-
}
2582-
2583-
accumulatedSizeForEightByte += helperPtr->fieldLayoutSizes[ordinal];
2584-
2585-
_ASSERTE(helperPtr->fieldClassifications[ordinal] != SystemVClassificationTypeMemory);
2586-
2587-
if (helperPtr->eightByteClassifications[currentEightByte] == helperPtr->fieldClassifications[ordinal])
2588-
{
2589-
// Do nothing. The eight-byte is already classified.
2590-
}
2591-
else if (helperPtr->eightByteClassifications[currentEightByte] == SystemVClassificationTypeNoClass)
2592-
{
2593-
helperPtr->eightByteClassifications[currentEightByte] = helperPtr->fieldClassifications[ordinal];
2594-
}
2595-
else if ((helperPtr->eightByteClassifications[currentEightByte] == SystemVClassificationTypeInteger) ||
2596-
(helperPtr->fieldClassifications[ordinal] == SystemVClassificationTypeInteger))
2597-
{
2598-
_ASSERTE(helperPtr->fieldClassifications[ordinal] != SystemVClassificationTypeIntegerReference);
2599-
helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeInteger;
2600-
}
2601-
else if ((helperPtr->eightByteClassifications[currentEightByte] == SystemVClassificationTypeIntegerReference) ||
2602-
(helperPtr->fieldClassifications[ordinal] == SystemVClassificationTypeIntegerReference))
2603-
{
2604-
helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeIntegerReference;
2605-
}
2606-
else
2607-
{
2608-
helperPtr->eightByteClassifications[currentEightByte] = SystemVClassificationTypeSSE;
2609-
}
2610-
}
2611-
2612-
helperPtr->eightByteCount = currentEightByte + 1;
2613-
helperPtr->eightByteSizes[currentEightByte] = accumulatedSizeForEightByte;
2614-
helperPtr->eightByteOffsets[currentEightByte] = lastEightByteOffset;
2615-
_ASSERTE(helperPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2616-
2617-
#ifdef _DEBUG
2618-
LOG((LF_JIT, LL_EVERYTHING, " ----\n"));
2619-
LOG((LF_JIT, LL_EVERYTHING, " **** Number EightBytes: %d\n", helperPtr->eightByteCount));
2620-
for (unsigned i = 0; i < helperPtr->eightByteCount; i++)
2621-
{
2622-
LOG((LF_JIT, LL_EVERYTHING, " **** eightByte %d -- classType: %s, eightByteOffset: %d, eightByteSize: %d\n",
2623-
i, GetSystemVClassificationTypeName(helperPtr->eightByteClassifications[i]), helperPtr->eightByteOffsets[i], helperPtr->eightByteSizes[i]));
2624-
}
2625-
#endif // _DEBUG
2626-
}
2512+
AssignClassifiedEightByteTypes(helperPtr, nestingLevel);
26272513

26282514
return true;
26292515
}
@@ -3066,6 +2952,15 @@ bool MethodTable::ClassifyEightBytesForNativeStruct(SystemVStructRegisterPassing
30662952

30672953
} // end per-field for loop
30682954

2955+
AssignClassifiedEightByteTypes(helperPtr, nestingLevel);
2956+
2957+
return true;
2958+
#endif // DACCESS_COMPILE
2959+
}
2960+
2961+
// Assigns the classification types to the array with eightbyte types.
2962+
void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel)
2963+
{
30692964
if (!helperPtr->inEmbeddedStruct)
30702965
{
30712966
_ASSERTE(nestingLevel == 0);
@@ -3108,7 +3003,14 @@ bool MethodTable::ClassifyEightBytesForNativeStruct(SystemVStructRegisterPassing
31083003
}
31093004
// Now the last field
31103005
_ASSERTE(lastField != -1); // if lastField==-1, then the struct has no fields!
3111-
helperPtr->fieldLayoutSizes[lastField] = helperPtr->structSize - helperPtr->fieldOffsets[lastField];
3006+
3007+
// A field size cannot be bigger than the size of an eightbyte.
3008+
// There are cases where for the native layout of a struct the VM allocates 16
3009+
// bytes space, but the struct has one eight-byte field.
3010+
// This field is of classification type INTEGER or INTEGERREFERENCE.
3011+
// Make sure the field layout size does not extend beyound an eightbyte.
3012+
_ASSERTE(helperPtr->fieldSizes[lastField] <= SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES);
3013+
helperPtr->fieldLayoutSizes[lastField] = min(helperPtr->structSize - helperPtr->fieldOffsets[lastField], SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES);
31123014

31133015
// Calculate the eightbytes and their types.
31143016
unsigned int accumulatedSizeForEightByte = 0;
@@ -3123,6 +3025,8 @@ bool MethodTable::ClassifyEightBytesForNativeStruct(SystemVStructRegisterPassing
31233025
continue;
31243026
}
31253027

3028+
_ASSERTE(helperPtr->fieldLayoutSizes[ordinal] <= SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES);
3029+
31263030
if ((accumulatedSizeForEightByte + helperPtr->fieldLayoutSizes[ordinal]) > SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES)
31273031
{
31283032
// Save data for this eightbyte.
@@ -3134,10 +3038,12 @@ bool MethodTable::ClassifyEightBytesForNativeStruct(SystemVStructRegisterPassing
31343038
_ASSERTE(currentEightByte < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
31353039

31363040
lastEightByteOffset = helperPtr->fieldOffsets[ordinal];
3137-
accumulatedSizeForEightByte = 0;
3041+
accumulatedSizeForEightByte = (accumulatedSizeForEightByte + helperPtr->fieldLayoutSizes[ordinal]) - SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES;
3042+
}
3043+
else
3044+
{
3045+
accumulatedSizeForEightByte += helperPtr->fieldLayoutSizes[ordinal];
31383046
}
3139-
3140-
accumulatedSizeForEightByte += helperPtr->fieldLayoutSizes[ordinal];
31413047

31423048
_ASSERTE(helperPtr->fieldClassifications[ordinal] != SystemVClassificationTypeMemory);
31433049

@@ -3181,9 +3087,6 @@ bool MethodTable::ClassifyEightBytesForNativeStruct(SystemVStructRegisterPassing
31813087
}
31823088
#endif // _DEBUG
31833089
}
3184-
3185-
return true;
3186-
#endif // DACCESS_COMPILE
31873090
}
31883091

31893092
#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)

src/vm/methodtable.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,6 @@ class MethodTable
10541054
// Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
10551055
bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct);
10561056
bool ClassifyEightBytesForNativeStruct(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct);
1057-
10581057
#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
10591058

10601059
// Copy m_dwFlags from another method table
@@ -1092,6 +1091,10 @@ class MethodTable
10921091

10931092
private:
10941093

1094+
#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
1095+
void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel);
1096+
#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
1097+
10951098
DWORD GetClassIndexFromToken(mdTypeDef typeToken)
10961099
{
10971100
LIMITED_METHOD_CONTRACT;

0 commit comments

Comments
 (0)