Some cleanups in Native AOT suspension area (#69885)
authorVladimir Sadov <vsadov@microsoft.com>
Fri, 3 Jun 2022 13:42:29 +0000 (06:42 -0700)
committerGitHub <noreply@github.com>
Fri, 3 Jun 2022 13:42:29 +0000 (06:42 -0700)
* some renames

* strongly typed transition frames

* remove remaining pieces of LoopHijack

* comments and some refactoring

* IsManaged

* removed m_CodeManagerList

* m_ModuleListLock

* better comment for a SafeHandle hack

* Renamed SetupHackPInvokeTunnel  (to not have "hack in the name)

* made IsInForbidBlockingRegion a debug-only assert

* removed ForbidBlockingHolder

* remove forbidBlocking tracking. It only affects 4 methods.

* Fix Unix build

* typo

* record managed code range in RuntimeInstance.

30 files changed:
src/coreclr/nativeaot/Runtime/AsmOffsets.h
src/coreclr/nativeaot/Runtime/EHHelpers.cpp
src/coreclr/nativeaot/Runtime/GCHelpers.cpp
src/coreclr/nativeaot/Runtime/ICodeManager.h
src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
src/coreclr/nativeaot/Runtime/RuntimeInstance.cpp
src/coreclr/nativeaot/Runtime/RuntimeInstance.h
src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp
src/coreclr/nativeaot/Runtime/StackFrameIterator.h
src/coreclr/nativeaot/Runtime/TypeManager.cpp
src/coreclr/nativeaot/Runtime/TypeManager.h
src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm
src/coreclr/nativeaot/Runtime/arm/GcProbe.asm
src/coreclr/nativeaot/Runtime/arm64/GcProbe.asm
src/coreclr/nativeaot/Runtime/gcrhenv.cpp
src/coreclr/nativeaot/Runtime/gcrhscan.cpp
src/coreclr/nativeaot/Runtime/i386/GcProbe.asm
src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h
src/coreclr/nativeaot/Runtime/inc/rhbinder.h
src/coreclr/nativeaot/Runtime/stressLog.cpp
src/coreclr/nativeaot/Runtime/thread.cpp
src/coreclr/nativeaot/Runtime/thread.h
src/coreclr/nativeaot/Runtime/thread.inl
src/coreclr/nativeaot/Runtime/threadstore.cpp
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.h
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.h
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.NativeAot.cs
src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs

index 4d24072..dc63aa4 100644 (file)
@@ -42,7 +42,7 @@ ASM_OFFSET(   14,    18, MethodTable, m_VTable)
 ASM_OFFSET(    0,     0, Thread, m_rgbAllocContextBuffer)
 ASM_OFFSET(   28,    38, Thread, m_ThreadStateFlags)
 ASM_OFFSET(   2c,    40, Thread, m_pTransitionFrame)
-ASM_OFFSET(   30,    48, Thread, m_pHackPInvokeTunnel)
+ASM_OFFSET(   30,    48, Thread, m_pDeferredTransitionFrame)
 ASM_OFFSET(   40,    68, Thread, m_ppvHijackedReturnAddressLocation)
 ASM_OFFSET(   44,    70, Thread, m_pvHijackedReturnAddress)
 #ifdef HOST_64BIT
index 5c47809..507cb07 100644 (file)
@@ -390,7 +390,7 @@ int32_t __stdcall RhpHardwareExceptionHandler(uintptr_t faultCode, uintptr_t fau
 {
     uintptr_t faultingIP = palContext->GetIp();
 
-    ICodeManager * pCodeManager = GetRuntimeInstance()->FindCodeManagerByAddress((PTR_VOID)faultingIP);
+    ICodeManager * pCodeManager = GetRuntimeInstance()->GetCodeManagerForAddress((PTR_VOID)faultingIP);
     bool translateToManagedException = false;
     if (pCodeManager != NULL)
     {
@@ -471,7 +471,7 @@ int32_t __stdcall RhpVectoredExceptionHandler(PEXCEPTION_POINTERS pExPtrs)
 
     uintptr_t faultingIP = pExPtrs->ContextRecord->GetIp();
 
-    ICodeManager * pCodeManager = GetRuntimeInstance()->FindCodeManagerByAddress((PTR_VOID)faultingIP);
+    ICodeManager * pCodeManager = GetRuntimeInstance()->GetCodeManagerForAddress((PTR_VOID)faultingIP);
     bool translateToManagedException = false;
     if (pCodeManager != NULL)
     {
index 6f7c1e5..1c4f851 100644 (file)
@@ -31,7 +31,7 @@ EXTERN_C NATIVEAOT_API void __cdecl RhpCollect(uint32_t uGeneration, uint32_t uM
 
     Thread * pCurThread = ThreadStore::GetCurrentThread();
 
-    pCurThread->SetupHackPInvokeTunnel();
+    pCurThread->DeferTransitionFrame();
     pCurThread->DisablePreemptiveMode();
 
     ASSERT(!pCurThread->IsDoNotTriggerGcSet());
@@ -46,7 +46,7 @@ EXTERN_C NATIVEAOT_API int64_t __cdecl RhpGetGcTotalMemory()
 
     Thread * pCurThread = ThreadStore::GetCurrentThread();
 
-    pCurThread->SetupHackPInvokeTunnel();
+    pCurThread->DeferTransitionFrame();
     pCurThread->DisablePreemptiveMode();
 
     int64_t ret = GCHeapUtilities::GetGCHeap()->GetTotalBytesInUse();
@@ -61,7 +61,7 @@ EXTERN_C NATIVEAOT_API int32_t __cdecl RhpStartNoGCRegion(int64_t totalSize, UIn
     Thread *pCurThread = ThreadStore::GetCurrentThread();
     ASSERT(!pCurThread->IsCurrentThreadInCooperativeMode());
 
-    pCurThread->SetupHackPInvokeTunnel();
+    pCurThread->DeferTransitionFrame();
     pCurThread->DisablePreemptiveMode();
 
     int result = GCHeapUtilities::GetGCHeap()->StartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC);
@@ -316,7 +316,7 @@ EXTERN_C NATIVEAOT_API void RhAllocateNewArray(MethodTable* pArrayEEType, uint32
 {
     Thread* pThread = ThreadStore::GetCurrentThread();
 
-    pThread->SetupHackPInvokeTunnel();
+    pThread->DeferTransitionFrame();
     pThread->DisablePreemptiveMode();
 
     ASSERT(!pThread->IsDoNotTriggerGcSet());
@@ -330,7 +330,7 @@ EXTERN_C NATIVEAOT_API void RhAllocateNewObject(MethodTable* pEEType, uint32_t f
 {
     Thread* pThread = ThreadStore::GetCurrentThread();
 
-    pThread->SetupHackPInvokeTunnel();
+    pThread->DeferTransitionFrame();
     pThread->DisablePreemptiveMode();
 
     ASSERT(!pThread->IsDoNotTriggerGcSet());
index d3b46b6..587b102 100644 (file)
@@ -1,8 +1,8 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
-#pragma once
 
-#define ICODEMANAGER_INCLUDED
+#pragma once
+#include <rhbinder.h>
 
 // TODO: Debugger/DAC support (look for TODO: JIT)
 
@@ -10,8 +10,6 @@ struct REGDISPLAY;
 
 #define GC_CALL_INTERIOR            0x1
 #define GC_CALL_PINNED              0x2
-#define GC_CALL_CHECK_APP_DOMAIN    0x4
-#define GC_CALL_STATIC              0x8
 
 typedef void (*GCEnumCallback)(
     void *              hCallback,      // callback data
@@ -47,6 +45,27 @@ enum GCRefKind : unsigned char
 };
 
 #ifdef TARGET_ARM64
+// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
+C_ASSERT(PTFF_X0_IS_GCREF == ((uint64_t)GCRK_Object << 32));
+C_ASSERT(PTFF_X0_IS_BYREF == ((uint64_t)GCRK_Byref << 32));
+C_ASSERT(PTFF_X1_IS_GCREF == ((uint64_t)GCRK_Scalar_Obj << 32));
+C_ASSERT(PTFF_X1_IS_BYREF == ((uint64_t)GCRK_Scalar_Byref << 32));
+
+inline uint64_t ReturnKindToTransitionFrameFlags(GCRefKind returnKind)
+{
+    if (returnKind == GCRK_Scalar)
+        return 0;
+
+    return PTFF_SAVE_X0 | PTFF_SAVE_X1 | ((uint64_t)returnKind << 32);
+}
+
+inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
+{
+    GCRefKind returnKind = (GCRefKind)((transFrameFlags & (PTFF_X0_IS_GCREF | PTFF_X0_IS_BYREF | PTFF_X1_IS_GCREF | PTFF_X1_IS_BYREF)) >> 32);
+    ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_X0) && (transFrameFlags & PTFF_SAVE_X1)));
+    return returnKind;
+}
+
 // Extract individual GCRefKind components from a composite return kind
 inline GCRefKind ExtractReg0ReturnKind(GCRefKind returnKind)
 {
@@ -135,7 +154,7 @@ public:
 
     virtual bool UnwindStackFrame(MethodInfo *    pMethodInfo,
                                   REGDISPLAY *    pRegisterSet,                     // in/out
-                                  PTR_VOID *      ppPreviousTransitionFrame) = 0;   // out
+                                  PInvokeTransitionFrame**      ppPreviousTransitionFrame) = 0;   // out
 
     virtual uintptr_t GetConservativeUpperBoundForOutgoingArgs(MethodInfo *   pMethodInfo,
                                                                 REGDISPLAY *   pRegisterSet) = 0;
index d3c58ed..064da7e 100644 (file)
@@ -109,7 +109,7 @@ COOP_PINVOKE_HELPER(uint32_t, RhGetLoadedOSModules, (Array * pResultArray))
 
 COOP_PINVOKE_HELPER(HANDLE, RhGetOSModuleFromPointer, (PTR_VOID pPointerVal))
 {
-    ICodeManager * pCodeManager = GetRuntimeInstance()->FindCodeManagerByAddress(pPointerVal);
+    ICodeManager * pCodeManager = GetRuntimeInstance()->GetCodeManagerForAddress(pPointerVal);
 
     if (pCodeManager != NULL)
         return (HANDLE)pCodeManager->GetOsModuleHandle();
@@ -393,7 +393,7 @@ EXTERN_C NATIVEAOT_API int32_t __cdecl RhpGetCurrentThreadStackTrace(void* pOutp
 {
     // This must be called via p/invoke rather than RuntimeImport to make the stack crawlable.
 
-    ThreadStore::GetCurrentThread()->SetupHackPInvokeTunnel();
+    ThreadStore::GetCurrentThread()->DeferTransitionFrame();
 
     return RhpCalculateStackTraceWorker(pOutputBuffer, outputBufferLength, pAddressInCurrentFrame);
 }
index 8ce73e0..e53a169 100644 (file)
@@ -56,7 +56,7 @@ COOP_PINVOKE_HELPER(uint8_t *, RhFindMethodStartAddress, (void * codeAddr))
 
 PTR_UInt8 RuntimeInstance::FindMethodStartAddress(PTR_VOID ControlPC)
 {
-    ICodeManager * pCodeManager = FindCodeManagerByAddress(ControlPC);
+    ICodeManager * pCodeManager = GetCodeManagerForAddress(ControlPC);
     MethodInfo methodInfo;
     if (pCodeManager != NULL && pCodeManager->FindMethodInfo(ControlPC, &methodInfo))
     {
@@ -66,20 +66,23 @@ PTR_UInt8 RuntimeInstance::FindMethodStartAddress(PTR_VOID ControlPC)
     return NULL;
 }
 
-ICodeManager * RuntimeInstance::FindCodeManagerByAddress(PTR_VOID pvAddress)
+// WARNING: This method is called by suspension while one thread is interrupted
+//          in a random location, possibly holding random locks.
+//          It is unsafe to use blocking APIs or allocate in this method.
+//          Please ensure that all methods called by this one also have this warning.
+bool RuntimeInstance::IsManaged(PTR_VOID pvAddress)
 {
-    ReaderWriterLock::ReadHolder read(&m_ModuleListLock);
+    return (dac_cast<TADDR>(pvAddress) - dac_cast<TADDR>(m_pvManagedCodeStartRange) < m_cbManagedCodeRange);
+}
 
-    // TODO: ICodeManager support in DAC
-#ifndef DACCESS_COMPILE
-    for (CodeManagerEntry * pEntry = m_CodeManagerList.GetHead(); pEntry != NULL; pEntry = pEntry->m_pNext)
+ICodeManager * RuntimeInstance::GetCodeManagerForAddress(PTR_VOID pvAddress)
+{
+    if (!IsManaged(pvAddress))
     {
-        if (dac_cast<TADDR>(pvAddress) - dac_cast<TADDR>(pEntry->m_pvStartRange) < pEntry->m_cbRange)
-            return pEntry->m_pCodeManager;
+        return NULL;
     }
-#endif
 
-    return NULL;
+    return m_CodeManager;
 }
 
 #ifndef DACCESS_COMPILE
@@ -90,7 +93,7 @@ ICodeManager * RuntimeInstance::FindCodeManagerByAddress(PTR_VOID pvAddress)
 ICodeManager * RuntimeInstance::FindCodeManagerForClasslibFunction(PTR_VOID address)
 {
     // Try looking up the code manager assuming the address is for code first. This is expected to be most common.
-    ICodeManager * pCodeManager = FindCodeManagerByAddress(address);
+    ICodeManager * pCodeManager = GetCodeManagerForAddress(address);
     if (pCodeManager != NULL)
         return pCodeManager;
 
@@ -119,7 +122,7 @@ void * RuntimeInstance::GetClasslibFunctionFromCodeAddress(PTR_VOID address, Cla
 
 PTR_UInt8 RuntimeInstance::GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID ControlPC)
 {
-    ICodeManager * pCodeManager = FindCodeManagerByAddress(ControlPC);
+    ICodeManager * pCodeManager = GetCodeManagerForAddress(ControlPC);
     if (pCodeManager != NULL)
     {
         PTR_UInt8 pData = (PTR_UInt8)pCodeManager->GetAssociatedData(ControlPC);
@@ -137,6 +140,10 @@ PTR_UInt8 RuntimeInstance::GetTargetOfUnboxingAndInstantiatingStub(PTR_VOID Cont
 
 GPTR_IMPL_INIT(RuntimeInstance, g_pTheRuntimeInstance, NULL);
 
+// WARNING: This method is called by suspension while one thread is interrupted
+//          in a random location, possibly holding random locks.
+//          It is unsafe to use blocking APIs or allocate in this method.
+//          Please ensure that all methods called by this one also have this warning.
 PTR_RuntimeInstance GetRuntimeInstance()
 {
     return g_pTheRuntimeInstance;
@@ -150,14 +157,6 @@ void RuntimeInstance::EnumAllStaticGCRefs(void * pfnCallback, void * pvCallbackD
     }
 }
 
-void RuntimeInstance::SetLoopHijackFlags(uint32_t flag)
-{
-    for (TypeManagerList::Iterator iter = m_TypeManagerList.Begin(); iter != m_TypeManagerList.End(); iter++)
-    {
-        iter->m_pTypeManager->SetLoopHijackFlag(flag);
-    }
-}
-
 RuntimeInstance::OsModuleList* RuntimeInstance::GetOsModuleList()
 {
     return dac_cast<DPTR(OsModuleList)>(dac_cast<TADDR>(this) + offsetof(RuntimeInstance, m_OsModuleList));
@@ -165,13 +164,14 @@ RuntimeInstance::OsModuleList* RuntimeInstance::GetOsModuleList()
 
 ReaderWriterLock& RuntimeInstance::GetTypeManagerLock()
 {
-    return m_ModuleListLock;
+    return m_TypeManagerLock;
 }
 
 #ifndef DACCESS_COMPILE
 
 RuntimeInstance::RuntimeInstance() :
     m_pThreadStore(NULL),
+    m_CodeManager(NULL),
     m_conservativeStackReportingEnabled(false),
     m_pUnboxingStubsRegion(NULL)
 {
@@ -196,56 +196,19 @@ void RuntimeInstance::EnableConservativeStackReporting()
     m_conservativeStackReportingEnabled = true;
 }
 
-bool RuntimeInstance::RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
+void RuntimeInstance::RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
 {
-    CodeManagerEntry * pEntry = new (nothrow) CodeManagerEntry();
-    if (NULL == pEntry)
-        return false;
+    _ASSERTE(m_CodeManager == NULL);
+    _ASSERTE(pCodeManager != NULL);
 
-    pEntry->m_pvStartRange = pvStartRange;
-    pEntry->m_cbRange = cbRange;
-    pEntry->m_pCodeManager = pCodeManager;
-
-    {
-        ReaderWriterLock::WriteHolder write(&m_ModuleListLock);
-
-        m_CodeManagerList.PushHead(pEntry);
-    }
-
-    return true;
-}
-
-void RuntimeInstance::UnregisterCodeManager(ICodeManager * pCodeManager)
-{
-    CodeManagerEntry * pEntry = NULL;
-
-    {
-        ReaderWriterLock::WriteHolder write(&m_ModuleListLock);
-
-        for (CodeManagerList::Iterator i = m_CodeManagerList.Begin(), end = m_CodeManagerList.End(); i != end; i++)
-        {
-            if (i->m_pCodeManager == pCodeManager)
-            {
-                pEntry = *i;
-
-                m_CodeManagerList.Remove(i);
-                break;
-            }
-        }
-    }
-
-    ASSERT(pEntry != NULL);
-    delete pEntry;
-}
-
-extern "C" bool __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
-{
-    return GetRuntimeInstance()->RegisterCodeManager(pCodeManager, pvStartRange, cbRange);
+    m_CodeManager = pCodeManager;
+    m_pvManagedCodeStartRange = pvStartRange;
+    m_cbManagedCodeRange = cbRange;
 }
 
-extern "C" void __stdcall UnregisterCodeManager(ICodeManager * pCodeManager)
+extern "C" void __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange)
 {
-    return GetRuntimeInstance()->UnregisterCodeManager(pCodeManager);
+    GetRuntimeInstance()->RegisterCodeManager(pCodeManager, pvStartRange, cbRange);
 }
 
 bool RuntimeInstance::RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange)
@@ -297,7 +260,7 @@ bool RuntimeInstance::RegisterTypeManager(TypeManager * pTypeManager)
     pEntry->m_pTypeManager = pTypeManager;
 
     {
-        ReaderWriterLock::WriteHolder write(&m_ModuleListLock);
+        ReaderWriterLock::WriteHolder write(&m_TypeManagerLock);
 
         m_TypeManagerList.PushHead(pEntry);
     }
index 6b74f77..245b5dc 100644 (file)
@@ -25,7 +25,7 @@ class RuntimeInstance
 
     PTR_ThreadStore             m_pThreadStore;
     HANDLE                      m_hPalInstance; // this is the HANDLE passed into DllMain
-    ReaderWriterLock            m_ModuleListLock;
+    ReaderWriterLock            m_TypeManagerLock;
 
 public:
     struct OsModuleEntry;
@@ -40,19 +40,11 @@ public:
 private:
     OsModuleList                m_OsModuleList;
 
-    struct CodeManagerEntry;
-    typedef DPTR(CodeManagerEntry) PTR_CodeManagerEntry;
+    ICodeManager*               m_CodeManager;
 
-    struct CodeManagerEntry
-    {
-        PTR_CodeManagerEntry    m_pNext;
-        PTR_VOID                m_pvStartRange;
-        uint32_t                  m_cbRange;
-        ICodeManager *          m_pCodeManager;
-    };
-
-    typedef SList<CodeManagerEntry> CodeManagerList;
-    CodeManagerList             m_CodeManagerList;
+    // we support only one code manager for now, so we just record the range.
+    void*                       m_pvManagedCodeStartRange;
+    uint32_t                    m_cbManagedCodeRange;
 
 public:
     struct TypeManagerEntry
@@ -99,10 +91,9 @@ public:
     void EnableConservativeStackReporting();
     bool IsConservativeStackReportingEnabled() { return m_conservativeStackReportingEnabled; }
 
-    bool RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
-    void UnregisterCodeManager(ICodeManager * pCodeManager);
+    void RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
 
-    ICodeManager * FindCodeManagerByAddress(PTR_VOID ControlPC);
+    ICodeManager * GetCodeManagerForAddress(PTR_VOID ControlPC);
     PTR_VOID GetClasslibFunctionFromCodeAddress(PTR_VOID address, ClasslibFunctionId functionId);
 
     bool RegisterTypeManager(TypeManager * pTypeManager);
@@ -113,6 +104,8 @@ public:
     bool RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange);
     bool IsUnboxingStub(uint8_t* pCode);
 
+    bool IsManaged(PTR_VOID pvAddress);
+
     static bool Initialize(HANDLE hPalInstance);
     void Destroy();
 
@@ -120,7 +113,6 @@ public:
 
     bool ShouldHijackCallsiteForGcStress(uintptr_t CallsiteIP);
     bool ShouldHijackLoopForGcStress(uintptr_t CallsiteIP);
-    void SetLoopHijackFlags(uint32_t flag);
 };
 typedef DPTR(RuntimeInstance) PTR_RuntimeInstance;
 
index af12ff4..18d71fa 100644 (file)
@@ -88,16 +88,11 @@ GVAL_IMPL_INIT(PTR_VOID, g_RhpRethrow2Addr, PointerToRhpRethrow2);
 #define FAILFAST_OR_DAC_FAIL_UNCONDITIONALLY(msg) { ASSERT_UNCONDITIONALLY(msg); RhFailFast(); }
 #endif
 
-PTR_PInvokeTransitionFrame GetPInvokeTransitionFrame(PTR_VOID pTransitionFrame)
-{
-    return static_cast<PTR_PInvokeTransitionFrame>(pTransitionFrame);
-}
-
-StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PTR_VOID pInitialTransitionFrame)
+StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PInvokeTransitionFrame* pInitialTransitionFrame)
 {
     STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ GC ]\n");
     ASSERT(!pThreadToWalk->DangerousCrossThreadIsHijacked());
-    InternalInit(pThreadToWalk, GetPInvokeTransitionFrame(pInitialTransitionFrame), GcStackWalkFlags);
+    InternalInit(pThreadToWalk, pInitialTransitionFrame, GcStackWalkFlags);
     PrepareToYieldFrame();
 }
 
@@ -140,7 +135,7 @@ void StackFrameIterator::EnterInitialInvalidState(Thread * pThreadToWalk)
 // NOTE: When the PC is in an assembly thunk, this function will unwind to the next managed
 // frame and may publish a conservative stack range (if and only if any of the unwound
 // thunks report a conservative range).
-void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PInvokeTransitionFrame pFrame, uint32_t dwFlags)
+void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PInvokeTransitionFrame* pFrame, uint32_t dwFlags)
 {
     // EH stackwalks are always required to unwind non-volatile floating point state.  This
     // state is never carried by PInvokeTransitionFrames, implying that they can never be used
@@ -306,12 +301,12 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PInvokeTransit
 
     if (category == InManagedCode)
     {
-        ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC));
+        ASSERT(m_pInstance->IsManaged(m_ControlPC));
     }
     else if (IsNonEHThunk(category))
     {
         UnwindNonEHThunkSequence();
-        ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC));
+        ASSERT(m_pInstance->IsManaged(m_ControlPC));
     }
     else
     {
@@ -349,8 +344,8 @@ void StackFrameIterator::InternalInitForStackTrace()
 {
     STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ StackTrace ]\n");
     Thread * pThreadToWalk = ThreadStore::GetCurrentThread();
-    PTR_VOID pFrame = pThreadToWalk->GetTransitionFrameForStackTrace();
-    InternalInit(pThreadToWalk, GetPInvokeTransitionFrame(pFrame), StackTraceStackWalkFlags);
+    PInvokeTransitionFrame* pFrame = pThreadToWalk->GetTransitionFrameForStackTrace();
+    InternalInit(pThreadToWalk, pFrame, StackTraceStackWalkFlags);
     PrepareToYieldFrame();
 }
 
@@ -374,7 +369,7 @@ void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PAL_LIMITED_CO
 
     // This codepath is used by the hijack stackwalk and we can get arbitrary ControlPCs from there.  If this
     // context has a non-managed control PC, then we're done.
-    if (!m_pInstance->FindCodeManagerByAddress(dac_cast<PTR_VOID>(pCtx->GetIp())))
+    if (!m_pInstance->IsManaged(dac_cast<PTR_VOID>(pCtx->GetIp())))
         return;
 
     //
@@ -878,7 +873,7 @@ void StackFrameIterator::UnwindFuncletInvokeThunk()
 
     // We expect to be called by the runtime's C# EH implementation, and since this function's notion of how
     // to unwind through the stub is brittle relative to the stub itself, we want to check as soon as we can.
-    ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC) && "unwind from funclet invoke stub failed");
+    ASSERT(m_pInstance->IsManaged(m_ControlPC) && "unwind from funclet invoke stub failed");
 #endif // defined(USE_PORTABLE_HELPERS)
 }
 
@@ -1276,7 +1271,7 @@ void StackFrameIterator::UnwindThrowSiteThunk()
 
     // We expect the throw site to be in managed code, and since this function's notion of how to unwind
     // through the stub is brittle relative to the stub itself, we want to check as soon as we can.
-    ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC) && "unwind from throw site stub failed");
+    ASSERT(m_pInstance->IsManaged(m_ControlPC) && "unwind from throw site stub failed");
 #endif // defined(USE_PORTABLE_HELPERS)
 }
 
