Skip to content

Commit 447ea44

Browse files
author
Fadi Hanna
committed
CR feedback
1 parent 51966dd commit 447ea44

File tree

5 files changed

+82
-56
lines changed

5 files changed

+82
-56
lines changed

src/coreclr/src/vm/genericdict.cpp

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,11 @@ DictionaryLayout* DictionaryLayout::ExpandDictionaryLayout(LoaderAllocator*
268268
_ASSERTE(pCurrentDictLayout->m_slots[pCurrentDictLayout->m_numSlots - 1].m_signature != NULL);
269269

270270
#ifdef _DEBUG
271-
// Stress debug mode by increasing size by only 1 slot
272-
if (!FitsIn<WORD>((DWORD)pCurrentDictLayout->m_numSlots + 1))
271+
// Stress debug mode by increasing size by only 1 slot for the first 10 slots.
272+
DWORD newSize = pCurrentDictLayout->m_numSlots > 10 ? (DWORD)pCurrentDictLayout->m_numSlots * 2 : pCurrentDictLayout->m_numSlots + 1;
273+
if (!FitsIn<WORD>(newSize))
273274
return NULL;
274-
DictionaryLayout* pNewDictionaryLayout = Allocate(pCurrentDictLayout->m_numSlots + 1, pAllocator, NULL);
275+
DictionaryLayout* pNewDictionaryLayout = Allocate((WORD)newSize, pAllocator, NULL);
275276
#else
276277
if (!FitsIn<WORD>((DWORD)pCurrentDictLayout->m_numSlots * 2))
277278
return NULL;
@@ -776,7 +777,6 @@ DWORD Dictionary::GetDictionarySlotsSizeForType(MethodTable* pMT)
776777
PRECONDITION(pMT->GetGenericsDictInfo()->m_wNumTyPars > 0);
777778
PRECONDITION(pMT->GetClass()->GetDictionaryLayout() != NULL);
778779
PRECONDITION(pMT->GetClass()->GetDictionaryLayout()->GetMaxSlots() > 0);
779-
PRECONDITION(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread());
780780
}
781781
CONTRACTL_END;
782782

@@ -790,7 +790,6 @@ DWORD Dictionary::GetDictionarySlotsSizeForMethod(MethodDesc* pMD)
790790
CONTRACTL
791791
{
792792
PRECONDITION(pMD->AsInstantiatedMethodDesc()->IMD_GetMethodDictionary() != NULL);
793-
PRECONDITION(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread());
794793
}
795794
CONTRACTL_END;
796795

