Skip to content

Commit b592364

Browse files
authored
Fix pGeneratedNewStub determination (#80128)
* Fix pGeneratedNewStub determination * Remove unnecessary ILStubCreatorHelperHolder concept
1 parent 9197fd5 commit b592364

File tree

1 file changed

+47
-40
lines changed

1 file changed

+47
-40
lines changed

src/coreclr/vm/dllimport.cpp

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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(&params, 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

Comments
 (0)