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 Helper Method Frames for Exception, GC and Thread methods #107218

Merged
merged 16 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ internal void InternalPreserveStackTrace()
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void PrepareForForeignExceptionRaise();

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern object? GetFrozenStackTrace(Exception exception);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern uint GetExceptionCount();

Expand Down Expand Up @@ -226,9 +223,14 @@ public DispatchState(
}
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ExceptionNative_GetFrozenStackTrace")]
private static partial void GetFrozenStackTrace(ObjectHandleOnStack exception, ObjectHandleOnStack stackTrace);

internal DispatchState CaptureDispatchState()
{
object? stackTrace = GetFrozenStackTrace(this);
Exception _this = this;
object? stackTrace = null;
GetFrozenStackTrace(ObjectHandleOnStack.Create(ref _this), ObjectHandleOnStack.Create(ref stackTrace));

return new DispatchState(stackTrace,
_remoteStackTraceString, _ipForWatsonBuckets, _watsonBuckets);
Expand Down
18 changes: 14 additions & 4 deletions src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ internal enum GC_ALLOC_FLAGS
GC_ALLOC_PINNED_OBJECT_HEAP = 64,
};

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern Array AllocateNewArray(IntPtr typeHandle, int length, GC_ALLOC_FLAGS flags);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCInterface_AllocateNewArray")]
private static partial void AllocateNewArray(IntPtr typeHandlePtr, int length, GC_ALLOC_FLAGS flags, ObjectHandleOnStack ret);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCInterface_GetTotalMemory")]
private static partial long GetTotalMemory();
Expand Down Expand Up @@ -800,7 +800,15 @@ public static unsafe T[] AllocateUninitializedArray<T>(int length, bool pinned =
if (pinned)
flags |= GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP;

return Unsafe.As<T[]>(AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags));
return AllocateNewArrayWorker<T>(length, flags);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved

[MethodImpl(MethodImplOptions.NoInlining)]
static U[] AllocateNewArrayWorker<U>(int length, GC_ALLOC_FLAGS flags)
{
U[]? result = null;
AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(U[]).TypeHandle), length, flags, ObjectHandleOnStack.Create(ref result));
return result!;
}
}

/// <summary>
Expand All @@ -818,7 +826,9 @@ public static T[] AllocateArray<T>(int length, bool pinned = false) // T[] rathe
flags = GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP;
}

return Unsafe.As<T[]>(AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags));
T[]? result = null;
AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags, ObjectHandleOnStack.Create(ref result));
return result!;
}

[MethodImpl(MethodImplOptions.InternalCall)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,26 +211,50 @@ public extern bool IsThreadPoolThread
internal set;
}

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_ThreadIsDead")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool ThreadIsDead(ThreadHandle t);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_TrySetPriority")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool TrySetPriority(ThreadHandle t, int priority);

/// <summary>Returns the priority of the thread.</summary>
public ThreadPriority Priority
{
get => (ThreadPriority)GetPriorityNative();
get
{
if (ThreadIsDead(GetNativeHandle())) // GC.KeepAlive() not needed since member fields are touched below.
{
throw new ThreadStateException(SR.ThreadState_Dead_Priority);
}
return (ThreadPriority)_priority;
}
set
{
SetPriorityNative((int)value);
ThreadHandle handle = GetNativeHandle();
if (ThreadIsDead(handle)) // GC.KeepAlive() not needed since member fields are touched below.
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
// Note that you can manipulate the priority of a thread that hasn't started yet,
// or one that is running. But you get an exception if you manipulate the priority
// of a thread that has died.
throw new ThreadStateException(SR.ThreadState_Dead_Priority);
}

int prev = _priority;
_priority = (int)value;
if (!TrySetPriority(handle, _priority)) // GC.KeepAlive() not needed since member fields are touched below.
{
_priority = prev;
throw new ThreadStateException(SR.ThreadState_SetPriorityFailed);
}
if (value != ThreadPriority.Normal)
{
_mayNeedResetForThreadPool = true;
}
}
}

[MethodImpl(MethodImplOptions.InternalCall)]
private extern int GetPriorityNative();

[MethodImpl(MethodImplOptions.InternalCall)]
private extern void SetPriorityNative(int priority);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetCurrentOSThreadId")]
private static partial ulong GetCurrentOSThreadId();

Expand All @@ -243,21 +267,31 @@ public ThreadPriority Priority
[MethodImpl(MethodImplOptions.InternalCall)]
private extern int GetThreadStateNative();

public ApartmentState GetApartmentState() =>
#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
(ApartmentState)GetApartmentStateNative();
#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT
ApartmentState.Unknown;
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT

/// <summary>
/// An unstarted thread can be marked to indicate that it will host a
/// single-threaded or multi-threaded apartment.
/// </summary>
#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetApartmentState")]
private static partial int GetApartmentState(ThreadHandle t);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetApartmentState")]
private static partial int SetApartmentState(ThreadHandle t, int state);

public ApartmentState GetApartmentState()
{
var state = (ApartmentState)GetApartmentState(GetNativeHandle());
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
GC.KeepAlive(this);
return state;
}

private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
{
ApartmentState retState = (ApartmentState)SetApartmentStateNative((int)state);
ApartmentState retState;
lock (this) // This is also satisfying a GC.KeepAlive().
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
retState = (ApartmentState)SetApartmentState(GetNativeHandle(), (int)state);
}

// Special case where we pass in Unknown and get back MTA.
// Once we CoUninitialize the thread, the OS will still
Expand All @@ -282,12 +316,9 @@ private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
return true;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern int GetApartmentStateNative();

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern int SetApartmentStateNative(int state);
#else // FEATURE_COMINTEROP_APARTMENT_SUPPORT
public ApartmentState GetApartmentState() => ApartmentState.Unknown;

private static bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
{
if (state != ApartmentState.Unknown)
Expand Down Expand Up @@ -331,18 +362,32 @@ public void Interrupt()
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_Interrupt")]
private static partial void Interrupt(ThreadHandle t);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_Join")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool Join(ThreadHandle t, int millisecondsTimeout);

/// <summary>
/// Waits for the thread to die or for timeout milliseconds to elapse.
/// </summary>
/// <returns>
/// Returns true if the thread died, or false if the wait timed out. If
/// -1 is given as the parameter, no timeout will occur.
/// </returns>
/// <exception cref="ArgumentException">if timeout &lt; -1 (Timeout.Infinite)</exception>
/// <exception cref="ArgumentOutOfRangeException">if timeout &lt; -1 (Timeout.Infinite)</exception>
/// <exception cref="ThreadInterruptedException">if the thread is interrupted while waiting</exception>
/// <exception cref="ThreadStateException">if the thread has not been started yet</exception>
[MethodImpl(MethodImplOptions.InternalCall)]
public extern bool Join(int millisecondsTimeout);
public bool Join(int millisecondsTimeout)
{
// Validate the timeout
if (millisecondsTimeout < 0 && millisecondsTimeout != Timeout.Infinite)
{
throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
}

bool res = Join(GetNativeHandle(), millisecondsTimeout);
GC.KeepAlive(this);
return res;
}

/// <summary>
/// Max value to be passed into <see cref="SpinWait(int)"/> for optimal delaying. This value is normalized to be
Expand Down
Loading
Loading