@@ -806,7 +805,6 @@ Dictionary* Dictionary::GetMethodDictionaryWithSizeCheck(MethodDesc* pMD, ULONG
806805
{
807806
THROWS;
808807
GC_TRIGGERS;
809-
PRECONDITION(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread());
810808
POSTCONDITION(CheckPointer(RETVAL));
811809
}
812810
CONTRACT_END;
@@ -820,23 +818,38 @@ Dictionary* Dictionary::GetMethodDictionaryWithSizeCheck(MethodDesc* pMD, ULONG
820818
{
821819
// Only expand the dictionary if the current slot we're trying to use is beyond the size of the dictionary
822820

823-
DictionaryLayout* pDictLayout = pMD->GetDictionaryLayout();
824-
InstantiatedMethodDesc* pIMD = pMD->AsInstantiatedMethodDesc();
825-
_ASSERTE(pDictLayout != NULL && pDictLayout->GetMaxSlots() > 0);
821+
// Take lock and check for size again, just in case another thread already resized the dictionary
822+
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
826823

827-
DWORD expectedDictionarySize = DictionaryLayout::GetDictionarySizeFromLayout(pMD->GetNumGenericMethodArgs(), pDictLayout);
828-
_ASSERT(currentDictionarySize < expectedDictionarySize);
824+
pDictionary = pMD->GetMethodDictionary();
825+
currentDictionarySize = GetDictionarySlotsSizeForMethod(pMD);
829826

830-
pDictionary = (Dictionary*)(void*)pIMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(expectedDictionarySize));
827+
if (currentDictionarySize <= (slotIndex * sizeof(DictionaryEntry)))
828+
{
829+
DictionaryLayout* pDictLayout = pMD->GetDictionaryLayout();
830+
InstantiatedMethodDesc* pIMD = pMD->AsInstantiatedMethodDesc();
831+
_ASSERTE(pDictLayout != NULL && pDictLayout->GetMaxSlots() > 0);
831832

832-
// Copy old dictionary entry contents
833-
memcpy(pDictionary, (const void*)pIMD->m_pPerInstInfo.GetValue(), currentDictionarySize);
833+
DWORD expectedDictionarySize = DictionaryLayout::GetDictionarySizeFromLayout(pMD->GetNumGenericMethodArgs(), pDictLayout);
834+
_ASSERT(currentDictionarySize < expectedDictionarySize);
835+
836+
pDictionary = (Dictionary*)(void*)pIMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(expectedDictionarySize));
837+
838+
// Copy old dictionary entry contents
839+
DictionaryEntry* pOldEntriesPtr = (DictionaryEntry*)pIMD->m_pPerInstInfo.GetValue();
840+
DictionaryEntry* pNewEntriesPtr = (DictionaryEntry*)pDictionary;
841+
for (int i = 0; i < currentDictionarySize / sizeof(DictionaryEntry); i++, pOldEntriesPtr++, pNewEntriesPtr++)
842+
{
843+
DictionaryEntry pSlotValue = VolatileLoadWithoutBarrier(pOldEntriesPtr);
844+
VolatileStoreWithoutBarrier(pNewEntriesPtr, pSlotValue);
845+
}
834846

835-
DWORD* pSizeSlot = (DWORD*)(pDictionary + pIMD->GetNumGenericMethodArgs());
836-
*pSizeSlot = expectedDictionarySize;
847+
DWORD* pSizeSlot = (DWORD*)(pDictionary + pIMD->GetNumGenericMethodArgs());
848+
*pSizeSlot = expectedDictionarySize;
837849

838-
// Publish the new dictionary slots to the type.
839-
FastInterlockExchangePointer((TypeHandle**)pIMD->m_pPerInstInfo.GetValuePtr(), (TypeHandle*)pDictionary);
850+
// Publish the new dictionary slots to the type.
851+
FastInterlockExchangePointer((TypeHandle**)pIMD->m_pPerInstInfo.GetValuePtr(), (TypeHandle*)pDictionary);
852+
}
840853
}
841854
#endif
842855

@@ -849,7 +862,6 @@ Dictionary* Dictionary::GetTypeDictionaryWithSizeCheck(MethodTable* pMT, ULONG s
849862
{
850863
THROWS;
851864
GC_TRIGGERS;
852-
PRECONDITION(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread());
853865
POSTCONDITION(CheckPointer(RETVAL));
854866
}
855867
CONTRACT_END;
@@ -863,25 +875,40 @@ Dictionary* Dictionary::GetTypeDictionaryWithSizeCheck(MethodTable* pMT, ULONG s
863875
{
864876
// Only expand the dictionary if the current slot we're trying to use is beyond the size of the dictionary
865877

866-
DictionaryLayout* pDictLayout = pMT->GetClass()->GetDictionaryLayout();
867-
_ASSERTE(pDictLayout != NULL && pDictLayout->GetMaxSlots() > 0);
878+
// Take lock and check for size again, just in case another thread already resized the dictionary
879+
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
868880

869-
DWORD expectedDictionarySize = DictionaryLayout::GetDictionarySizeFromLayout(pMT->GetNumGenericArgs(), pDictLayout);
870-
_ASSERT(currentDictionarySize < expectedDictionarySize);
881+
pDictionary = pMT->GetDictionary();
882+
currentDictionarySize = GetDictionarySlotsSizeForType(pMT);
871883

872-
// Expand type dictionary
873-
pDictionary = (Dictionary*)(void*)pMT->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(expectedDictionarySize));
884+
if (currentDictionarySize <= (slotIndex * sizeof(DictionaryEntry)))
885+
{
886+
DictionaryLayout* pDictLayout = pMT->GetClass()->GetDictionaryLayout();
887+
_ASSERTE(pDictLayout != NULL && pDictLayout->GetMaxSlots() > 0);
874888

875-
// Copy old dictionary entry contents
876-
memcpy(pDictionary, (const void*)pMT->GetPerInstInfo()[pMT->GetNumDicts() - 1].GetValue(), currentDictionarySize);
889+
DWORD expectedDictionarySize = DictionaryLayout::GetDictionarySizeFromLayout(pMT->GetNumGenericArgs(), pDictLayout);
890+
_ASSERT(currentDictionarySize < expectedDictionarySize);
877891

878-
DWORD* pSizeSlot = (DWORD*)(pDictionary + pMT->GetNumGenericArgs());
879-
*pSizeSlot = expectedDictionarySize;
892+
// Expand type dictionary
893+
pDictionary = (Dictionary*)(void*)pMT->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(expectedDictionarySize));
880894

881-
// Publish the new dictionary slots to the type.
882-
ULONG dictionaryIndex = pMT->GetNumDicts() - 1;
883-
TypeHandle** pPerInstInfo = (TypeHandle**)pMT->GetPerInstInfo()->GetValuePtr();
884-
FastInterlockExchangePointer(pPerInstInfo + dictionaryIndex, (TypeHandle*)pDictionary);
895+
// Copy old dictionary entry contents
896+
DictionaryEntry* pOldEntriesPtr = (DictionaryEntry*)pMT->GetPerInstInfo()[pMT->GetNumDicts() - 1].GetValue();
897+
DictionaryEntry* pNewEntriesPtr = (DictionaryEntry*)pDictionary;
898+
for (int i = 0; i < currentDictionarySize / sizeof(DictionaryEntry); i++, pOldEntriesPtr++, pNewEntriesPtr++)
899+
{
900+
DictionaryEntry pSlotValue = VolatileLoadWithoutBarrier(pOldEntriesPtr);
901+
VolatileStoreWithoutBarrier(pNewEntriesPtr, pSlotValue);
902+
}
903+
904+
DWORD* pSizeSlot = (DWORD*)(pDictionary + pMT->GetNumGenericArgs());
905+
*pSizeSlot = expectedDictionarySize;
906+
907+
// Publish the new dictionary slots to the type.
908+
ULONG dictionaryIndex = pMT->GetNumDicts() - 1;
909+
TypeHandle** pPerInstInfo = (TypeHandle**)pMT->GetPerInstInfo()->GetValuePtr();
910+
FastInterlockExchangePointer(pPerInstInfo + dictionaryIndex, (TypeHandle*)pDictionary);
911+
}
885912
}
886913
#endif
887914