@@ -1314,7 +1309,7 @@ UnwindOutOfCurrentManagedFrame:
     uintptr_t DEBUG_preUnwindSP = m_RegDisplay.GetSP();
 #endif
 
-    PTR_VOID pPreviousTransitionFrame;
+    PInvokeTransitionFrame* pPreviousTransitionFrame;
     FAILFAST_OR_DAC_FAIL(GetCodeManager()->UnwindStackFrame(&m_methodInfo, &m_RegDisplay, &pPreviousTransitionFrame));
 
     bool doingFuncletUnwind = GetCodeManager()->IsFunclet(&m_methodInfo);
@@ -1337,8 +1332,8 @@ UnwindOutOfCurrentManagedFrame:
             // will unwind through the thunk and back to the nearest managed frame, and therefore may
             // see a conservative range reported by one of the thunks encountered during this "nested"
             // unwind.
-            InternalInit(m_pThread, GetPInvokeTransitionFrame(pPreviousTransitionFrame), GcStackWalkFlags);
-            ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC));
+            InternalInit(m_pThread, pPreviousTransitionFrame, GcStackWalkFlags);
+            ASSERT(m_pInstance->IsManaged(m_ControlPC));
         }
         m_dwFlags |= UnwoundReversePInvoke;
     }
@@ -1465,7 +1460,7 @@ UnwindOutOfCurrentManagedFrame:
         // from the iterator with the one and only exception being cases where a managed frame must
         // be skipped due to funclet collapsing.
 
