Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove some implicit Helper Method Frames (HMF) #107648

Merged
merged 9 commits into from
Sep 24, 2024
10 changes: 7 additions & 3 deletions src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
Original file line number Diff line number Diff line change
@@ -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.
//
Original file line number Diff line number Diff line change
@@ -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();
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}
}

// 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();
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}
return buffer;
}

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe TailCallTls* GetTailCallInfo(IntPtr retAddrSlot, IntPtr* retAddr);
Original file line number Diff line number Diff line change
@@ -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)
/// </summary>
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,32 @@ 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);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetIsBackground")]
private static partial void SetIsBackground(ThreadHandle t, Interop.BOOL value);

/// <summary>Returns true if the thread is a threadpool thread.</summary>
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);
_isThreadPool = value;
}
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetPriority")]
132 changes: 43 additions & 89 deletions src/coreclr/vm/comsynchronizable.cpp
Original file line number Diff line number Diff line change
@@ -127,20 +127,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());
@@ -175,7 +172,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
@@ -212,11 +209,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);

@@ -230,18 +223,7 @@ ULONG WINAPI ThreadNative::KickOffThread(void* pass)
return 0;
}

extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, 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)
static void StartThread(Thread* pNewThread, int threadStackSize, int priority, BOOL isThreadPool, PCWSTR pThreadName)
{
STANDARD_VM_CONTRACT;

@@ -291,6 +273,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();

@@ -321,6 +305,17 @@ void ThreadNative::Start(Thread* pNewThread, int threadStackSize, int priority,
}
}

extern "C" void QCALLTYPE ThreadNative_Start(QCall::ThreadHandle thread, int threadStackSize, int priority, BOOL isThreadPool, PCWSTR pThreadName)
{
QCALL_CONTRACT;

BEGIN_QCALL;

StartThread(thread, threadStackSize, priority, isThreadPool, pThreadName);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved

END_QCALL;
}

extern "C" void QCALLTYPE ThreadNative_SetPriority(QCall::ObjectHandleOnStack thread, INT32 iPriority)
{
QCALL_CONTRACT;
@@ -427,24 +422,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)
@@ -729,6 +706,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)
{
@@ -741,9 +739,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;
@@ -755,16 +750,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);
@@ -785,51 +774,16 @@ void ThreadNative::InformThreadNameChange(Thread* pThread, LPCWSTR name, INT32 l
}
#endif // PROFILING_SUPPORTED


#ifdef DEBUGGING_SUPPORTED
if (CORDebuggerAttached())
{
_ASSERTE(NULL != g_pDebugInterface);
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)
{
Loading