@@ -1493,14 +1520,11 @@ Dictionary::PopulateEntry(
14931520

14941521
if ((slotIndex != 0) && !IsCompilationProcess())
14951522
{
1496-
// Lock is needed because dictionary pointers can get updated during dictionary size expansion
1497-
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
1498-
14991523
Dictionary* pDictionary = (pMT != NULL) ?
15001524
GetTypeDictionaryWithSizeCheck(pMT, slotIndex) :
15011525
GetMethodDictionaryWithSizeCheck(pMD, slotIndex);
15021526

1503-
*(pDictionary->GetSlotAddr(0, slotIndex)) = result;
1527+
VolatileStoreWithoutBarrier(pDictionary->GetSlotAddr(0, slotIndex), (DictionaryEntry)result);
15041528
*ppSlot = pDictionary->GetSlotAddr(0, slotIndex);
15051529
}
15061530
}

src/coreclr/src/vm/generics.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,10 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
278278
DWORD cbPerInst = sizeof(GenericsDictInfo) + pOldMT->GetPerInstInfoSize();
279279

280280
// Finally we need space for the instantiation/dictionary for this type
281-
// Note that this is an unsafe operation because it uses the dictionary layout to compute the size needed,
282-
// and the dictionary layout can be updated by other threads during a dictionary size expansion. This is
283-
// not a problem anyways because whenever we load a value from the dictionary after a certain index, we will
284-
// always check the size of the dictionary and expand it if needed
281+
// Note that it is possible for the dictionary layout to be expanded in size by other threads while we're still
282+
// creating this type. In other words: this type will have a smaller dictionary that its layout. This is not a
283+
// problem however because whenever we need to load a value from the dictionary of this type beyond its size, we
284+
// will expand the dictionary at that point.
285285
DWORD cbInstAndDict = pOldMT->GetInstAndDictSize();
286286

287287
// Allocate from the high frequence heap of the correct domain
@@ -493,10 +493,11 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
493493
}
494494

495495
PTR_DictionaryLayout pLayout = pOldMT->GetClass()->GetDictionaryLayout();
496-
if (pLayout != NULL && pLayout->GetMaxSlots() > 0)
496+
if (pLayout != NULL)
497497
{
498-
ULONG_PTR* pDictionarySlots = (ULONG_PTR*)pMT->GetPerInstInfo()[pOldMT->GetNumDicts() - 1].GetValue();
499-
ULONG_PTR* pSizeSlot = pDictionarySlots + ntypars;
498+
_ASSERTE(pLayout->GetMaxSlots() > 0);
499+
PTR_Dictionary pDictionarySlots = pMT->GetPerInstInfo()[pOldMT->GetNumDicts() - 1].GetValue();
500+
DWORD* pSizeSlot = (DWORD*)(pDictionarySlots + ntypars);
500501
*pSizeSlot = cbInstAndDict;
501502
}
502503

