@@ -4745,11 +4745,25 @@ namespace
47454745 RemoveILStubCacheEntry ();
47464746 }
47474747
4748+ inline bool CreatedTheAssociatedPublishedStubMD ()
4749+ {
4750+ return m_bILStubCreator;
4751+ }
4752+
47484753 inline void GetStubMethodDesc ()
47494754 {
47504755 WRAPPER_NO_CONTRACT;
47514756
4757+ // The creator flag represents ownership of the associated stub MD and indicates that the
4758+ // stub MD has not been removed from the cache, so the lookup below is guaranteed to return
4759+ // this owned published stub MD.
4760+ #ifdef _DEBUG
4761+ MethodDesc* pPreexistingStubMD = m_pStubMD;
4762+ bool createdThePreexistingMD = m_bILStubCreator;
4763+ #endif // _DEBUG
4764+
47524765 m_pStubMD = ::GetStubMethodDesc (m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD);
4766+ _ASSERTE (!createdThePreexistingMD || (m_bILStubCreator && (m_pStubMD == pPreexistingStubMD)));
47534767 }
47544768
47554769 inline void RemoveILStubCacheEntry ()
@@ -4776,20 +4790,6 @@ namespace
47764790 m_amTracker.SuppressRelease ();
47774791 }
47784792
4779- DEBUG_NOINLINE static void HolderEnter (ILStubCreatorHelper *pThis)
4780- {
4781- WRAPPER_NO_CONTRACT;
4782- ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
4783- pThis->GetStubMethodDesc ();
4784- }
4785-
4786- DEBUG_NOINLINE static void HolderLeave (ILStubCreatorHelper *pThis)
4787- {
4788- WRAPPER_NO_CONTRACT;
4789- ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
4790- pThis->RemoveILStubCacheEntry ();
4791- }
4792-
47934793 private:
47944794 MethodDesc* m_pTargetMD;
47954795 NDirectStubParameters* m_pParams;
@@ -4800,8 +4800,6 @@ namespace
48004800 bool m_bILStubCreator; // Only the creator can remove the ILStub from the Cache
48014801 }; // ILStubCreatorHelper
48024802
4803- typedef Wrapper<ILStubCreatorHelper*, ILStubCreatorHelper::HolderEnter, ILStubCreatorHelper::HolderLeave> ILStubCreatorHelperHolder;
4804-
48054803 MethodDesc* CreateInteropILStub (
48064804 ILStubState* pss,
48074805 StubSigDesc* pSigDesc,
@@ -4875,8 +4873,8 @@ namespace
48754873 pSigDesc->m_pMT
48764874 );
48774875
4878- // The following two ILStubCreatorHelperHolder are to recover the status when an
4879- // exception happen during the generation of the IL stubs. We need to free the
4876+ // The following ILStubCreatorHelper is to recover the status when an
4877+ // exception happens during the generation of the IL stubs. We need to free the
48804878 // memory allocated and restore the ILStubCache.
48814879 //
48824880 // The following block is logically divided into two phases. The first phase is
@@ -4886,7 +4884,7 @@ namespace
48864884 //
48874885 // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
48884886 // allocated memory during the creation of MethodDesc so that we are able to remove
4889- // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper
4887+ // them when destructing ILStubCreatorHelper
48904888
48914889 // When removing IL Stub from Cache, we have a constraint that only the thread which
48924890 // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
@@ -4899,10 +4897,8 @@ namespace
48994897 ListLockHolder pILStubLock (pLoaderModule->GetDomain ()->GetILStubGenLock ());
49004898
49014899 {
4902- // The holder will free the allocated MethodDesc and restore the ILStubCache
4903- // if exception happen.
4904- ILStubCreatorHelperHolder pCreateOrGetStubHolder (&ilStubCreatorHelper);
4905- pStubMD = pCreateOrGetStubHolder->GetStubMD ();
4900+ ilStubCreatorHelper.GetStubMethodDesc ();
4901+ pStubMD = ilStubCreatorHelper.GetStubMD ();
49064902
49074903 // /////////////////////////////
49084904 //
@@ -4916,16 +4912,11 @@ namespace
49164912
49174913 ListLockEntryLockHolder pEntryLock (pEntry, FALSE );
49184914
4919- // We can release the holder for the first phase now
4920- pCreateOrGetStubHolder.SuppressRelease ();
4921-
49224915 // We have the entry lock we need to use, so we can release the global lock.
49234916 pILStubLock.Release ();
49244917
49254918 {
4926- // The holder will free the allocated MethodDesc and restore the ILStubCache
4927- // if exception happen. The reason to get the holder again is to
4928- ILStubCreatorHelperHolder pGenILHolder (&ilStubCreatorHelper);
4919+ ilStubCreatorHelper.GetStubMethodDesc ();
49294920
49304921 if (!pEntryLock.DeadlockAwareAcquire ())
49314922 {
@@ -4950,11 +4941,11 @@ namespace
49504941 pILStubLock.Acquire ();
49514942
49524943 // Assure that pStubMD we have now has not been destroyed by other threads
4953- pGenILHolder-> GetStubMethodDesc ();
4944+ ilStubCreatorHelper. GetStubMethodDesc ();
49544945
4955- while (pStubMD != pGenILHolder-> GetStubMD ())
4946+ while (pStubMD != ilStubCreatorHelper. GetStubMD ())
49564947 {
4957- pStubMD = pGenILHolder-> GetStubMD ();
4948+ pStubMD = ilStubCreatorHelper. GetStubMD ();
49584949
49594950 pEntry.Assign (ListLockEntry::Find (pILStubLock, pStubMD, " il stub gen lock" ));
49604951 pEntryLock.Assign (pEntry, FALSE );
@@ -4980,7 +4971,7 @@ namespace
49804971
49814972 pILStubLock.Acquire ();
49824973
4983- pGenILHolder-> GetStubMethodDesc ();
4974+ ilStubCreatorHelper. GetStubMethodDesc ();
49844975 }
49854976 }
49864977
@@ -5064,22 +5055,38 @@ namespace
50645055 sgh.SuppressRelease ();
50655056 }
50665057
5067- if (pGeneratedNewStub)
5068- {
5069- *pGeneratedNewStub = true ;
5070- }
5071-
50725058 pEntry->m_hrResultCode = S_OK;
50735059 break ;
50745060 }
50755061
50765062 // Link the MethodDesc onto the method table with the lock taken
50775063 AddMethodDescChunkWithLockTaken (¶ms, pStubMD);
5078-
5079- pGenILHolder.SuppressRelease ();
50805064 }
50815065 }
50825066 }
5067+
5068+ // Callers use the new stub indicator to distinguish between 1) the case where a new stub
5069+ // MD was generated during this call and 2) the case where this function attached to a stub
5070+ // MD that was generated by some other call (either a call that completed earlier or a call
5071+ // on a racing thread). In particular, reliably detecting case (1) is crucial because it is
5072+ // the only case where this call permanently publishes a new stub MD into the cache,
5073+ // meaning it is the only case where the caller cannot safely free any allocations (such as
5074+ // a signature buffer) which the stub MD might reference.
5075+ //
5076+ // Set the indicator if and only if the stub MD that will be imminiently returned to the
5077+ // caller was created by the code above (and will therefore become a permanent member of
5078+ // the cache when the SuppressRelease occurs below). Note that, in the presence of racing
5079+ // threads, the current call may or may not have carried out IL generation for the stub;
5080+ // the only important thing is whether the current call was the one that created the stub
5081+ // MD earlier on.
5082+ if (ilStubCreatorHelper.CreatedTheAssociatedPublishedStubMD ())
5083+ {
5084+ if (pGeneratedNewStub)
5085+ {
5086+ *pGeneratedNewStub = true ;
5087+ }
5088+ }
5089+
50835090 ilStubCreatorHelper.SuppressRelease ();
50845091 }
50855092
0 commit comments