From 3ab61c27d331b0ea7f617dbebb0f2965f20f5edb Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Tue, 24 Sep 2024 15:39:34 -0700 Subject: [PATCH] Remove some implicit Helper Method Frames (HMF) (#107648) * Remove some implicit Helper Method Frames (HMF) Remove FCThrow in locations where explicit HMF have been removed. Convert GC.GetGeneration() RuntimeHelpers.EnsureSufficientExecutionStack() RuntimeHelpers.AllocTailCallArgBuffer() Thread.IsBackground getter Thread.IsThreadPoolThread property --------- Co-authored-by: Jan Kotas --- .../src/System/GC.CoreCLR.cs | 10 +- .../RuntimeHelpers.CoreCLR.cs | 25 +++- .../src/System/Threading/Thread.CoreCLR.cs | 53 ++++++-- src/coreclr/vm/comsynchronizable.cpp | 122 +++++------------- src/coreclr/vm/comsynchronizable.h | 33 +---- src/coreclr/vm/comutilnative.cpp | 10 +- src/coreclr/vm/comutilnative.h | 2 +- src/coreclr/vm/corelib.h | 1 + src/coreclr/vm/ecalllist.h | 8 +- src/coreclr/vm/fcall.h | 23 ---- src/coreclr/vm/object.h | 2 + src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/reflectioninvocation.cpp | 30 +---- src/coreclr/vm/reflectioninvocation.h | 1 - src/coreclr/vm/tailcallhelp.cpp | 18 +-- src/coreclr/vm/tailcallhelp.h | 2 +- src/coreclr/vm/threads.cpp | 4 +- src/coreclr/vm/threads.h | 2 +- .../RegisteredWaitHandle.Portable.cs | 2 +- 19 files changed, 130 insertions(+), 219 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs index f8246642b9e61..dd7cd4c630944 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs @@ -155,12 +155,16 @@ public static void RemoveMemoryPressure(long bytesAllocated) _RemoveMemoryPressure((ulong)bytesAllocated); } - // Returns the generation that obj is currently in. // - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern int GetGeneration(object obj); + public static int GetGeneration(object obj) + { + ArgumentNullException.ThrowIfNull(obj); + return GetGenerationInternal(obj); + } + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern int GetGenerationInternal(object obj); // Forces a collection of all generations from 0 through Generation. // diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 77311a0242172..1b1f550ae53e1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -301,13 +301,18 @@ public static int OffsetToStringData // This method ensures that there is sufficient stack to execute the average Framework function. // If there is not enough stack, then it throws System.InsufficientExecutionStackException. - // Note: this method is not part of the CER support, and is not to be confused with ProbeForSufficientStack. - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void EnsureSufficientExecutionStack(); + // Note: this method is not to be confused with ProbeForSufficientStack. + public static void EnsureSufficientExecutionStack() + { + if (!TryEnsureSufficientExecutionStack()) + { + throw new InsufficientExecutionStackException(); + } + } // This method ensures that there is sufficient stack to execute the average Framework function. // If there is not enough stack, then it return false. - // Note: this method is not part of the CER support, and is not to be confused with ProbeForSufficientStack. + // Note: this method is not to be confused with ProbeForSufficientStack. [MethodImpl(MethodImplOptions.InternalCall)] public static extern bool TryEnsureSufficientExecutionStack(); @@ -469,7 +474,17 @@ public static IntPtr AllocateTypeAssociatedMemory(Type type, int size) private static partial IntPtr AllocateTypeAssociatedMemory(QCallTypeHandle type, uint size); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern IntPtr AllocTailCallArgBuffer(int size, IntPtr gcDesc); + private static extern IntPtr AllocTailCallArgBufferWorker(int size, IntPtr gcDesc); + + private static IntPtr AllocTailCallArgBuffer(int size, IntPtr gcDesc) + { + IntPtr buffer = AllocTailCallArgBufferWorker(size, gcDesc); + if (buffer == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + return buffer; + } [MethodImpl(MethodImplOptions.InternalCall)] private static extern unsafe TailCallTls* GetTailCallInfo(IntPtr retAddrSlot, IntPtr* retAddr); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs index 9a75255b8e442..7843c86f1ba81 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @@ -60,6 +60,7 @@ public sealed partial class Thread // Set in unmanaged and read in managed code. private bool _isDead; + private bool _isThreadPool; private Thread() { } @@ -89,13 +90,13 @@ private unsafe void StartCore() { fixed (char* pThreadName = _name) { - StartInternal(GetNativeHandle(), _startHelper?._maxStackSize ?? 0, _priority, pThreadName); + StartInternal(GetNativeHandle(), _startHelper?._maxStackSize ?? 0, _priority, _isThreadPool ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, pThreadName); } } } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_Start")] - private static unsafe partial void StartInternal(ThreadHandle t, int stackSize, int priority, char* pThreadName); + private static unsafe partial void StartInternal(ThreadHandle t, int stackSize, int priority, Interop.BOOL isThreadPool, char* pThreadName); // Called from the runtime private void StartCallback() @@ -194,9 +195,24 @@ partial void ThreadNameChanged(string? value) /// public bool IsBackground { - get => GetIsBackground(); + get + { + if (_isDead) + { + throw new ThreadStateException(SR.ThreadState_Dead_State); + } + + Interop.BOOL res = GetIsBackground(GetNativeHandle()); + GC.KeepAlive(this); + return res != Interop.BOOL.FALSE; + } set { + if (_isDead) + { + throw new ThreadStateException(SR.ThreadState_Dead_State); + } + SetIsBackground(GetNativeHandle(), value ? Interop.BOOL.TRUE : Interop.BOOL.FALSE); GC.KeepAlive(this); if (!value) @@ -206,19 +222,36 @@ public bool IsBackground } } - [MethodImpl(MethodImplOptions.InternalCall)] - private extern bool GetIsBackground(); + [SuppressGCTransition] + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetIsBackground")] + private static partial Interop.BOOL GetIsBackground(ThreadHandle t); [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetIsBackground")] private static partial void SetIsBackground(ThreadHandle t, Interop.BOOL value); /// Returns true if the thread is a threadpool thread. - public extern bool IsThreadPoolThread + public bool IsThreadPoolThread { - [MethodImpl(MethodImplOptions.InternalCall)] - get; - [MethodImpl(MethodImplOptions.InternalCall)] - internal set; + get + { + if (_isDead) + { + throw new ThreadStateException(SR.ThreadState_Dead_State); + } + + return _isThreadPool; + } + internal set + { + Debug.Assert(value); + Debug.Assert(!_isDead); + Debug.Assert(((ThreadState & ThreadState.Unstarted) != 0) +#if TARGET_WINDOWS + || ThreadPool.UseWindowsThreadPool +#endif + ); + _isThreadPool = value; + } } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetPriority")] diff --git a/src/coreclr/vm/comsynchronizable.cpp b/src/coreclr/vm/comsynchronizable.cpp index e87f93a04095a..a5236718ad869 100644 --- a/src/coreclr/vm/comsynchronizable.cpp +++ b/src/coreclr/vm/comsynchronizable.cpp @@ -119,20 +119,17 @@ INT32 MapFromNTPriority(INT32 NTPriority) return ours; } - -void ThreadNative::KickOffThread_Worker(LPVOID ptr) +static void KickOffThread_Worker(LPVOID ptr) { CONTRACTL { GC_TRIGGERS; THROWS; MODE_COOPERATIVE; + PRECONDITION(ptr == NULL); } CONTRACTL_END; - KickOffThread_Args *pKickOffArgs = (KickOffThread_Args *) ptr; - pKickOffArgs->retVal = 0; - PREPARE_NONVIRTUAL_CALLSITE(METHOD__THREAD__START_CALLBACK); DECLARE_ARGHOLDER_ARRAY(args, 1); args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(GetThread()->GetExposedObjectRaw()); @@ -167,7 +164,7 @@ static void PulseAllHelper(Thread* pThread) } // When an exposed thread is started by Win32, this is where it starts. -ULONG WINAPI ThreadNative::KickOffThread(void* pass) +static ULONG WINAPI KickOffThread(void* pass) { CONTRACTL @@ -204,11 +201,7 @@ ULONG WINAPI ThreadNative::KickOffThread(void* pass) _ASSERTE(GetThread() == pThread); // Now that it's started - KickOffThread_Args args; - args.share = NULL; - args.pThread = pThread; - - ManagedThreadBase::KickOff(KickOffThread_Worker, &args); + ManagedThreadBase::KickOff(KickOffThread_Worker, NULL); PulseAllHelper(pThread); @@ -222,21 +215,13 @@ ULONG WINAPI ThreadNative::KickOffThread(void* pass) return 0; } -extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, PCWSTR pThreadName) +extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, BOOL isThreadPool, PCWSTR pThreadName) { QCALL_CONTRACT; BEGIN_QCALL; - ThreadNative::Start(thread, threadStackSize, priority, pThreadName); - - END_QCALL; -} - -void ThreadNative::Start(Thread* pNewThread, int threadStackSize, int priority, PCWSTR pThreadName) -{ - STANDARD_VM_CONTRACT; - + Thread* pNewThread = thread; _ASSERTE(pNewThread != NULL); // Is the thread already started? You can't restart a thread. @@ -283,6 +268,8 @@ void ThreadNative::Start(Thread* pNewThread, int threadStackSize, int priority, pNewThread->ChooseThreadCPUGroupAffinity(); pNewThread->SetThreadState(Thread::TS_LegalToJoin); + if (isThreadPool) + pNewThread->SetIsThreadPoolThread(); DWORD ret = pNewThread->StartThread(); @@ -311,6 +298,8 @@ void ThreadNative::Start(Thread* pNewThread, int threadStackSize, int priority, PulseAllHelper(pNewThread); pNewThread->HandleThreadStartupFailure(); } + + END_QCALL; } extern "C" void QCALLTYPE ThreadNative_SetPriority(QCall::ObjectHandleOnStack thread, INT32 iPriority) @@ -419,24 +408,6 @@ extern "C" void QCALLTYPE ThreadNative_Initialize(QCall::ObjectHandleOnStack t) END_QCALL; } -// Return whether or not this is a background thread. -FCIMPL1(FC_BOOL_RET, ThreadNative::GetIsBackground, ThreadBaseObject* pThisUNSAFE) -{ - FCALL_CONTRACT; - - if (pThisUNSAFE==NULL) - FCThrowRes(kNullReferenceException, W("NullReference_This")); - - // validate the thread - Thread *thread = pThisUNSAFE->GetInternal(); - - if (ThreadIsDead(thread)) - FCThrowRes(kThreadStateException, W("ThreadState_Dead_State")); - - FC_RETURN_BOOL(thread->IsBackground()); -} -FCIMPLEND - // Deliver the state of the thread as a consistent set of bits. // Duplicate logic in DacDbiInterfaceImpl::GetPartialUserState() extern "C" INT32 QCALLTYPE ThreadNative_GetThreadState(QCall::ThreadHandle thread) @@ -743,6 +714,27 @@ FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE) } FCIMPLEND +// Get whether or not this is a background thread. +extern "C" BOOL QCALLTYPE ThreadNative_GetIsBackground(QCall::ThreadHandle thread) +{ + CONTRACTL + { + QCALL_CHECK_NO_GC_TRANSITION; + PRECONDITION(thread != NULL); + } + CONTRACTL_END; + + BOOL res = FALSE; + + BEGIN_QCALL; + + res = thread->IsBackground(); + + END_QCALL; + + return res; +} + // Set whether or not this is a background thread. extern "C" void QCALLTYPE ThreadNative_SetIsBackground(QCall::ThreadHandle thread, BOOL value) { @@ -755,9 +747,6 @@ extern "C" void QCALLTYPE ThreadNative_SetIsBackground(QCall::ThreadHandle threa BEGIN_QCALL; - if (ThreadIsDead(thread)) - COMPlusThrow(kThreadStateException, W("ThreadState_Dead_State")); - thread->SetBackground(value); END_QCALL; @@ -769,16 +758,10 @@ extern "C" void QCALLTYPE ThreadNative_InformThreadNameChange(QCall::ThreadHandl BEGIN_QCALL; - ThreadNative::InformThreadNameChange(thread, name, len); - - END_QCALL; -} + Thread* pThread = thread; -void ThreadNative::InformThreadNameChange(Thread* pThread, LPCWSTR name, INT32 len) -{ - // Set on Windows 10 Creators Update and later machines the unmanaged thread name as well. That will show up in ETW traces and debuggers which is very helpful - // if more and more threads get a meaningful name - // Will also show up in Linux in gdb and such. + // The name will show up in ETW traces and debuggers which is very helpful if more and more threads + // get a meaningful name. Will also show up in Linux in gdb and such. if (len > 0 && name != NULL && pThread->GetThreadHandle() != INVALID_HANDLE_VALUE) { SetThreadName(pThread->GetThreadHandle(), name); @@ -799,7 +782,6 @@ void ThreadNative::InformThreadNameChange(Thread* pThread, LPCWSTR name, INT32 l } #endif // PROFILING_SUPPORTED - #ifdef DEBUGGING_SUPPORTED if (CORDebuggerAttached()) { @@ -807,43 +789,9 @@ void ThreadNative::InformThreadNameChange(Thread* pThread, LPCWSTR name, INT32 l g_pDebugInterface->NameChangeEvent(NULL, pThread); } #endif // DEBUGGING_SUPPORTED -} - -FCIMPL1(FC_BOOL_RET, ThreadNative::IsThreadpoolThread, ThreadBaseObject* thread) -{ - FCALL_CONTRACT; - - if (thread==NULL) - FCThrowRes(kNullReferenceException, W("NullReference_This")); - Thread *pThread = thread->GetInternal(); - - if (pThread == NULL) - FCThrowRes(kThreadStateException, W("ThreadState_Dead_State")); - - BOOL ret = pThread->IsThreadPoolThread(); - - FC_GC_POLL_RET(); - - FC_RETURN_BOOL(ret); -} -FCIMPLEND - -FCIMPL1(void, ThreadNative::SetIsThreadpoolThread, ThreadBaseObject* thread) -{ - FCALL_CONTRACT; - - if (thread == NULL) - FCThrowResVoid(kNullReferenceException, W("NullReference_This")); - - Thread *pThread = thread->GetInternal(); - - if (pThread == NULL) - FCThrowResVoid(kThreadStateException, W("ThreadState_Dead_State")); - - pThread->SetIsThreadPoolThread(); + END_QCALL; } -FCIMPLEND FCIMPL0(INT32, ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration) { diff --git a/src/coreclr/vm/comsynchronizable.h b/src/coreclr/vm/comsynchronizable.h index b7c64c529084f..c06af82d0f296 100644 --- a/src/coreclr/vm/comsynchronizable.h +++ b/src/coreclr/vm/comsynchronizable.h @@ -15,22 +15,9 @@ #ifndef _COMSYNCHRONIZABLE_H #define _COMSYNCHRONIZABLE_H -#include "field.h" // For FieldDesc definition. - -// -// Each function that we call through native only gets one argument, -// which is actually a pointer to its stack of arguments. Our structs -// for accessing these are defined below. -// - -struct SharedState; - class ThreadNative { -friend class ThreadBaseObject; - public: - enum { PRIORITY_LOWEST = 0, @@ -52,30 +39,14 @@ friend class ThreadBaseObject; ThreadAbortRequested = 128, }; - static FCDECL1(FC_BOOL_RET, GetIsBackground, ThreadBaseObject* pThisUNSAFE); - static FCDECL0(INT32, GetOptimalMaxSpinWaitsPerSpinIteration); static FCDECL1(void, Finalize, ThreadBaseObject* pThis); - static FCDECL1(FC_BOOL_RET,IsThreadpoolThread, ThreadBaseObject* thread); - static FCDECL1(void, SetIsThreadpoolThread, ThreadBaseObject* thread); - - static void Start(Thread* pNewThread, int threadStackSize, int priority, PCWSTR pThreadName); - static void InformThreadNameChange(Thread* pThread, LPCWSTR name, INT32 len); -private: - - struct KickOffThread_Args { - Thread *pThread; - SharedState *share; - ULONG retVal; - }; - - static void KickOffThread_Worker(LPVOID /* KickOffThread_Args* */); - static ULONG WINAPI KickOffThread(void *pass); }; -extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, PCWSTR pThreadName); +extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, BOOL isThreadPool, PCWSTR pThreadName); extern "C" void QCALLTYPE ThreadNative_SetPriority(QCall::ObjectHandleOnStack thread, INT32 iPriority); extern "C" void QCALLTYPE ThreadNative_GetCurrentThread(QCall::ObjectHandleOnStack thread); +extern "C" BOOL QCALLTYPE ThreadNative_GetIsBackground(QCall::ThreadHandle thread); extern "C" void QCALLTYPE ThreadNative_SetIsBackground(QCall::ThreadHandle thread, BOOL value); extern "C" void QCALLTYPE ThreadNative_InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len); extern "C" BOOL QCALLTYPE ThreadNative_YieldThread(); diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index c43bb35378f24..f8dc1ec066e31 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -688,19 +688,15 @@ extern "C" int QCALLTYPE GCInterface_WaitForFullGCComplete(int millisecondsTimeo return result; } -/*================================GetGeneration================================= +/*================================GetGenerationInternal================================= **Action: Returns the generation in which args->obj is found. **Returns: The generation in which args->obj is found. **Arguments: args->obj -- The object to locate. -**Exceptions: ArgumentException if args->obj is null. ==============================================================================*/ -FCIMPL1(int, GCInterface::GetGeneration, Object* objUNSAFE) +FCIMPL1(int, GCInterface::GetGenerationInternal, Object* objUNSAFE) { FCALL_CONTRACT; - - if (objUNSAFE == NULL) - FCThrowArgumentNull(W("obj")); - + _ASSERTE(objUNSAFE != NULL); int result = (INT32)GCHeapUtilities::GetGCHeap()->WhichGeneration(objUNSAFE); FC_GC_POLL_RET(); return result; diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index ef41239a6bb0f..473300b87677f 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -170,7 +170,7 @@ class GCInterface { static FCDECL1(void, SetLOHCompactionMode, int newLOHCompactionyMode); static FCDECL2(FC_BOOL_RET, RegisterForFullGCNotification, UINT32 gen2Percentage, UINT32 lohPercentage); static FCDECL0(FC_BOOL_RET, CancelFullGCNotification); - static FCDECL1(int, GetGeneration, Object* objUNSAFE); + static FCDECL1(int, GetGenerationInternal, Object* objUNSAFE); static FCDECL0(UINT64, GetSegmentSize); static FCDECL0(int, GetLastGCPercentTimeInGC); static FCDECL1(UINT64, GetGenerationSize, int gen); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 138e3d51399e6..17ee79fb96858 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -836,6 +836,7 @@ DEFINE_FIELD_U(_startHelper, ThreadBaseObject, m_StartHelper) DEFINE_FIELD_U(_DONT_USE_InternalThread, ThreadBaseObject, m_InternalThread) DEFINE_FIELD_U(_priority, ThreadBaseObject, m_Priority) DEFINE_FIELD_U(_isDead, ThreadBaseObject, m_IsDead) +DEFINE_FIELD_U(_isThreadPool, ThreadBaseObject, m_IsThreadPool) DEFINE_CLASS(THREAD, Threading, Thread) DEFINE_METHOD(THREAD, START_CALLBACK, StartCallback, IM_RetVoid) #ifdef FEATURE_OBJCMARSHAL diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index b1f475b3b1640..8996b3a16d811 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -299,9 +299,6 @@ FCFuncEnd() FCFuncStart(gThreadFuncs) FCFuncElement("InternalFinalize", ThreadNative::Finalize) - FCFuncElement("GetIsBackground", ThreadNative::GetIsBackground) - FCFuncElement("get_IsThreadPoolThread", ThreadNative::IsThreadpoolThread) - FCFuncElement("set_IsThreadPoolThread", ThreadNative::SetIsThreadpoolThread) FCFuncElement("get_OptimalMaxSpinWaitsPerSpinIteration", ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration) FCFuncEnd() @@ -340,7 +337,7 @@ FCFuncStart(gGCInterfaceFuncs) FCFuncElement("GetSegmentSize", GCInterface::GetSegmentSize) FCFuncElement("GetLastGCPercentTimeInGC", GCInterface::GetLastGCPercentTimeInGC) FCFuncElement("GetGenerationSize", GCInterface::GetGenerationSize) - FCFuncElement("GetGeneration", GCInterface::GetGeneration) + FCFuncElement("GetGenerationInternal", GCInterface::GetGenerationInternal) FCFuncElement("GetMaxGeneration", GCInterface::GetMaxGeneration) FCFuncElement("_SuppressFinalize", GCInterface::SuppressFinalize) @@ -396,9 +393,8 @@ FCFuncStart(gRuntimeHelpers) FCFuncElement("PrepareDelegate", ReflectionInvocation::PrepareDelegate) FCFuncElement("TryGetHashCode", ObjectNative::TryGetHashCode) FCFuncElement("ContentEquals", ObjectNative::ContentEquals) - FCFuncElement("EnsureSufficientExecutionStack", ReflectionInvocation::EnsureSufficientExecutionStack) FCFuncElement("TryEnsureSufficientExecutionStack", ReflectionInvocation::TryEnsureSufficientExecutionStack) - FCFuncElement("AllocTailCallArgBuffer", TailCallHelp::AllocTailCallArgBuffer) + FCFuncElement("AllocTailCallArgBufferWorker", TailCallHelp::AllocTailCallArgBufferWorker) FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo) FCFuncElement("Box", JIT_Box) FCFuncElement("Unbox_Nullable", JIT_Unbox_Nullable) diff --git a/src/coreclr/vm/fcall.h b/src/coreclr/vm/fcall.h index a8b11854e795e..5982611e88295 100644 --- a/src/coreclr/vm/fcall.h +++ b/src/coreclr/vm/fcall.h @@ -1242,29 +1242,9 @@ struct FCSigCheck { return 0; \ } -//============================================================================================== -// Like FCThrow but can be used for a VOID-returning FCall. The only -// difference is in the "return" statement. -//============================================================================================== -#define FCThrowVoid(reKind) FCThrowExVoid(reKind, 0, 0, 0, 0) - -//============================================================================================== -// This version lets you attach a message with inserts (similar to -// COMPlusThrow()). -//============================================================================================== -#define FCThrowExVoid(reKind, resID, arg1, arg2, arg3) \ - { \ - while (NULL == \ - __FCThrow(__me, reKind, resID, arg1, arg2, arg3)) {}; \ - return; \ - } - // Use FCThrowRes to throw an exception with a localized error message from the // ResourceManager in managed code. #define FCThrowRes(reKind, resourceName) FCThrowArgumentEx(reKind, NULL, resourceName) -#define FCThrowArgumentNull(argName) FCThrowArgumentEx(kArgumentNullException, argName, NULL) -#define FCThrowArgumentOutOfRange(argName, message) FCThrowArgumentEx(kArgumentOutOfRangeException, argName, message) -#define FCThrowArgument(argName, message) FCThrowArgumentEx(kArgumentException, argName, message) #define FCThrowArgumentEx(reKind, argName, resourceName) \ { \ @@ -1276,9 +1256,6 @@ struct FCSigCheck { // Use FCThrowRes to throw an exception with a localized error message from the // ResourceManager in managed code. #define FCThrowResVoid(reKind, resourceName) FCThrowArgumentVoidEx(reKind, NULL, resourceName) -#define FCThrowArgumentNullVoid(argName) FCThrowArgumentVoidEx(kArgumentNullException, argName, NULL) -#define FCThrowArgumentOutOfRangeVoid(argName, message) FCThrowArgumentVoidEx(kArgumentOutOfRangeException, argName, message) -#define FCThrowArgumentVoid(argName, message) FCThrowArgumentVoidEx(kArgumentException, argName, message) #define FCThrowArgumentVoidEx(reKind, argName, resourceName) \ { \ diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h index c9abe58b8e731..e637a64da2fd1 100644 --- a/src/coreclr/vm/object.h +++ b/src/coreclr/vm/object.h @@ -1327,6 +1327,8 @@ class ThreadBaseObject : public Object // Set in unmanaged code and read in managed code. bool m_IsDead; + bool m_IsThreadPool; + protected: // the ctor and dtor can do no useful work. ThreadBaseObject() {LIMITED_METHOD_CONTRACT;}; diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index bd4f396de4959..18e080bbe12d2 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -240,6 +240,7 @@ static const Entry s_QCall[] = DllImportEntry(ThreadNative_Start) DllImportEntry(ThreadNative_SetPriority) DllImportEntry(ThreadNative_GetCurrentThread) + DllImportEntry(ThreadNative_GetIsBackground) DllImportEntry(ThreadNative_SetIsBackground) DllImportEntry(ThreadNative_InformThreadNameChange) DllImportEntry(ThreadNative_YieldThread) diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index d332fc12a468c..1cd79ba6326c8 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -1438,37 +1438,17 @@ FCIMPL1(void, ReflectionInvocation::PrepareDelegate, Object* delegateUNSAFE) } FCIMPLEND -// This method checks to see if there is sufficient stack to execute the average Framework method. -// If there is not, then it throws System.InsufficientExecutionStackException. The limit for each -// thread is precomputed when the thread is created. -FCIMPL0(void, ReflectionInvocation::EnsureSufficientExecutionStack) -{ - FCALL_CONTRACT; - - Thread *pThread = GetThread(); - - // We use the address of a local variable as our "current stack pointer", which is - // plenty close enough for the purposes of this method. - UINT_PTR current = reinterpret_cast(&pThread); - UINT_PTR limit = pThread->GetCachedStackSufficientExecutionLimit(); - - if (current < limit) - { - FCThrowVoid(kInsufficientExecutionStackException); - } -} -FCIMPLEND - -// As with EnsureSufficientExecutionStack, this method checks and returns whether there is -// sufficient stack to execute the average Framework method, but rather than throwing, -// it simply returns a Boolean: true for sufficient stack space, otherwise false. +// This method checks and returns whether there is sufficient stack to execute the +// average Framework method, but rather than throwing, it simply returns a +// Boolean: true for sufficient stack space, otherwise false. FCIMPL0(FC_BOOL_RET, ReflectionInvocation::TryEnsureSufficientExecutionStack) { FCALL_CONTRACT; Thread *pThread = GetThread(); - // Same logic as EnsureSufficientExecutionStack + // We use the address of a local variable as our "current stack pointer", which is + // plenty close enough for the purposes of this method. UINT_PTR current = reinterpret_cast(&pThread); UINT_PTR limit = pThread->GetCachedStackSufficientExecutionLimit(); diff --git a/src/coreclr/vm/reflectioninvocation.h b/src/coreclr/vm/reflectioninvocation.h index ff20d72d870f9..f2879590f2d96 100644 --- a/src/coreclr/vm/reflectioninvocation.h +++ b/src/coreclr/vm/reflectioninvocation.h @@ -47,7 +47,6 @@ class ReflectionInvocation { public: static FCDECL1(void, PrepareDelegate, Object* delegateUNSAFE); - static FCDECL0(void, EnsureSufficientExecutionStack); static FCDECL0(FC_BOOL_RET, TryEnsureSufficientExecutionStack); // TypedReference functions, should go somewhere else diff --git a/src/coreclr/vm/tailcallhelp.cpp b/src/coreclr/vm/tailcallhelp.cpp index 4d9c60838b54f..d59a2861a80c4 100644 --- a/src/coreclr/vm/tailcallhelp.cpp +++ b/src/coreclr/vm/tailcallhelp.cpp @@ -11,23 +11,11 @@ #include "threads.h" -FCIMPL2(void*, TailCallHelp::AllocTailCallArgBuffer, INT32 size, void* gcDesc) +FCIMPL2(void*, TailCallHelp::AllocTailCallArgBufferWorker, INT32 size, void* gcDesc) { - CONTRACTL - { - FCALL_CHECK; - INJECT_FAULT(FCThrow(kOutOfMemoryException);); - } - CONTRACTL_END - + FCALL_CONTRACT; _ASSERTE(size >= 0); - - void* result = GetThread()->GetTailCallTls()->AllocArgBuffer(size, gcDesc); - - if (result == NULL) - FCThrow(kOutOfMemoryException); - - return result; + return GetThread()->GetTailCallTls()->AllocArgBuffer(size, gcDesc); } FCIMPLEND diff --git a/src/coreclr/vm/tailcallhelp.h b/src/coreclr/vm/tailcallhelp.h index 32883076a6920..10b14bd9f6161 100644 --- a/src/coreclr/vm/tailcallhelp.h +++ b/src/coreclr/vm/tailcallhelp.h @@ -13,7 +13,7 @@ struct ArgBufferLayout; class TailCallHelp { public: - static FCDECL2(void*, AllocTailCallArgBuffer, INT32, void*); + static FCDECL2(void*, AllocTailCallArgBufferWorker, INT32, void*); static FCDECL2(void*, GetTailCallInfo, void**, void**); static void CreateTailCallHelperStubs( diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index c7ad8ef380d2c..92ca9f9ede48a 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -6201,9 +6201,9 @@ BOOL Thread::SetStackLimits(SetStackLimitScope scope) return FALSE; } - // Compute the limit used by EnsureSufficientExecutionStack and cache it on the thread. This minimum stack size should + // Compute the limit used by TryEnsureSufficientExecutionStack and cache it on the thread. This minimum stack size should // be sufficient to allow a typical non-recursive call chain to execute, including potential exception handling and - // garbage collection. Used for probing for available stack space through RuntimeImports.EnsureSufficientExecutionStack, + // garbage collection. Used for probing for available stack space through RuntimeImports.TryEnsureSufficientExecutionStack, // among other things. #ifdef HOST_64BIT const UINT_PTR MinExecutionStackSize = 128 * 1024; diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index 8de07ab7e5cde..dc349b02c7122 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -2423,7 +2423,7 @@ class Thread // These access the stack base and limit values for this thread. (They are cached during InitThread.) The // "stack base" is the "upper bound", i.e., where the stack starts growing from. (Main's call frame is at the // upper bound.) The "stack limit" is the "lower bound", i.e., how far the stack can grow down to. - // The "stack sufficient execution limit" is used by EnsureSufficientExecutionStack() to limit how much stack + // The "stack sufficient execution limit" is used by TryEnsureSufficientExecutionStack() to limit how much stack // should remain to execute the average Framework method. PTR_VOID GetCachedStackBase() {LIMITED_METHOD_DAC_CONTRACT; return m_CacheStackBase; } PTR_VOID GetCachedStackLimit() {LIMITED_METHOD_DAC_CONTRACT; return m_CacheStackLimit;} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs index 74dbefe586906..574dbf5ee2ed2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs @@ -58,7 +58,7 @@ internal RegisteredWaitHandle(WaitHandle waitHandle, _ThreadPoolWaitOrTimerCallb #if TARGET_WASI if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 #endif -#if WINDOWS +#if TARGET_WINDOWS Debug.Assert(!ThreadPool.UseWindowsThreadPool); #endif GC.SuppressFinalize(this);