@@ -556,7 +556,6 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
556556    m_FixupCrst.Init (CrstModuleFixup, (CrstFlags)(CRST_HOST_BREAKABLE|CRST_REENTRANCY));
557557    m_InstMethodHashTableCrst.Init (CrstInstMethodHashTable, CRST_REENTRANCY);
558558    m_ISymUnmanagedReaderCrst.Init (CrstISymUnmanagedReader, CRST_DEBUGGER_THREAD);
559-     m_DictionaryCrst.Init (CrstDomainLocalBlock);
560559
561560    if  (!m_file->HasNativeImage ())
562561    {
@@ -688,12 +687,8 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
688687    }
689688#endif  //  defined (PROFILING_SUPPORTED) &&!defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
690689
691- #ifndef  CROSSGEN_COMPILE
692-     m_dynamicSlotsHashForTypes.Init (GetLoaderAllocator ());
693-     m_dynamicSlotsHashForMethods.Init (GetLoaderAllocator ());
694- #endif 
695- 
696690    LOG ((LF_CLASSLOADER, LL_INFO10, " Loaded pModule: \" %ws\" .\n " GetDebugName ()));
691+ 
697692}
698693
699694#endif  //  DACCESS_COMPILE
@@ -13238,327 +13233,6 @@ void ReflectionModule::ReleaseILData()
1323813233
1323913234    Module::ReleaseILData ();
1324013235}
13241- 
13242- TypeHandle* AllocateNewMethodDictionaryForExpansion (InstantiatedMethodDesc* pIMD, DWORD cbSize)
13243- {
13244-     TypeHandle* pInstOrPerInstInfo = (TypeHandle*)(void *)pIMD->GetLoaderAllocator ()->GetHighFrequencyHeap ()->AllocMem (S_SIZE_T (cbSize + sizeof (void *)));
13245-     ZeroMemory (pInstOrPerInstInfo, cbSize + sizeof (void *));
13246- 
13247-     //  Slot[-1] points at previous dictionary to help with diagnostics when investigating crashes
13248-     *(byte**)pInstOrPerInstInfo = (byte*)pIMD->m_pPerInstInfo .GetValue () + 1 ;
13249-     pInstOrPerInstInfo++;
13250- 
13251-     //  Copy old dictionary entry contents
13252-     memcpy (pInstOrPerInstInfo, (const  void *)pIMD->m_pPerInstInfo .GetValue (), pIMD->GetDictionarySlotsSize ());
13253- 
13254-     ULONG_PTR* pSizeSlot = ((ULONG_PTR*)pInstOrPerInstInfo) + pIMD->GetNumGenericMethodArgs ();
13255-     *pSizeSlot = cbSize;
13256- 
13257-     return  pInstOrPerInstInfo;
13258- }
13259- 
13260- TypeHandle* AllocateNewTypeDictionaryForExpansion (MethodTable* pMT, DWORD cbSize)
13261- {
13262-     TypeHandle* pInstOrPerInstInfo = (TypeHandle*)(void *)pMT->GetLoaderAllocator ()->GetHighFrequencyHeap ()->AllocMem (S_SIZE_T (cbSize + sizeof (void *)));
13263-     ZeroMemory (pInstOrPerInstInfo, cbSize + sizeof (void *));
13264- 
13265-     //  Slot[-1] points at previous dictionary to help with diagnostics when investigating crashes
13266-     *(byte**)pInstOrPerInstInfo = (byte*)pMT->GetPerInstInfo ()[pMT->GetNumDicts () - 1 ].GetValue () + 1 ;
13267-     pInstOrPerInstInfo++;
13268- 
13269-     //  Copy old dictionary entry contents
13270-     memcpy (pInstOrPerInstInfo, (const  void *)pMT->GetPerInstInfo ()[pMT->GetNumDicts () - 1 ].GetValue (), pMT->GetDictionarySlotsSize ());
13271- 
13272-     ULONG_PTR* pSizeSlot = ((ULONG_PTR*)pInstOrPerInstInfo) + pMT->GetNumGenericArgs ();
13273-     *pSizeSlot = cbSize;
13274- 
13275-     return  pInstOrPerInstInfo;
13276- }
13277- 
13278- #ifdef  _DEBUG
13279- void  Module::EnsureTypeRecorded (MethodTable* pMT)
13280- {
13281-     _ASSERTE (SystemDomain::SystemModule ()->m_DictionaryCrst .OwnedByCurrentThread ());
13282- 
13283-     BOOL typeExistsInHashtable = FALSE ;
13284-     auto  lamda = [&typeExistsInHashtable, pMT](OBJECTREF obj, MethodTable* pMTKey, MethodTable* pMTValue)
13285-     {
13286-         typeExistsInHashtable = (pMT == pMTValue);
13287-         return  pMT != pMTValue;
13288-     };
13289- 
13290-     m_dynamicSlotsHashForTypes.VisitValuesOfKey (pMT->GetCanonicalMethodTable (), lamda);
13291-     _ASSERTE (typeExistsInHashtable);
13292- }
13293- 
13294- void  Module::EnsureMethodRecorded (MethodDesc* pMD)
13295- {
13296-     _ASSERTE (SystemDomain::SystemModule ()->m_DictionaryCrst .OwnedByCurrentThread ());
13297- 
13298-     BOOL methodExistsInHashtable = FALSE ;
13299-     auto  lamda = [&methodExistsInHashtable, pMD](OBJECTREF obj, MethodDesc* pMDKey, MethodDesc* pMDValue)
13300-     {
13301-         methodExistsInHashtable = (pMD== pMDValue);
13302-         return  pMD != pMDValue;
13303-     };
13304- 
13305-     m_dynamicSlotsHashForMethods.VisitValuesOfKey (pMD->GetExistingWrappedMethodDesc (), lamda);
13306-     _ASSERTE (methodExistsInHashtable);
13307- }
13308- #endif 
13309- 
13310- void  Module::RecordTypeForDictionaryExpansion_Locked (MethodTable* pGenericParentMT, MethodTable* pDependencyMT)
13311- {
13312-     CONTRACTL
13313-     {
13314-         GC_TRIGGERS;
13315-         PRECONDITION (CheckPointer (pGenericParentMT) && CheckPointer (pDependencyMT));
13316-         PRECONDITION (pGenericParentMT->HasInstantiation () && pGenericParentMT != pGenericParentMT->GetCanonicalMethodTable ());
13317-         PRECONDITION (SystemDomain::SystemModule ()->m_DictionaryCrst .OwnedByCurrentThread ());
13318-     }
13319-     CONTRACTL_END
13320- 
13321-     DictionaryLayout* pDictLayout = pDependencyMT->GetClass ()->GetDictionaryLayout ();
13322-     if  (pDictLayout != NULL  && pDictLayout->GetMaxSlots () > 0 )
13323-     {
13324-         DWORD sizeFromDictLayout = DictionaryLayout::GetDictionarySizeFromLayout (pDependencyMT->GetNumGenericArgs (), pDictLayout);
13325-         if  (pDependencyMT->GetDictionarySlotsSize () != sizeFromDictLayout)
13326-         {
13327-             _ASSERT (pDependencyMT->GetDictionarySlotsSize () < sizeFromDictLayout);
13328- 
13329-             // 
13330-             //  Another thread got a chance to expand the dictionary layout and expand the dictionary slots of
13331-             //  other types, but not for this one yet because we're still in the process of recording it for 
13332-             //  expansions.
13333-             //  Expand the dictionary slots here before finally adding the type to the hashtable.
13334-             // 
13335- 
13336-             TypeHandle* pInstOrPerInstInfo = AllocateNewTypeDictionaryForExpansion (pDependencyMT, sizeFromDictLayout);
13337- 
13338-             //  Publish the new dictionary slots to the type.
13339-             TypeHandle** pPerInstInfo = (TypeHandle**)pDependencyMT->GetPerInstInfo ()->GetValuePtr ();
13340-             FastInterlockExchangePointer (pPerInstInfo + (pDependencyMT->GetNumDicts () - 1 ), pInstOrPerInstInfo);
13341- 
13342-             FlushProcessWriteBuffers ();
13343-         }
13344-     }
13345- 
13346-     GCX_COOP ();
13347-     m_dynamicSlotsHashForTypes.Add (pGenericParentMT->GetCanonicalMethodTable (), pDependencyMT, GetLoaderAllocator ());
13348- }
13349- 
13350- void  Module::RecordMethodForDictionaryExpansion_Locked (MethodDesc* pDependencyMD)
13351- {
13352-     CONTRACTL
13353-     {
13354-         GC_TRIGGERS;
13355-         PRECONDITION (CheckPointer (pDependencyMD) && pDependencyMD->HasMethodInstantiation () && pDependencyMD->IsInstantiatingStub ());
13356-         PRECONDITION (pDependencyMD->GetDictionaryLayout () != NULL  && pDependencyMD->GetDictionaryLayout ()->GetMaxSlots () > 0 );
13357-         PRECONDITION (SystemDomain::SystemModule ()->m_DictionaryCrst .OwnedByCurrentThread ());
13358-     }
13359-     CONTRACTL_END
13360- 
13361-     DictionaryLayout* pDictLayout = pDependencyMD->GetDictionaryLayout ();
13362-     InstantiatedMethodDesc* pIMDDependency = pDependencyMD->AsInstantiatedMethodDesc ();
13363- 
13364-     DWORD sizeFromDictLayout = DictionaryLayout::GetDictionarySizeFromLayout (pDependencyMD->GetNumGenericMethodArgs (), pDictLayout);
13365-     if  (pIMDDependency->GetDictionarySlotsSize () != sizeFromDictLayout)
13366-     {
13367-         _ASSERT (pIMDDependency->GetDictionarySlotsSize () < sizeFromDictLayout);
13368- 
13369-         // 
13370-         //  Another thread got a chance to expand the dictionary layout and expand the dictionary slots of
13371-         //  other methods, but not for this one yet because we're still in the process of recording it for 
13372-         //  expansions.
13373-         //  Expand the dictionary slots here before finally adding the method to the hashtable.
13374-         // 
13375- 
13376-         TypeHandle* pInstOrPerInstInfo = AllocateNewMethodDictionaryForExpansion (pIMDDependency, sizeFromDictLayout);
13377- 
13378-         FastInterlockExchangePointer ((TypeHandle**)pIMDDependency->m_pPerInstInfo .GetValuePtr (), pInstOrPerInstInfo);
13379- 
13380-         FlushProcessWriteBuffers ();
13381-     }
13382- 
13383-     GCX_COOP ();
13384- 
13385-     _ASSERTE (pDependencyMD->GetExistingWrappedMethodDesc () != NULL );
13386-     m_dynamicSlotsHashForMethods.Add (pDependencyMD->GetExistingWrappedMethodDesc (), pDependencyMD, GetLoaderAllocator ());
13387- }
13388- 
13389- void  Module::ExpandTypeDictionaries_Locked (MethodTable* pMT, DictionaryLayout* pOldLayout, DictionaryLayout* pNewLayout)
13390- {
13391-     CONTRACTL
13392-     {
13393-         STANDARD_VM_CHECK;
13394-         INJECT_FAULT (ThrowOutOfMemory (););
13395-         PRECONDITION (CheckPointer (pOldLayout) && CheckPointer (pNewLayout));
13396-         PRECONDITION (CheckPointer (pMT) && pMT->HasInstantiation () && pMT->GetClass ()->GetDictionaryLayout () == pOldLayout);
13397-         PRECONDITION (SystemDomain::SystemModule ()->m_DictionaryCrst .OwnedByCurrentThread ());
13398-     }
13399-     CONTRACTL_END
13400- 
13401-     GCX_COOP ();
13402- 
13403-     MethodTable* pCanonMT = pMT->GetCanonicalMethodTable ();
13404-     DWORD oldInfoSize = DictionaryLayout::GetDictionarySizeFromLayout (pMT->GetNumGenericArgs (), pOldLayout);
13405-     DWORD newInfoSize = DictionaryLayout::GetDictionarySizeFromLayout (pMT->GetNumGenericArgs (), pNewLayout);
13406- 
13407-     // 
13408-     //  Dictionary expansion for types needs to be done in multiple steps, given how derived types do not directly embed dictionaries
13409-     //  from parent types, but instead reference them from directly from the parent types. Also, this is necessary to ensure correctness
13410-     //  for lock-free read operations for dictionary slots:
13411-     //       1) Allocate new dictionaries for all instantiated types of the same typedef as the one being expanded.
13412-     //       2) After all allocations and initializations are completed, publish the dictionaries to the types in #1 after 
13413-     //          flushing write buffers
13414-     //       3) For all types that derive from #1, update the embedded dictinoary pointer to the newly allocated one.
13415-     // 
13416- 
13417-     struct  NewDictionary 
13418-     {
13419-         MethodTable* pMT;
13420-         TypeHandle* pDictSlots;
13421-     };
13422-     StackSArray<NewDictionary> dictionaryUpdates;
13423- 
13424- #ifdef  _DEBUG
13425-     auto  expandPerInstInfos = [oldInfoSize, newInfoSize, &dictionaryUpdates](OBJECTREF obj, MethodTable* pMTKey, MethodTable* pMTToUpdate)
13426- #else 
13427-     auto  expandPerInstInfos = [newInfoSize, &dictionaryUpdates](OBJECTREF obj, MethodTable* pMTKey, MethodTable* pMTToUpdate)
13428- #endif 
13429-     {
13430-         if  (!pMTToUpdate->HasSameTypeDefAs (pMTKey))
13431-             return  true ;
13432- 
13433-         _ASSERTE (pMTToUpdate != pMTToUpdate->GetCanonicalMethodTable () && pMTToUpdate->GetCanonicalMethodTable () == pMTKey);
13434-         _ASSERTE (pMTToUpdate->GetDictionarySlotsSize () == oldInfoSize);
13435- 
13436-         TypeHandle* pInstOrPerInstInfo = AllocateNewTypeDictionaryForExpansion (pMTToUpdate, newInfoSize);
13437- 
13438-         NewDictionary entry;
13439-         entry.pMT  = pMTToUpdate;
13440-         entry.pDictSlots  = pInstOrPerInstInfo;
13441-         dictionaryUpdates.Append (entry);
13442- 
13443-         return  true ; //  Keep walking
13444-     };
13445- 
13446-     m_dynamicSlotsHashForTypes.VisitValuesOfKey (pCanonMT, expandPerInstInfos);
13447- 
13448-     //  Flush write buffers to ensure new dictionaries are fully writted and initalized before publishing them
13449-     FlushProcessWriteBuffers ();
13450- 
13451-     for  (SArray<NewDictionary>::Iterator i = dictionaryUpdates.Begin (); i != dictionaryUpdates.End (); i++)
13452-     {
13453-         MethodTable* pMT = i->pMT ;
13454-         TypeHandle** pPerInstInfo = (TypeHandle**)pMT->GetPerInstInfo ()->GetValuePtr ();
13455-         FastInterlockExchangePointer (pPerInstInfo + (pMT->GetNumDicts () - 1 ), i->pDictSlots );
13456-         _ASSERTE (pMT->GetDictionarySlotsSize () == newInfoSize);
13457-         _ASSERTE ((TypeHandle*)pMT->GetPerInstInfo ()[pMT->GetNumDicts () - 1 ].GetValue () == i->pDictSlots );
13458-     }
13459- 
13460-     auto  updateDependentDicts = [](OBJECTREF obj, MethodTable* pMTKey, MethodTable* pMTToUpdate)
13461-     {
13462-         if  (pMTToUpdate->HasSameTypeDefAs (pMTKey))
13463-             return  true ;
13464- 
13465-         MethodTable* pCurrentMT = pMTToUpdate->GetParentMethodTable ();
13466-         while  (pCurrentMT)
13467-         {
13468-             if  (pCurrentMT->HasSameTypeDefAs (pMTKey))
13469-             {
13470-                 DWORD dictToUpdate = pCurrentMT->GetNumDicts () - 1 ;
13471-                 Dictionary* pUpdatedParentDict = pCurrentMT->GetPerInstInfo ()[dictToUpdate].GetValue ();
13472-                 TypeHandle** pPerInstInfo = (TypeHandle**)pMTToUpdate->GetPerInstInfo ()->GetValuePtr ();
13473-                 FastInterlockExchangePointer (pPerInstInfo + dictToUpdate, (TypeHandle*)pUpdatedParentDict);
13474-                 _ASSERTE (pMTToUpdate->GetPerInstInfo ()[dictToUpdate].GetValue () == pUpdatedParentDict);
13475- 
13476-                 return  true ; //  Keep walking
13477-             }
13478-             pCurrentMT = pCurrentMT->GetParentMethodTable ();
13479-         }
13480- 
13481-         UNREACHABLE ();
13482-     };
13483- 
13484-     m_dynamicSlotsHashForTypes.VisitValuesOfKey (pCanonMT, updateDependentDicts);
13485- 
13486-     //  Ensure no other thread uses old dictionary pointers
13487-     FlushProcessWriteBuffers ();
13488- }
13489- 
13490- void  Module::ExpandMethodDictionaries_Locked (MethodDesc* pMD, DictionaryLayout* pOldLayout, DictionaryLayout* pNewLayout)
13491- {
13492-     CONTRACTL
13493-     {
13494-         STANDARD_VM_CHECK;
13495-         INJECT_FAULT (ThrowOutOfMemory (););
13496-         PRECONDITION (CheckPointer (pOldLayout) && CheckPointer (pNewLayout));
13497-         PRECONDITION (CheckPointer (pMD));
13498-         PRECONDITION (pMD->HasMethodInstantiation () && pMD->GetDictionaryLayout () == pOldLayout);
13499-         PRECONDITION (SystemDomain::SystemModule ()->m_DictionaryCrst .OwnedByCurrentThread ());
13500-     }
13501-     CONTRACTL_END
13502- 
13503-     GCX_COOP ();
13504- 
13505-     // 
13506-     //  Dictionary expansion for methods needs to be done in two steps to ensure correctness for lock-free read operations 
13507-     //  for dictionary slots:
13508-     //       1) Allocate new dictionaries for all instantiated methods sharing the same canonical form as the input method
13509-     //       2) After all allocations and initializations are completed, publish the dictionaries to the methods after 
13510-     //          flushing write buffers
13511-     // 
13512- 
13513-     MethodDesc* pCanonMD = pMD->IsInstantiatingStub () ? pMD->GetExistingWrappedMethodDesc () : pMD;
13514-     _ASSERTE (pCanonMD != NULL );
13515-     DWORD oldInfoSize = DictionaryLayout::GetDictionarySizeFromLayout (pMD->GetNumGenericMethodArgs (), pOldLayout);
13516-     DWORD newInfoSize = DictionaryLayout::GetDictionarySizeFromLayout (pMD->GetNumGenericMethodArgs (), pNewLayout);
13517- 
13518-     struct  NewDictionary 
13519-     {
13520-         InstantiatedMethodDesc* pIMD;
13521-         TypeHandle* pDictSlots;
13522-     };
13523-     StackSArray<NewDictionary> dictionaryUpdates;
13524- 
13525- #ifdef  _DEBUG
13526-     auto  lambda = [oldInfoSize, newInfoSize, &dictionaryUpdates](OBJECTREF obj, MethodDesc* pMDKey, MethodDesc* pMDToUpdate)
13527- #else 
13528-     auto  lambda = [newInfoSize, &dictionaryUpdates](OBJECTREF obj, MethodDesc* pMDKey, MethodDesc* pMDToUpdate)
13529- #endif 
13530-     {
13531-         //  Update m_pPerInstInfo for the pMethodDesc being visited here
13532-         _ASSERTE (pMDToUpdate->IsInstantiatingStub () && pMDToUpdate->GetExistingWrappedMethodDesc () == pMDKey);
13533- 
13534-         InstantiatedMethodDesc* pInstantiatedMD = pMDToUpdate->AsInstantiatedMethodDesc ();
13535-         _ASSERTE (pInstantiatedMD->GetDictionarySlotsSize () == oldInfoSize);
13536- 
13537-         TypeHandle* pInstOrPerInstInfo = AllocateNewMethodDictionaryForExpansion (pInstantiatedMD, newInfoSize);
13538- 
13539-         NewDictionary entry;
13540-         entry.pIMD  = pInstantiatedMD;
13541-         entry.pDictSlots  = pInstOrPerInstInfo;
13542-         dictionaryUpdates.Append (entry);
13543- 
13544-         return  true ; //  Keep walking
13545-     };
13546- 
13547-     m_dynamicSlotsHashForMethods.VisitValuesOfKey (pCanonMD, lambda);
13548- 
13549-     //  Flush write buffers to ensure new dictionaries are fully writted and initalized before publishing them
13550-     FlushProcessWriteBuffers ();
13551- 
13552-     for  (SArray<NewDictionary>::Iterator i = dictionaryUpdates.Begin (); i != dictionaryUpdates.End (); i++)
13553-     {
13554-         FastInterlockExchangePointer ((TypeHandle**)i->pIMD ->m_pPerInstInfo .GetValuePtr (), i->pDictSlots );
13555-         _ASSERTE ((TypeHandle*)i->pIMD ->m_pPerInstInfo .GetValue () == i->pDictSlots );
13556-         _ASSERTE (i->pIMD ->GetDictionarySlotsSize () == newInfoSize);
13557-     }
13558- 
13559-     //  Ensure no other thread uses old dictionary pointers
13560-     FlushProcessWriteBuffers ();
13561- }
1356213236#endif  //  !CROSSGEN_COMPILE
1356313237
1356413238#endif  //  !DACCESS_COMPILE
0 commit comments