From 7c3f305960bb80cf32feed9e2f31f6b659ff073c Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 6 Oct 2026 23:18:00 -0700 Subject: [PATCH 1/2] Allocate PreallocatedSentinelObject on frozen heap One less pinned object and handle on regular heap --- src/coreclr/vm/appdomain.cpp | 18 ++++++++++++------ src/coreclr/vm/vars.cpp | 4 ++-- src/coreclr/vm/vars.hpp | 4 +--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 2756ed858e9fe5..7639aeecf705c2 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -174,8 +174,8 @@ OBJECTREF *PinnedHeapHandleBucket::TryAllocateEmbeddedFreeHandle() } CONTRACTL_END; - OBJECTREF pPreallocatedSentinelObject = ObjectFromHandle(g_pPreallocatedSentinelObject); - _ASSERTE(pPreallocatedSentinelObject != NULL); + OBJECTREF pPreallocatedSentinelObject = g_pPreallocatedSentinelObject; + _ASSERTE(pPreallocatedSentinelObject != NULL); for (int i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++) { @@ -405,8 +405,8 @@ void PinnedHeapHandleTable::ReleaseHandlesLocked(OBJECTREF *pObjRef, DWORD nRele _ASSERTE(m_Crst.OwnedByCurrentThread()); #endif - OBJECTREF pPreallocatedSentinelObject = ObjectFromHandle(g_pPreallocatedSentinelObject); - _ASSERTE(pPreallocatedSentinelObject != NULL); + OBJECTREF pPreallocatedSentinelObject = g_pPreallocatedSentinelObject; + _ASSERTE(pPreallocatedSentinelObject != NULL); // Add the released handles to the list of available handles. @@ -807,8 +807,14 @@ void SystemDomain::PreallocateSpecialObjects() _ASSERTE(g_pPreallocatedSentinelObject == NULL); - OBJECTREF pPreallocatedSentinelObject = AllocateObject(g_pObjectClass); - g_pPreallocatedSentinelObject = AppDomain::GetCurrentDomain()->CreatePinningHandle( pPreallocatedSentinelObject ); + g_pPreallocatedSentinelObject = TryAllocateFrozenObject(g_pObjectClass); + if (g_pPreallocatedSentinelObject == NULL) + { + OBJECTREF pPreallocatedSentinelObject = AllocateObject(g_pObjectClass); + // Keep the fallback object alive and immovable for the lifetime of the runtime. + OBJECTHANDLE handle = AppDomain::GetCurrentDomain()->CreatePinningHandle(pPreallocatedSentinelObject); + g_pPreallocatedSentinelObject = ObjectFromHandle(handle); + } } void SystemDomain::CreatePreallocatedExceptions() diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index ae813d80f56c72..4023b652daa384 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -124,11 +124,11 @@ GVAL_IMPL_INIT(PTR_WSTR, g_EntryAssemblyPath, NULL); #ifndef DACCESS_COMPILE -// @TODO - PROMOTE. OBJECTHANDLE g_pPreallocatedOutOfMemoryException; OBJECTHANDLE g_pPreallocatedStackOverflowException; OBJECTHANDLE g_pPreallocatedExecutionEngineException; -OBJECTHANDLE g_pPreallocatedSentinelObject; + +OBJECTREF g_pPreallocatedSentinelObject; // // diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 49334c9953d73e..2d3560af03b931 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -396,14 +396,12 @@ GVAL_DECL(PTR_WSTR, g_EntryAssemblyPath); // Global System Information extern SYSTEM_INFO g_SystemInfo; -// @TODO - PROMOTE. -// @TODO - I'd like to make these private members of CLRException some day. EXTERN OBJECTHANDLE g_pPreallocatedOutOfMemoryException; EXTERN OBJECTHANDLE g_pPreallocatedStackOverflowException; EXTERN OBJECTHANDLE g_pPreallocatedExecutionEngineException; // we use this as a dummy object to indicate free space in the handle tables -- this object is never visible to the world -EXTERN OBJECTHANDLE g_pPreallocatedSentinelObject; +EXTERN OBJECTREF g_pPreallocatedSentinelObject; EXTERN MethodTable* g_pCastHelpers; From f4f7e01423b1d9cec2c98d6c10cdcc0ed51f1380 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 7 Oct 2026 09:34:07 -0700 Subject: [PATCH 2/2] Apply suggestion from @jkotas --- src/coreclr/vm/vars.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index 4023b652daa384..3a1f1c766300d4 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -128,7 +128,7 @@ OBJECTHANDLE g_pPreallocatedOutOfMemoryException; OBJECTHANDLE g_pPreallocatedStackOverflowException; OBJECTHANDLE g_pPreallocatedExecutionEngineException; -OBJECTREF g_pPreallocatedSentinelObject; +OBJECTREF g_pPreallocatedSentinelObject = NULL; // //