src/coreclr/src/vm/genmeth.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,10 @@ InstantiatedMethodDesc::NewInstantiatedMethodDesc(MethodTable *pExactMT,
373373
{
374374
if (pWrappedMD->IsSharedByGenericMethodInstantiations())
375375
{
376-
// It is ok to not take a lock here while reading the dictionary layout pointer. This is because
377-
// when we load values from a generic dictionary beyond a certain index, we will check the size of
378-
// the dictionary and expand it if needed.
376+
// Note that it is possible for the dictionary layout to be expanded in size by other threads while we're still
377+
// creating this method. In other words: this method will have a smaller dictionary that its layout. This is not a
378+
// problem however because whenever we need to load a value from the dictionary of this method beyond its size, we
379+
// will expand the dictionary at that point.
379380
pDL = pWrappedMD->AsInstantiatedMethodDesc()->GetDictLayoutRaw();
380381
}
381382
}
@@ -402,9 +403,9 @@ InstantiatedMethodDesc::NewInstantiatedMethodDesc(MethodTable *pExactMT,
402403
{
403404
// Has to be at least larger than the first slots containing the instantiation arguments,
404405
// and the slot with size information. Otherwise, we shouldn't really have a size slot
405-
_ASSERTE(infoSize > (sizeof(TypeHandle*) * methodInst.GetNumArgs() + sizeof(ULONG_PTR*)));
406+
_ASSERTE(infoSize > sizeof(TypeHandle*) * (methodInst.GetNumArgs() + 1));
406407

407-
ULONG_PTR* pDictSizeSlot = ((ULONG_PTR*)pInstOrPerInstInfo) + methodInst.GetNumArgs();
408+
DWORD* pDictSizeSlot = (DWORD*)(pInstOrPerInstInfo + methodInst.GetNumArgs());
408409
*pDictSizeSlot = infoSize;
409410
}
410411
}

src/coreclr/src/vm/method.hpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3469,10 +3469,9 @@ class InstantiatedMethodDesc : public MethodDesc
34693469
{
34703470
LIMITED_METHOD_DAC_CONTRACT;
34713471

3472-
// No lock needed here. This is considered a safe operation here because in the case of a generic dictionary
3473-
// expansion, the values of the old dictionary slots are copied to the newly allocated dictionary, and the old
3474-
// dictionary is kept around, so whether IMD_GetMethodDictionary returns the new or old dictionaries, the
3475-
// values of the instantiation arguments will always be the same.
3472+
// No lock needed here. In the case of a generic dictionary expansion, the values of the old dictionary
3473+
// slots are copied to the newly allocated dictionary, and the old dictionary is kept around. Whether we
3474+
// return the old or new dictionary here, the values of the instantiation arguments will always be the same.
34763475
return Instantiation(IMD_GetMethodDictionary()->GetInstantiation(), m_wNumGenericArgs);
34773476
}
34783477

src/coreclr/src/vm/methodtablebuilder.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10462,10 +10462,11 @@ MethodTableBuilder::SetupMethodTable2(
1046210462
pInstDest[j] = inst[j];
1046310463
}
1046410464

10465-
if (pClass->GetDictionaryLayout() != NULL && pClass->GetDictionaryLayout()->GetMaxSlots() > 0)
10465+
PTR_DictionaryLayout pLayout = pClass->GetDictionaryLayout();
10466+
if (pLayout != NULL && pLayout->GetMaxSlots() > 0)
1046610467
{
10467-
ULONG_PTR* pDictionarySlots = (ULONG_PTR*)pMT->GetPerInstInfo()[bmtGenerics->numDicts - 1].GetValue();
10468-
ULONG_PTR* pSizeSlot = pDictionarySlots + bmtGenerics->GetNumGenericArgs();
10468+
PTR_Dictionary pDictionarySlots = pMT->GetPerInstInfo()[bmtGenerics->numDicts - 1].GetValue();
10469+
DWORD* pSizeSlot = (DWORD*)(pDictionarySlots + bmtGenerics->GetNumGenericArgs());
1046910470
*pSizeSlot = cbDict;
1047010471
}
1047110472
}

0 commit comments

Comments
 (0)