@@ -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 }
0 commit comments