@@ -4745,11 +4745,25 @@ namespace
4745
4745
RemoveILStubCacheEntry ();
4746
4746
}
4747
4747
4748
+ inline bool CreatedTheAssociatedPublishedStubMD ()
4749
+ {
4750
+ return m_bILStubCreator;
4751
+ }
4752
+
4748
4753
inline void GetStubMethodDesc ()
4749
4754
{
4750
4755
WRAPPER_NO_CONTRACT;
4751
4756
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
+
4752
4765
m_pStubMD = ::GetStubMethodDesc (m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD);
4766
+ _ASSERTE (!createdThePreexistingMD || (m_bILStubCreator && (m_pStubMD == pPreexistingStubMD)));
4753
4767
}
4754
4768
4755
4769
inline void RemoveILStubCacheEntry ()
@@ -4776,20 +4790,6 @@ namespace
4776
4790
m_amTracker.SuppressRelease ();
4777
4791
}
4778
4792
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
-
4793
4793
private:
4794
4794
MethodDesc* m_pTargetMD;
4795
4795
NDirectStubParameters* m_pParams;
@@ -4800,8 +4800,6 @@ namespace
4800
4800
bool m_bILStubCreator; // Only the creator can remove the ILStub from the Cache
4801
4801
}; // ILStubCreatorHelper
4802
4802
4803
- typedef Wrapper<ILStubCreatorHelper*, ILStubCreatorHelper::HolderEnter, ILStubCreatorHelper::HolderLeave> ILStubCreatorHelperHolder;
4804
-
4805
4803
MethodDesc* CreateInteropILStub (
4806
4804
ILStubState* pss,
4807
4805
StubSigDesc* pSigDesc,
@@ -4875,8 +4873,8 @@ namespace
4875
4873
pSigDesc->m_pMT
4876
4874
);
4877
4875
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
4880
4878
// memory allocated and restore the ILStubCache.
4881
4879
//
4882
4880
// The following block is logically divided into two phases. The first phase is
@@ -4886,7 +4884,7 @@ namespace
4886
4884
//
4887
4885
// ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
4888
4886
// 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
4890
4888
4891
4889
// When removing IL Stub from Cache, we have a constraint that only the thread which
4892
4890
// creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
@@ -4899,10 +4897,8 @@ namespace
4899
4897
ListLockHolder pILStubLock (pLoaderModule->GetDomain ()->GetILStubGenLock ());
4900
4898
4901
4899
{
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 ();
4906
4902
4907
4903
// /////////////////////////////
4908
4904
//
@@ -4916,16 +4912,11 @@ namespace
4916
4912
4917
4913
ListLockEntryLockHolder pEntryLock (pEntry, FALSE );
4918
4914
4919
- // We can release the holder for the first phase now
4920
- pCreateOrGetStubHolder.SuppressRelease ();
4921
-
4922
4915
// We have the entry lock we need to use, so we can release the global lock.
4923
4916
pILStubLock.Release ();
4924
4917
4925
4918
{
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 ();
4929
4920
4930
4921
if (!pEntryLock.DeadlockAwareAcquire ())
4931
4922
{
@@ -4950,11 +4941,11 @@ namespace
4950
4941
pILStubLock.Acquire ();
4951
4942
4952
4943
// Assure that pStubMD we have now has not been destroyed by other threads
4953
- pGenILHolder-> GetStubMethodDesc ();
4944
+ ilStubCreatorHelper. GetStubMethodDesc ();
4954
4945
4955
- while (pStubMD != pGenILHolder-> GetStubMD ())
4946
+ while (pStubMD != ilStubCreatorHelper. GetStubMD ())
4956
4947
{
4957
- pStubMD = pGenILHolder-> GetStubMD ();
4948
+ pStubMD = ilStubCreatorHelper. GetStubMD ();
4958
4949
4959
4950
pEntry.Assign (ListLockEntry::Find (pILStubLock, pStubMD, " il stub gen lock" ));
4960
4951
pEntryLock.Assign (pEntry, FALSE );
@@ -4980,7 +4971,7 @@ namespace
4980
4971
4981
4972
pILStubLock.Acquire ();
4982
4973
4983
- pGenILHolder-> GetStubMethodDesc ();
4974
+ ilStubCreatorHelper. GetStubMethodDesc ();
4984
4975
}
4985
4976
}
4986
4977
@@ -5064,22 +5055,38 @@ namespace
5064
5055
sgh.SuppressRelease ();
5065
5056
}
5066
5057
5067
- if (pGeneratedNewStub)
5068
- {
5069
- *pGeneratedNewStub = true ;
5070
- }
5071
-
5072
5058
pEntry->m_hrResultCode = S_OK;
5073
5059
break ;
5074
5060
}
5075
5061
5076
5062
// Link the MethodDesc onto the method table with the lock taken
5077
5063
AddMethodDescChunkWithLockTaken (¶ms, pStubMD);
5078
-
5079
- pGenILHolder.SuppressRelease ();
5080
5064
}
5081
5065
}
5082
5066
}
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
+
5083
5090
ilStubCreatorHelper.SuppressRelease ();
5084
5091
}
5085
5092
0 commit comments