// step 3 - update each pre-existing method instantiation
{
+ // Backpatching entry point slots requires cooperative GC mode, see
+ // MethodDescBackpatchInfoTracker::Backpatch_Locked(). The code version manager's table lock is an unsafe lock that
+ // may be taken in any GC mode. The lock is taken in cooperative GC mode on some other paths, so the same ordering
+ // must be used here to prevent deadlock.
+ GCX_COOP();
TableLockHolder lock(this);
+
for (DWORD i = 0; i < cActiveVersions; i++)
{
// Its possible the active IL version has changed if
pCode = pMethodDesc->PrepareCode(activeVersion);
}
- MethodDescBackpatchInfoTracker::ConditionalLockHolder lockHolder(pMethodDesc->MayHaveEntryPointSlotsToBackpatch());
+ bool mayHaveEntryPointSlotsToBackpatch = pMethodDesc->MayHaveEntryPointSlotsToBackpatch();
+ MethodDescBackpatchInfoTracker::ConditionalLockHolder lockHolder(mayHaveEntryPointSlotsToBackpatch);
// suspend in preparation for publishing if needed
if (fEESuspend)
}
{
+ // Backpatching entry point slots requires cooperative GC mode, see
+ // MethodDescBackpatchInfoTracker::Backpatch_Locked(). The code version manager's table lock is an unsafe lock that
+ // may be taken in any GC mode. The lock is taken in cooperative GC mode on some other paths, so the same ordering
+ // must be used here to prevent deadlock.
+ GCX_MAYBE_COOP(mayHaveEntryPointSlotsToBackpatch);
TableLockHolder lock(this);
+
// The common case is that newActiveCode == activeCode, however we did leave the lock so there is
// possibility that the active version has changed. If it has we need to restart the compilation
// and publishing process with the new active version instead.
break;
}
}
- } // exit lock
+ } // exit lock, revert GC mode
if (fEESuspend)
{
{
// TODO: This function needs to make sure it does not change the precode's target if call counting is in progress. Track
// whether call counting is currently being done for the method, and use a lock to ensure the expected precode target.
- WRAPPER_NO_CONTRACT;
+
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+
+ // Backpatching entry point slots requires cooperative GC mode, see MethodDescBackpatchInfoTracker::Backpatch_Locked().
+ // The code version manager's table lock is an unsafe lock that may be taken in any GC mode. The lock is taken in
+ // cooperative GC mode on other paths, so the caller must use the same ordering to prevent deadlock (switch to
+ // cooperative GC mode before taking the lock).
+ if (pMethod->MayHaveEntryPointSlotsToBackpatch())
+ {
+ MODE_COOPERATIVE;
+ }
+ else
+ {
+ MODE_ANY;
+ }
+ }
+ CONTRACTL_END;
+
_ASSERTE(LockOwnedByCurrentThread());
_ASSERTE(pMethod->IsVersionable());
+
HRESULT hr = S_OK;
PCODE pCode = nativeCodeVersion.IsNull() ? NULL : nativeCodeVersion.GetNativeCode();
if (pMethod->IsVersionableWithoutJumpStamp())
// code version will activate then.
ILCodeVersion ilParent;
HRESULT hr = S_OK;
- MethodDescBackpatchInfoTracker::ConditionalLockHolder lockHolder;
+ bool mayHaveEntryPointSlotsToBackpatch = pMethod->MayHaveEntryPointSlotsToBackpatch();
+ MethodDescBackpatchInfoTracker::ConditionalLockHolder lockHolder(mayHaveEntryPointSlotsToBackpatch);
{
- // As long as we are exclusively using precode publishing for tiered compilation
- // methods this first attempt should succeed
+ // Backpatching entry point slots requires cooperative GC mode, see
+ // MethodDescBackpatchInfoTracker::Backpatch_Locked(). The code version manager's table lock is an unsafe lock that
+ // may be taken in any GC mode. The lock is taken in cooperative GC mode on some other paths, so the same ordering
+ // must be used here to prevent deadlock.
+ GCX_MAYBE_COOP(mayHaveEntryPointSlotsToBackpatch);
CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
+
+ // As long as we are exclusively using any non-JumpStamp publishing for tiered compilation
+ // methods this first attempt should succeed
ilParent = nativeCodeVersion.GetILCodeVersion();
hr = ilParent.SetActiveNativeCodeVersion(nativeCodeVersion, FALSE);
LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::ActivateCodeVersion Method=0x%pM (%s::%s), code version id=0x%x. SetActiveNativeCodeVersion ret=0x%x\n",
// viable. This fallback path is just here as a proof-of-concept.
ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_REJIT);
{
+ // Backpatching entry point slots requires cooperative GC mode, see
+ // MethodDescBackpatchInfoTracker::Backpatch_Locked(). The code version manager's table lock is an unsafe lock that
+ // may be taken in any GC mode. The lock is taken in cooperative GC mode on some other paths, so the same ordering
+ // must be used here to prevent deadlock.
+ GCX_MAYBE_COOP(mayHaveEntryPointSlotsToBackpatch);
CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
+
hr = ilParent.SetActiveNativeCodeVersion(nativeCodeVersion, TRUE);
LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::ActivateCodeVersion Method=0x%pM (%s::%s), code version id=0x%x. [Suspended] SetActiveNativeCodeVersion ret=0x%x\n",
pMethod, pMethod->m_pszDebugClassName, pMethod->m_pszDebugMethodName,