-        ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC));
+        ASSERT(m_pInstance->IsManaged(m_ControlPC));
 
         if (collapsingTargetFrame != NULL)
         {
@@ -1574,7 +1569,7 @@ void StackFrameIterator::PrepareToYieldFrame()
     if (!IsValid())
         return;
 
-    ASSERT(m_pInstance->FindCodeManagerByAddress(m_ControlPC));
+    ASSERT(m_pInstance->IsManaged(m_ControlPC));
 
     if (m_dwFlags & ApplyReturnAddressAdjustment)
     {
@@ -1659,7 +1654,7 @@ void StackFrameIterator::CalculateCurrentMethodState()
     // Assume that the caller is likely to be in the same module
     if (m_pCodeManager == NULL || !m_pCodeManager->FindMethodInfo(m_ControlPC, &m_methodInfo))
     {
-        m_pCodeManager = dac_cast<PTR_ICodeManager>(m_pInstance->FindCodeManagerByAddress(m_ControlPC));
+        m_pCodeManager = dac_cast<PTR_ICodeManager>(m_pInstance->GetCodeManagerForAddress(m_ControlPC));
         FAILFAST_OR_DAC_FAIL(m_pCodeManager);
 
         FAILFAST_OR_DAC_FAIL(m_pCodeManager->FindMethodInfo(m_ControlPC, &m_methodInfo));
@@ -1717,7 +1712,7 @@ bool StackFrameIterator::IsValidReturnAddress(PTR_VOID pvAddress)
     if (category == InThrowSiteThunk)
         return true;
 
-    return (NULL != GetRuntimeInstance()->FindCodeManagerByAddress(pvAddress));
+    return GetRuntimeInstance()->IsManaged(pvAddress);
 }
 
 // Support for conservatively reporting GC references in a stack range. This is used when managed methods with
index a5c826f..1f460fa 100644 (file)
@@ -33,7 +33,7 @@ class StackFrameIterator
 
 public:
     StackFrameIterator() {}
-    StackFrameIterator(Thread * pThreadToWalk, PTR_VOID pInitialTransitionFrame);
+    StackFrameIterator(Thread * pThreadToWalk, PInvokeTransitionFrame* pInitialTransitionFrame);
     StackFrameIterator(Thread * pThreadToWalk, PTR_PAL_LIMITED_CONTEXT pCtx);
 
 
index 3e5203f..b57b863 100644 (file)
@@ -49,7 +49,6 @@ TypeManager::TypeManager(HANDLE osModule, ReadyToRunHeader * pHeader, void** pCl
     m_pThreadStaticsDataSection = (uint8_t*)GetModuleSection(ReadyToRunSectionType::ThreadStaticRegion, &length);
     m_pThreadStaticsGCInfo = (StaticGcDesc*)GetModuleSection(ReadyToRunSectionType::ThreadStaticGCDescRegion, &length);
     m_pTlsIndex = (uint32_t*)GetModuleSection(ReadyToRunSectionType::ThreadStaticIndex, &length);
-    m_pLoopHijackFlag = (uint32_t*)GetModuleSection(ReadyToRunSectionType::LoopHijackFlag, &length);
     m_pDispatchMapTable = (DispatchMap **)GetModuleSection(ReadyToRunSectionType::InterfaceDispatchTable, &length);
 }
 
index bd34a64..4dbce21 100644 (file)
@@ -20,7 +20,6 @@ class TypeManager
     uint32_t*                   m_pTlsIndex;  // Pointer to TLS index if this module uses thread statics
     void**                      m_pClasslibFunctions;
     uint32_t                    m_nClasslibFunctions;
-    uint32_t*                   m_pLoopHijackFlag;
 
     TypeManager(HANDLE osModule, ReadyToRunHeader * pHeader, void** pClasslibFunctions, uint32_t nClasslibFunctions);
 
@@ -31,7 +30,6 @@ public:
     HANDLE GetOsModuleHandle();
     void* GetClasslibFunction(ClasslibFunctionId functionId);
     uint32_t* GetPointerToTlsIndex() { return m_pTlsIndex; }
-    void SetLoopHijackFlag(uint32_t flag) { if (m_pLoopHijackFlag != nullptr) *m_pLoopHijackFlag = flag; }
 
 private:
 
index 79abdc3..ffb26f3 100644 (file)
@@ -46,7 +46,7 @@ PUSH_PROBE_FRAME macro threadReg, trashReg, extraStack, BITMASK
     movdqa          [rsp + 20h], xmm0
 
     ; link the frame into the Thread
-    mov             [threadReg + OFFSETOF__Thread__m_pHackPInvokeTunnel], trashReg
+    mov             [threadReg + OFFSETOF__Thread__m_pDeferredTransitionFrame], trashReg
 endm
 
 ;;
@@ -132,7 +132,7 @@ WaitForGCCompletion macro
         test        dword ptr [rbx + OFFSETOF__Thread__m_ThreadStateFlags], TSF_SuppressGcStress + TSF_DoNotTriggerGc
         jnz         @F
 
-        mov         rcx, [rbx + OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        mov         rcx, [rbx + OFFSETOF__Thread__m_pDeferredTransitionFrame]
         call        RhpWaitForGCNoAbort
 @@:
 
@@ -230,7 +230,7 @@ NESTED_ENTRY RhpGcProbe, _TEXT
         mov         rbx, rdx
         WaitForGCCompletion
 
-        mov         rax, [rbx + OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        mov         rax, [rbx + OFFSETOF__Thread__m_pDeferredTransitionFrame]
         test        dword ptr [rax + OFFSETOF__PInvokeTransitionFrame__m_Flags], PTFF_THREAD_ABORT
         jnz         Abort
         POP_PROBE_FRAME 0
@@ -687,7 +687,7 @@ DontSaveXmmAgain:
         mov         [rsp +  20h], rax       ; save return address into PInvokeTransitionFrame
 
         ; Early out if GC stress is currently suppressed. Do this after we have computed the real address to
-        ; return to but before we link the transition frame onto m_pHackPInvokeTunnel (because hitting this
+        ; return to but before we link the transition frame onto m_pDeferredTransitionFrame (because hitting this
         ; condition implies we're running restricted callouts during a GC itself and we could end up
         ; overwriting a co-op frame set by the code that caused the GC in the first place, e.g. a GC.Collect
         ; call).
@@ -696,7 +696,7 @@ DontSaveXmmAgain:
 
         ; link the frame into the Thread
         lea         rcx, [rsp + sizeof_OutgoingScratchSpace]    ; rcx <- PInvokeTransitionFrame*
-        mov         [rsi + OFFSETOF__Thread__m_pHackPInvokeTunnel], rcx
+        mov         [rsi + OFFSETOF__Thread__m_pDeferredTransitionFrame], rcx
 
         ;;
         ;; Unhijack this thread, if necessary.
index 82976b9..3e3f2c6 100644 (file)
@@ -122,7 +122,7 @@ __PPF_ThreadReg SETS "r2"
 
         ; Perform the rest of the PInvokeTransitionFrame initialization.
         INIT_PROBE_FRAME $__PPF_ThreadReg, $trashReg, $BITMASK, PROBE_FRAME_SIZE
-        str         sp, [$__PPF_ThreadReg, #OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        str         sp, [$__PPF_ThreadReg, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
     MEND
 
     ; Simple macro to use when PROLOG_PROBE_FRAME was used to set up and initialize the prolog and
@@ -200,7 +200,7 @@ __PPF_ThreadReg SETS "r2"
         tst         r2, #TSF_SuppressGcStress__OR__TSF_DoNotTriggerGC
         bne         %ft0
 
-        ldr         r2, [r4, #OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        ldr         r2, [r4, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
         bl          RhpWaitForGCNoAbort
 0
     MEND
@@ -505,7 +505,7 @@ DREG_SZ equ     (SIZEOF__PAL_LIMITED_CONTEXT - (OFFSETOF__PAL_LIMITED_CONTEXT__L
 
         ; TRASHES r1
         INIT_PROBE_FRAME r2, r1, #PROBE_SAVE_FLAGS_R0_IS_GCREF, (PROBE_FRAME_SIZE + 8)
-        str         sp, [r2, #OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        str         sp, [r2, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
     MEND
 
 ;;
index 59af51a..c794331 100644 (file)
@@ -175,7 +175,7 @@ __PPF_ThreadReg SETS "x2"
         ; Perform the rest of the PInvokeTransitionFrame initialization.
         INIT_PROBE_FRAME $__PPF_ThreadReg, $trashReg, $savedRegsMask, $gcFlags, PROBE_FRAME_SIZE
         mov         $trashReg, sp
-        str         $trashReg, [$__PPF_ThreadReg, #OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        str         $trashReg, [$__PPF_ThreadReg, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
     MEND
 
     ; Simple macro to use when PROLOG_PROBE_FRAME was used to set up and initialize the prolog and
@@ -312,7 +312,7 @@ EXTRA_SAVE_SIZE equ (32*16)
         tst         w2, #TSF_SuppressGcStress__OR__TSF_DoNotTriggerGC
         bne         %ft0
 
-        ldr         x9, [x4, #OFFSETOF__Thread__m_pHackPInvokeTunnel]
+        ldr         x9, [x4, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
         bl          RhpWaitForGCNoAbort
 0
     MEND
index df1baaa..f4f1322 100644 (file)
@@ -294,11 +294,11 @@ Object* GcAllocInternal(MethodTable *pEEType, uint32_t uFlags, uintptr_t numElem
 //  pTransitionFrame-  transition frame to make stack crawable
 // Returns a pointer to the object allocated or NULL on failure.
 
-COOP_PINVOKE_HELPER(void*, RhpGcAlloc, (MethodTable* pEEType, uint32_t uFlags, uintptr_t numElements, void* pTransitionFrame))
+COOP_PINVOKE_HELPER(void*, RhpGcAlloc, (MethodTable* pEEType, uint32_t uFlags, uintptr_t numElements, PInvokeTransitionFrame* pTransitionFrame))
 {
     Thread* pThread = ThreadStore::GetCurrentThread();
 
-    pThread->SetCurrentThreadPInvokeTunnelForGcAlloc(pTransitionFrame);
+    pThread->SetDeferredTransitionFrame(pTransitionFrame);
 
     return GcAllocInternal(pEEType, uFlags, numElements, pThread);
 }
index be64a06..3f7e7a7 100644 (file)
@@ -50,9 +50,6 @@ void GCToEEInterface::GcScanRoots(EnumGcRefCallbackFunc * fn,  int condemned, in
             continue;
 
 #if !defined (ISOLATED_HEAPS)
-        // @TODO: it is very bizarre that this IsThreadUsingAllocationContextHeap takes a copy of the
-        // allocation context instead of a reference or a pointer to it. This seems very wasteful given how
-        // large the alloc_context is.
         if (!GCHeapUtilities::GetGCHeap()->IsThreadUsingAllocationContextHeap(pThread->GetAllocContext(),
                                                                      sc->thread_number))
         {
@@ -102,9 +99,9 @@ void GCToEEInterface::GcEnumAllocContexts (enum_alloc_context_func* fn, void* pa
 void PromoteCarefully(PTR_PTR_Object obj, uint32_t flags, EnumGcRefCallbackFunc * fnGcEnumRef, EnumGcRefScanContext * pSc)
 {
     //
-    // Sanity check that the flags contain only these three values
+    // Sanity check that the flags contain only these values
     //
-    assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED|GC_CALL_CHECK_APP_DOMAIN)) == 0);
+    assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED)) == 0);
 
     //
     // Sanity check that GC_CALL_INTERIOR FLAG is set
@@ -122,9 +119,9 @@ void PromoteCarefully(PTR_PTR_Object obj, uint32_t flags, EnumGcRefCallbackFunc
 void GcEnumObject(PTR_PTR_Object ppObj, uint32_t flags, EnumGcRefCallbackFunc * fnGcEnumRef, EnumGcRefScanContext * pSc)
 {
     //
-    // Sanity check that the flags contain only these three values
+    // Sanity check that the flags contain only these values
     //
-    assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED|GC_CALL_CHECK_APP_DOMAIN)) == 0);
+    assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED)) == 0);
 
     // for interior pointers, we optimize the case in which
     //  it points into the current threads stack area
index cc350f6..c27c664 100644 (file)
@@ -237,7 +237,7 @@ ifdef FEATURE_GC_STRESS
 ;;  All other registers trashed
 ;;
 StressGC macro
-        mov         [ebx + OFFSETOF__Thread__m_pHackPInvokeTunnel], esp
+        mov         [ebx + OFFSETOF__Thread__m_pDeferredTransitionFrame], esp
         call        REDHAWKGCINTERFACE__STRESSGC
 endm
 
index a975e33..a16086d 100644 (file)
@@ -50,7 +50,7 @@ enum class ReadyToRunSectionType
     ThreadStaticOffsetRegion    = 208,
     ThreadStaticGCDescRegion    = 209,
     ThreadStaticIndex           = 210,
-    LoopHijackFlag              = 211,
+    // 211 is unused - it was used by LoopHijackFlag
     ImportAddressTables         = 212,
 
     // Sections 300 - 399 are reserved for RhFindBlob backwards compatibility
index b5c7394..1cedebd 100644 (file)
@@ -1,6 +1,8 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+#pragma once
+
 //
 // This header contains binder-generated data structures that the runtime consumes.
 //
@@ -433,29 +435,7 @@ enum PInvokeTransitionFrameFlags : uint64_t
     PTFF_THREAD_ABORT   = 0x0000001000000000,   // indicates that ThreadAbortException should be thrown when returning from the transition
 };
 
-// TODO: Consider moving the PInvokeTransitionFrameFlags definition to a separate file to simplify header dependencies
-#ifdef ICODEMANAGER_INCLUDED
-// Verify that we can use bitwise shifts to convert from GCRefKind to PInvokeTransitionFrameFlags and back
-C_ASSERT(PTFF_X0_IS_GCREF == ((uint64_t)GCRK_Object << 32));
-C_ASSERT(PTFF_X0_IS_BYREF == ((uint64_t)GCRK_Byref << 32));
-C_ASSERT(PTFF_X1_IS_GCREF == ((uint64_t)GCRK_Scalar_Obj << 32));
-C_ASSERT(PTFF_X1_IS_BYREF == ((uint64_t)GCRK_Scalar_Byref << 32));
-
-inline uint64_t ReturnKindToTransitionFrameFlags(GCRefKind returnKind)
-{
-    if (returnKind == GCRK_Scalar)
-        return 0;
 
-    return PTFF_SAVE_X0 | PTFF_SAVE_X1 | ((uint64_t)returnKind << 32);
-}
-
-inline GCRefKind TransitionFrameFlagsToReturnKind(uint64_t transFrameFlags)
-{
-    GCRefKind returnKind = (GCRefKind)((transFrameFlags & (PTFF_X0_IS_GCREF | PTFF_X0_IS_BYREF | PTFF_X1_IS_GCREF | PTFF_X1_IS_BYREF)) >> 32);
-    ASSERT((returnKind == GCRK_Scalar) || ((transFrameFlags & PTFF_SAVE_X0) && (transFrameFlags & PTFF_SAVE_X1)));
-    return returnKind;
-}
-#endif // ICODEMANAGER_INCLUDED
 #else // TARGET_ARM
 enum PInvokeTransitionFrameFlags
 {
@@ -645,3 +625,4 @@ struct ColdToHotMapping
     SubSectionDesc  subSection[/*subSectionCount*/1];
     //  UINT32   hotRVAofColdMethod[/*coldMethodCount*/];
 };
+
index 61f8818..da766cd 100644 (file)
@@ -132,7 +132,6 @@ void StressLog::Initialize(unsigned facilities,  unsigned level, unsigned maxByt
 /* create a new thread stress log buffer associated with pThread                 */
 
 ThreadStressLog* StressLog::CreateThreadStressLog(Thread * pThread) {
-
     if (theLog.facilitiesToLog == 0)
         return NULL;
 
@@ -145,12 +144,6 @@ ThreadStressLog* StressLog::CreateThreadStressLog(Thread * pThread) {
         return msgs;
     }
 
-    //if we are not allowed to allocate stress log, we should not even try to take the lock
-    if (pThread->IsInCantAllocStressLogRegion())
-    {
-        return NULL;
-    }
-
     // if it looks like we won't be allowed to allocate a new chunk, exit early
     if (VolatileLoad(&theLog.deadCount) == 0 && !AllowNewChunk (0))
     {
@@ -264,10 +257,6 @@ void StressLog::ThreadDetach(ThreadStressLog *msgs) {
 bool StressLog::AllowNewChunk (long numChunksInCurThread)
 {
     Thread* pCurrentThread = ThreadStore::RawGetCurrentThread();
-    if (pCurrentThread->IsInCantAllocStressLogRegion())
-    {
-        return FALSE;
-    }
 
     _ASSERTE (numChunksInCurThread <= VolatileLoad(&theLog.totalChunk));
     uint32_t perThreadLimit = theLog.MaxSizePerThread;
index f4e1b34..0db1d14 100644 (file)
@@ -44,15 +44,15 @@ extern "C" void _ReadWriteBarrier(void);
 #endif // _MSC_VER
 #endif //!DACCESS_COMPILE
 
-PTR_VOID Thread::GetTransitionFrame()
+PInvokeTransitionFrame* Thread::GetTransitionFrame()
 {
     if (ThreadStore::GetSuspendingThread() == this)
     {
-        // This thread is in cooperative mode, so we grab the transition frame
-        // from the 'tunnel' location, which will have the frame from the most
+        // This thread is in cooperative mode, so we grab the deferred frame
+        // which is the frame from the most
         // recent 'cooperative pinvoke' transition that brought us here.
-        ASSERT(m_pHackPInvokeTunnel != NULL);
-        return m_pHackPInvokeTunnel;
+        ASSERT(m_pDeferredTransitionFrame != NULL);
+        return m_pDeferredTransitionFrame;
     }
 
     ASSERT(m_pCachedTransitionFrame != NULL);
@@ -61,13 +61,13 @@ PTR_VOID Thread::GetTransitionFrame()
 
 #ifndef DACCESS_COMPILE
 
-PTR_VOID Thread::GetTransitionFrameForStackTrace()
+PInvokeTransitionFrame* Thread::GetTransitionFrameForStackTrace()
 {
     ASSERT_MSG(ThreadStore::GetSuspendingThread() == NULL, "Not allowed when suspended for GC.");
     ASSERT_MSG(this == ThreadStore::GetCurrentThread(), "Only supported for current thread.");
     ASSERT(Thread::IsCurrentThreadInCooperativeMode());
-    ASSERT(m_pHackPInvokeTunnel != NULL);
-    return m_pHackPInvokeTunnel;
+    ASSERT(m_pDeferredTransitionFrame != NULL);
+    return m_pDeferredTransitionFrame;
 }
 
 void Thread::WaitForSuspend()
@@ -76,7 +76,7 @@ void Thread::WaitForSuspend()
     GetThreadStore()->WaitForSuspendComplete();
 }
 
-void Thread::WaitForGC(void * pTransitionFrame)
+void Thread::WaitForGC(PInvokeTransitionFrame* pTransitionFrame)
 {
     ASSERT(!IsDoNotTriggerGcSet());
 
@@ -105,13 +105,17 @@ void Thread::WaitForGC(void * pTransitionFrame)
 //
 // Returns true if it sucessfully cached the transition frame (i.e. the thread was in unmanaged).
 // Returns false otherwise.
-//
+// 
+// WARNING: This method is called by suspension while one thread is interrupted
+//          in a random location, possibly holding random locks.
+//          It is unsafe to use blocking APIs or allocate in this method.
+//          Please ensure that all methods called by this one also have this warning.
 bool Thread::CacheTransitionFrameForSuspend()
 {
     if (m_pCachedTransitionFrame != NULL)
         return true;
 
-    PTR_VOID temp = m_pTransitionFrame;     // volatile read
+    PInvokeTransitionFrame* temp = m_pTransitionFrame;     // volatile read
     if (temp == NULL)
         return false;
 
@@ -121,32 +125,27 @@ bool Thread::CacheTransitionFrameForSuspend()
 
 void Thread::ResetCachedTransitionFrame()
 {
-    // @TODO: I don't understand this assert because ResumeAllThreads is clearly written
-    // to be reseting other threads' cached transition frames.
-
-    //ASSERT((ThreadStore::GetCurrentThreadIfAvailable() == this) ||
-    //       (m_pCachedTransitionFrame != NULL));
     m_pCachedTransitionFrame = NULL;
 }
 
 // This function simulates a PInvoke transition using a frame pointer from somewhere further up the stack that
-// was passed in via the m_pHackPInvokeTunnel field.  It is used to allow us to grandfather-in the set of GC
+// was passed in via the m_pDeferredTransitionFrame field.  It is used to allow us to grandfather-in the set of GC
 // code that runs in cooperative mode without having to rewrite it in managed code.  The result is that the
 // code that calls into this special mode must spill preserved registers as if it's going to PInvoke, but
-// record its transition frame pointer in m_pHackPInvokeTunnel and leave the thread in the cooperative
+// record its transition frame pointer in m_pDeferredTransitionFrame and leave the thread in the cooperative
 // mode.  Later on, when this function is called, we effect the state transition to 'unmanaged' using the
 // previously setup transition frame.
 void Thread::EnablePreemptiveMode()
 {
     ASSERT(ThreadStore::GetCurrentThread() == this);
 #if !defined(HOST_WASM)
-    ASSERT(m_pHackPInvokeTunnel != NULL);
+    ASSERT(m_pDeferredTransitionFrame != NULL);
 #endif
 
     Unhijack();
 
     // ORDERING -- this write must occur before checking the trap
-    m_pTransitionFrame = m_pHackPInvokeTunnel;
+    m_pTransitionFrame = m_pDeferredTransitionFrame;
 
     // We need to prevent compiler reordering between above write and below read.  Both the read and the write
     // are volatile, so it's possible that the particular semantic for volatile that MSVC provides is enough,
@@ -173,7 +172,7 @@ void Thread::DisablePreemptiveMode()
 
     if (ThreadStore::IsTrapThreadsRequested() && (this != ThreadStore::GetSuspendingThread()))
     {
-        WaitForGC(m_pHackPInvokeTunnel);
+        WaitForGC(m_pDeferredTransitionFrame);
     }
 }
 #endif // !DACCESS_COMPILE
@@ -435,10 +434,10 @@ bool Thread::GcScanRoots(GcScanRootsCallbackFunc * pfnEnumCallback, void * token
     //When debugging we might be trying to enumerate with or without a transition frame
     //on top of the stack. If there is one use it, otherwise the debugger provides a set of initial registers
     //to use.
-    PTR_VOID pTransitionFrame = GetTransitionFrame();
+    PInvokeTransitionFrame* pTransitionFrame = GetTransitionFrame();
     if(pTransitionFrame != NULL)
     {
-        StackFrameIterator  frameIterator(this, GetTransitionFrame());
+        StackFrameIterator  frameIterator(this, pTransitionFrame);
         GcScanRootsWorker(&GcScanRootsCallbackWrapper, &callbackDataWrapper, frameIterator);
     }
     else
@@ -485,7 +484,7 @@ void Thread::GcScanRootsWorker(void * pfnEnumCallback, void * pvCallbackData, St
             PTR_VOID pLowerBound = dac_cast<PTR_VOID>(frameIterator.GetRegisterSet()->GetSP());
 
             // Transition frame may contain callee saved registers that need to be reported as well
-            PTR_VOID pTransitionFrame = GetTransitionFrame();
+            PInvokeTransitionFrame* pTransitionFrame = GetTransitionFrame();
             ASSERT(pTransitionFrame != NULL);
             if (pTransitionFrame < pLowerBound)
                 pLowerBound = pTransitionFrame;
@@ -638,42 +637,34 @@ bool Thread::Hijack()
     // requires THREAD_SUSPEND_RESUME / THREAD_GET_CONTEXT / THREAD_SET_CONTEXT permissions
 
     Thread* pCurrentThread = ThreadStore::GetCurrentThread();
-    pCurrentThread->EnterCantAllocRegion();
     uint32_t result = PalHijack(m_hPalThread, HijackCallback, this);
-    pCurrentThread->LeaveCantAllocRegion();
     return result == 0;
-
 }
 
 UInt32_BOOL Thread::HijackCallback(HANDLE /*hThread*/, PAL_LIMITED_CONTEXT* pThreadContext, void* pCallbackContext)
 {
     Thread* pThread = (Thread*) pCallbackContext;
 
-    //
-    // WARNING: The hijack operation will take a read lock on the RuntimeInstance's module list.
-    // (This is done to find a Module based on an IP.)  Therefore, if the thread we've just
-    // suspended owns the write lock on the module list, we'll deadlock with it when we try to
-    // take the read lock below.  So we must attempt a non-blocking acquire of the read lock
-    // early and fail the hijack if we can't get it.  This will cause us to simply retry later.
-    //
-    if (GetRuntimeInstance()->m_ModuleListLock.DangerousTryPulseReadLock())
+    // we have a thread stopped, and we do not know where exactly.
+    // it could be in a system call or in our own runtime holding locks
+    // current thread should not block or allocate while we determine whether the location is in managed code.
+    if (pThread->CacheTransitionFrameForSuspend())
     {
-        if (pThread->CacheTransitionFrameForSuspend())
-        {
-            // IMPORTANT: GetThreadContext should not be trusted arbitrarily.  We are careful here to recheck
-            // the thread's state flag that indicates whether or not it has made it to unmanaged code.  If
-            // it has reached unmanaged code (even our own wait helper routines), then we cannot trust the
-            // context returned by it.  This is due to various races that occur updating the reported context
-            // during syscalls.
-            return TRUE;
-        }
-        else
-        {
-            return pThread->InternalHijack(pThreadContext, NormalHijackTargets) ? TRUE : FALSE;
-        }
+        // This thread has already made it to preemptive (posted a transition frame)
+        // we do not need to hijack it
+        return true;
+    }
+
+    if (!GetRuntimeInstance()->IsManaged((PTR_VOID)pThreadContext->IP))
+    {
+        // Running in cooperative mode, but not managed.
+        // We cannot continue.
+        return false;
     }
 
-    return FALSE;
+    // TODO: attempt to redirect 
+
+    return pThread->InternalHijack(pThreadContext, NormalHijackTargets);
 }
 
 #ifdef FEATURE_GC_STRESS
@@ -882,7 +873,7 @@ void * Thread::GetUnhijackedReturnAddress(void ** ppvReturnAddressLocation)
     else
         pvReturnAddress = *ppvReturnAddressLocation;
 
-    ASSERT(NULL != GetRuntimeInstance()->FindCodeManagerByAddress(pvReturnAddress));
+    ASSERT(GetRuntimeInstance()->IsManaged(pvReturnAddress));
     return pvReturnAddress;
 }
 
index 10fb95a..2c50024 100644 (file)
@@ -27,7 +27,7 @@ class Thread;
 # endif
 #endif // HOST_64BIT
 
-#define TOP_OF_STACK_MARKER ((PTR_VOID)(uintptr_t)(intptr_t)-1)
+#define TOP_OF_STACK_MARKER ((PInvokeTransitionFrame*)(ptrdiff_t)-1)
 
 #define DYNAMIC_TYPE_TLS_OFFSET_FLAG 0x80000000
 
@@ -55,23 +55,24 @@ struct ExInfo
     PTR_PAL_LIMITED_CONTEXT m_pExContext;
     PTR_Object              m_exception;  // actual object reference, specially reported by GcScanRootsWorker
     ExKind                  m_kind;
-    uint8_t                   m_passNumber;
-    uint32_t                  m_idxCurClause;
+    uint8_t                 m_passNumber;
+    uint32_t                m_idxCurClause;
     StackFrameIterator      m_frameIter;
     volatile void*          m_notifyDebuggerSP;
 };
 
 struct ThreadBuffer
 {
-    uint8_t                   m_rgbAllocContextBuffer[SIZEOF_ALLOC_CONTEXT];
-    uint32_t volatile         m_ThreadStateFlags;                     // see Thread::ThreadStateFlags enum
+    uint8_t                 m_rgbAllocContextBuffer[SIZEOF_ALLOC_CONTEXT];
+    uint32_t volatile       m_ThreadStateFlags;                     // see Thread::ThreadStateFlags enum
 #if DACCESS_COMPILE
-    PTR_VOID                m_pTransitionFrame;
+    volatile
+    PInvokeTransitionFrame* m_pTransitionFrame;
 #else
-    PTR_VOID volatile       m_pTransitionFrame;
+    PInvokeTransitionFrame* m_pTransitionFrame;
 #endif
-    PTR_VOID                m_pHackPInvokeTunnel;                   // see Thread::EnablePreemptiveMode
-    PTR_VOID                m_pCachedTransitionFrame;
+    PInvokeTransitionFrame* m_pDeferredTransitionFrame;             // see Thread::EnablePreemptiveMode
+    PInvokeTransitionFrame* m_pCachedTransitionFrame;
     PTR_Thread              m_pNext;                                // used by ThreadStore's SList<Thread>
     HANDLE                  m_hPalThread;                           // WARNING: this may legitimately be INVALID_HANDLE_VALUE
     void **                 m_ppvHijackedReturnAddressLocation;
@@ -86,12 +87,11 @@ struct ThreadBuffer
     PTR_VOID                m_pStackLow;
     PTR_VOID                m_pStackHigh;
     PTR_UInt8               m_pTEB;                                 // Pointer to OS TEB structure for this thread
-    uint64_t                  m_uPalThreadIdForLogging;               // @TODO: likely debug-only
+    uint64_t                m_uPalThreadIdForLogging;               // @TODO: likely debug-only
     EEThreadId              m_threadId;
     PTR_VOID                m_pThreadStressLog;                     // pointer to head of thread's StressLogChunks
-    uint32_t                m_cantAlloc;
 #ifdef FEATURE_GC_STRESS
-    uint32_t                  m_uRand;                                // current per-thread random number
+    uint32_t                m_uRand;                                // current per-thread random number
 #endif // FEATURE_GC_STRESS
 
     // Thread Statics Storage for dynamic types
@@ -102,7 +102,7 @@ struct ThreadBuffer
 
 struct ReversePInvokeFrame
 {
-    void*   m_savedPInvokeTransitionFrame;
+    PInvokeTransitionFrame*   m_savedPInvokeTransitionFrame;
     Thread* m_savedThread;
 };
 
@@ -151,7 +151,7 @@ private:
     //
     // SyncState members
     //
-    PTR_VOID    GetTransitionFrame();
+    PInvokeTransitionFrame* GetTransitionFrame();
 
     void GcScanRootsWorker(void * pfnEnumCallback, void * pvCallbackData, StackFrameIterator & sfIter);
 
@@ -210,9 +210,6 @@ public:
 #ifndef DACCESS_COMPILE
     void                SetThreadStressLog(void * ptsl);
 #endif // DACCESS_COMPILE
-    void                EnterCantAllocRegion();
-    void                LeaveCantAllocRegion();
-    bool                IsInCantAllocStressLogRegion();
 #ifdef FEATURE_GC_STRESS
     void                SetRandomSeed(uint32_t seed);
     uint32_t              NextRand();
@@ -222,7 +219,7 @@ public:
 
     bool                IsCurrentThreadInCooperativeMode();
 
-    PTR_VOID            GetTransitionFrameForStackTrace();
+    PInvokeTransitionFrame* GetTransitionFrameForStackTrace();
     void *              GetCurrentThreadPInvokeReturnAddress();
 
     static bool         IsHijackTarget(void * address);
@@ -233,13 +230,13 @@ public:
     void                EnablePreemptiveMode();
     void                DisablePreemptiveMode();
 
-    // Set the m_pHackPInvokeTunnel field for GC allocation helpers that setup transition frame
+    // Set the m_pDeferredTransitionFrame field for GC allocation helpers that setup transition frame
     // in assembly code. Do not use anywhere else.
-    void                SetCurrentThreadPInvokeTunnelForGcAlloc(void * pTransitionFrame);
+    void                SetDeferredTransitionFrame(PInvokeTransitionFrame* pTransitionFrame);
 
-    // Setup the m_pHackPInvokeTunnel field for GC helpers entered via regular PInvoke.
+    // Setup the m_pDeferredTransitionFrame field for GC helpers entered via regular PInvoke.
     // Do not use anywhere else.
-    void                SetupHackPInvokeTunnel();
+    void                DeferTransitionFrame();
 
     //
     // GC support APIs - do not use except from GC itself
@@ -252,7 +249,7 @@ public:
     // Managed/unmanaged interop transitions support APIs
     //
     void WaitForSuspend();
-    void WaitForGC(void * pTransitionFrame);
+    void WaitForGC(PInvokeTransitionFrame* pTransitionFrame);
 
     void ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame);
 
index c8c1311..9c5ebe8 100644 (file)
@@ -2,18 +2,18 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 #ifndef DACCESS_COMPILE
-inline void Thread::SetCurrentThreadPInvokeTunnelForGcAlloc(void * pTransitionFrame)
+inline void Thread::SetDeferredTransitionFrame(PInvokeTransitionFrame* pTransitionFrame)
 {
     ASSERT(ThreadStore::GetCurrentThread() == this);
     ASSERT(Thread::IsCurrentThreadInCooperativeMode());
-    m_pHackPInvokeTunnel = pTransitionFrame;
+    m_pDeferredTransitionFrame = pTransitionFrame;
 }
 
-inline void Thread::SetupHackPInvokeTunnel()
+inline void Thread::DeferTransitionFrame()
 {
     ASSERT(ThreadStore::GetCurrentThread() == this);
     ASSERT(!Thread::IsCurrentThreadInCooperativeMode());
-    m_pHackPInvokeTunnel = m_pTransitionFrame;
+    m_pDeferredTransitionFrame = m_pTransitionFrame;
 }
 #endif // DACCESS_COMPILE
 
@@ -41,18 +41,3 @@ inline PTR_VOID Thread::GetThreadStressLog() const
 {
     return m_pThreadStressLog;
 }
-
-inline void Thread::EnterCantAllocRegion()
-{
-    m_cantAlloc++;
-}
-
-inline void Thread::LeaveCantAllocRegion()
-{
-    m_cantAlloc--;
-}
-
-inline bool Thread::IsInCantAllocStressLogRegion()
-{
-    return m_cantAlloc != 0;
-}
index 36bf43c..bd7e7e7 100644 (file)
@@ -213,9 +213,6 @@ void ThreadStore::SuspendAllThreads(bool waitForGCEvent)
     // set the global trap for pinvoke leave and return
     RhpTrapThreads |= (uint32_t)TrapThreadsFlags::TrapThreads;
 
-    // Set each module's loop hijack flag
-    GetRuntimeInstance()->SetLoopHijackFlags(RhpTrapThreads);
-
     // Our lock-free algorithm depends on flushing write buffers of all processors running RH code.  The
     // reason for this is that we essentially implement Dekker's algorithm, which requires write ordering.
     PalFlushProcessWriteBuffers();
@@ -232,8 +229,7 @@ void ThreadStore::SuspendAllThreads(bool waitForGCEvent)
 
             if (!pTargetThread->CacheTransitionFrameForSuspend())
             {
-                // We drive all threads to preemptive mode by hijacking them with both a
-                // return-address hijack and loop hijacks.
+                // We drive all threads to preemptive mode by hijacking them with return-address hijack.
                 keepWaiting = true;
                 pTargetThread->Hijack();
             }
@@ -278,9 +274,6 @@ void ThreadStore::ResumeAllThreads(bool waitForGCEvent)
 
     RhpTrapThreads &= ~(uint32_t)TrapThreadsFlags::TrapThreads;
 
-    // Reset module's hijackLoops flag
-    GetRuntimeInstance()->SetLoopHijackFlags(0);
-
     RhpSuspendingThread = NULL;
     if (waitForGCEvent)
     {
@@ -380,7 +373,7 @@ DECLSPEC_THREAD ThreadBuffer tls_CurrentThread =
     { 0 },                              // m_rgbAllocContextBuffer
     Thread::TSF_Unknown,                // m_ThreadStateFlags
     TOP_OF_STACK_MARKER,                // m_pTransitionFrame
-    TOP_OF_STACK_MARKER,                // m_pHackPInvokeTunnel
+    TOP_OF_STACK_MARKER,                // m_pDeferredTransitionFrame
     0,                                  // m_pCachedTransitionFrame
     0,                                  // m_pNext
     INVALID_HANDLE_VALUE,               // m_hPalThread
index 88a850c..6ccc249 100644 (file)
@@ -234,7 +234,7 @@ uintptr_t UnixNativeCodeManager::GetConservativeUpperBoundForOutgoingArgs(Method
 
 bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo *    pMethodInfo,
                                              REGDISPLAY *    pRegisterSet,                 // in/out
-                                             PTR_VOID *      ppPreviousTransitionFrame)    // out
+                                             PInvokeTransitionFrame**      ppPreviousTransitionFrame)    // out
 {
     UnixNativeMethodInfo * pNativeMethodInfo = (UnixNativeMethodInfo *)pMethodInfo;
 
@@ -267,7 +267,8 @@ bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo *    pMethodInfo,
         {
             basePointer = dac_cast<TADDR>(pRegisterSet->GetFP());
         }
-        *ppPreviousTransitionFrame = *(void**)(basePointer + slot);
+
+        *ppPreviousTransitionFrame = *(PInvokeTransitionFrame**)(basePointer + slot);
         return true;
     }
 
@@ -444,8 +445,7 @@ PTR_VOID UnixNativeCodeManager::GetAssociatedData(PTR_VOID ControlPC)
     return dac_cast<PTR_VOID>(p + *dac_cast<PTR_Int32>(p));
 }
 
-extern "C" bool RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
-extern "C" void UnregisterCodeManager(ICodeManager * pCodeManager);
+extern "C" void RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
 extern "C" bool RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange);
 
 extern "C"
@@ -461,12 +461,10 @@ bool RhRegisterOSModule(void * pModule,
     if (pUnixNativeCodeManager == nullptr)
         return false;
 
-    if (!RegisterCodeManager(pUnixNativeCodeManager, pvManagedCodeStartRange, cbManagedCodeRange))
-        return false;
+    RegisterCodeManager(pUnixNativeCodeManager, pvManagedCodeStartRange, cbManagedCodeRange);
 
     if (!RegisterUnboxingStubs(pvUnboxingStubsStartRange, cbUnboxingStubsRange))
     {
-        UnregisterCodeManager(pUnixNativeCodeManager);
         return false;
     }
 
index 8603a2b..6a4dc63 100644 (file)
@@ -41,7 +41,7 @@ public:
 
     bool UnwindStackFrame(MethodInfo *    pMethodInfo,
                           REGDISPLAY *    pRegisterSet,                 // in/out
-                          PTR_VOID *      ppPreviousTransitionFrame);   // out
+                          PInvokeTransitionFrame**      ppPreviousTransitionFrame);   // out
 
     uintptr_t GetConservativeUpperBoundForOutgoingArgs(MethodInfo *   pMethodInfo,
                                                         REGDISPLAY *   pRegisterSet);
index 290a308..c2fdecb 100644 (file)
@@ -490,7 +490,7 @@ uintptr_t CoffNativeCodeManager::GetConservativeUpperBoundForOutgoingArgs(Method
 
 bool CoffNativeCodeManager::UnwindStackFrame(MethodInfo *    pMethodInfo,
                                       REGDISPLAY *    pRegisterSet,                 // in/out
-                                      PTR_VOID *      ppPreviousTransitionFrame)    // out
+                                      PInvokeTransitionFrame**      ppPreviousTransitionFrame)    // out
 {
     CoffNativeMethodInfo * pNativeMethodInfo = (CoffNativeMethodInfo *)pMethodInfo;
 
@@ -526,7 +526,8 @@ bool CoffNativeCodeManager::UnwindStackFrame(MethodInfo *    pMethodInfo,
         {
             basePointer = dac_cast<TADDR>(pRegisterSet->GetFP());
         }
-        *ppPreviousTransitionFrame = *(void**)(basePointer + slot);
+
+        *ppPreviousTransitionFrame = *(PInvokeTransitionFrame**)(basePointer + slot);
         return true;
     }
 
@@ -870,8 +871,7 @@ PTR_VOID CoffNativeCodeManager::GetAssociatedData(PTR_VOID ControlPC)
     return dac_cast<PTR_VOID>(m_moduleBase + dataRVA);
 }
 
-extern "C" bool __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
-extern "C" void __stdcall UnregisterCodeManager(ICodeManager * pCodeManager);
+extern "C" void __stdcall RegisterCodeManager(ICodeManager * pCodeManager, PTR_VOID pvStartRange, uint32_t cbRange);
 extern "C" bool __stdcall RegisterUnboxingStubs(PTR_VOID pvStartRange, uint32_t cbRange);
 
 extern "C"
@@ -894,12 +894,10 @@ bool RhRegisterOSModule(void * pModule,
     if (pCoffNativeCodeManager == nullptr)
         return false;
 
-    if (!RegisterCodeManager(pCoffNativeCodeManager, pvManagedCodeStartRange, cbManagedCodeRange))
-        return false;
+    RegisterCodeManager(pCoffNativeCodeManager, pvManagedCodeStartRange, cbManagedCodeRange);
 
     if (!RegisterUnboxingStubs(pvUnboxingStubsStartRange, cbUnboxingStubsRange))
     {
-        UnregisterCodeManager(pCoffNativeCodeManager);
         return false;
     }
 
index 1bebb4d..eb2b03f 100644 (file)
@@ -77,7 +77,7 @@ public:
 
     bool UnwindStackFrame(MethodInfo *    pMethodInfo,
                           REGDISPLAY *    pRegisterSet,                 // in/out
-                          PTR_VOID *      ppPreviousTransitionFrame);   // out
+                          PInvokeTransitionFrame**      ppPreviousTransitionFrame);   // out
 
     uintptr_t GetConservativeUpperBoundForOutgoingArgs(MethodInfo *   pMethodInfo,
                                                         REGDISPLAY *   pRegisterSet);
index 82d6fa4..9dfa230 100644 (file)
@@ -2,10 +2,11 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Diagnostics;
+using System.Runtime.ConstrainedExecution;
 
 namespace System.Runtime.InteropServices
 {
-    public abstract partial class SafeHandle
+    public abstract partial class SafeHandle : CriticalFinalizerObject, IDisposable
     {
         // The handle cannot be closed until we are sure that no other objects might
         // be using it.  In the case of finalization, there may be other objects in
@@ -24,11 +25,12 @@ namespace System.Runtime.InteropServices
         // finalization cycle, but should be released in the next.
         //
         // This has the effect of delaying cleanup for much longer than would have
-        // happened on the CLR.  This also means that we may not close some handles
+        // happened on the CLR, which is an observable behavior change.
+        // This also means that we may not close some handles
         // at shutdown, since there may not be another finalization cycle to run
         // the delayed finalizer.  If either of these end up being a problem, we should
-        // consider adding more control over finalization order to MRT (or, better,
-        // turning over control of finalization ordering to System.Private.CoreLib).
+        // consider implementing MethodTable::HasCriticalFinalizer
+        // Same applies to `CriticalHandle`
 
         private sealed class DelayedFinalizer
         {
index 3a84d06..30d8af4 100644 (file)
@@ -82,7 +82,7 @@ namespace Internal.Runtime
         ThreadStaticOffsetRegion = 208,
         ThreadStaticGCDescRegion = 209,
         ThreadStaticIndex = 210,
-        LoopHijackFlag = 211,
+        // 211 is unused - it was used by LoopHijackFlag
         ImportAddressTables = 212,
         ModuleInitializerList = 213,