Skip to content

Commit ee68e0c

Browse files
AaronRobinsonMSFTjtschuster
authored andcommitted
Remove Helper Method Frames for Exception, GC and Thread methods (dotnet#107218)
* Convert Exception.GetFrozenStackTrace() * Convert GC.AllocateNewArray() Removed use of Unsafe.As(). * Convert Thread.GetApartmentStateNative() and Thread.SetApartmentStateNative() * Convert Thread.Join() * Convert Thread.Priority property
1 parent 70518f4 commit ee68e0c

File tree

14 files changed

+250
-279
lines changed

14 files changed

+250
-279
lines changed

src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,6 @@ internal void InternalPreserveStackTrace()
117117
[MethodImpl(MethodImplOptions.InternalCall)]
118118
private static extern void PrepareForForeignExceptionRaise();
119119

120-
[MethodImpl(MethodImplOptions.InternalCall)]
121-
private static extern object? GetFrozenStackTrace(Exception exception);
122-
123120
[MethodImpl(MethodImplOptions.InternalCall)]
124121
internal static extern uint GetExceptionCount();
125122

@@ -226,9 +223,14 @@ public DispatchState(
226223
}
227224
}
228225

226+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ExceptionNative_GetFrozenStackTrace")]
227+
private static partial void GetFrozenStackTrace(ObjectHandleOnStack exception, ObjectHandleOnStack stackTrace);
228+
229229
internal DispatchState CaptureDispatchState()
230230
{
231-
object? stackTrace = GetFrozenStackTrace(this);
231+
Exception _this = this;
232+
object? stackTrace = null;
233+
GetFrozenStackTrace(ObjectHandleOnStack.Create(ref _this), ObjectHandleOnStack.Create(ref stackTrace));
232234

233235
return new DispatchState(stackTrace,
234236
_remoteStackTraceString, _ipForWatsonBuckets, _watsonBuckets);

src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ internal enum GC_ALLOC_FLAGS
103103
GC_ALLOC_PINNED_OBJECT_HEAP = 64,
104104
};
105105

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

109109
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCInterface_GetTotalMemory")]
110110
private static partial long GetTotalMemory();
@@ -791,16 +791,25 @@ public static unsafe T[] AllocateUninitializedArray<T>(int length, bool pinned =
791791
{
792792
return new T[length];
793793
}
794-
795794
#endif
796795
}
797796

798-
// Runtime overrides GC_ALLOC_ZEROING_OPTIONAL if the type contains references, so we don't need to worry about that.
799-
GC_ALLOC_FLAGS flags = GC_ALLOC_FLAGS.GC_ALLOC_ZEROING_OPTIONAL;
800-
if (pinned)
801-
flags |= GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP;
797+
return AllocateNewArrayWorker(length, pinned);
798+
799+
[MethodImpl(MethodImplOptions.NoInlining)]
800+
static T[] AllocateNewArrayWorker(int length, bool pinned)
801+
{
802+
// Runtime overrides GC_ALLOC_ZEROING_OPTIONAL if the type contains references, so we don't need to worry about that.
803+
GC_ALLOC_FLAGS flags = GC_ALLOC_FLAGS.GC_ALLOC_ZEROING_OPTIONAL;
804+
if (pinned)
805+
{
806+
flags |= GC_ALLOC_FLAGS.GC_ALLOC_PINNED_OBJECT_HEAP;
807+
}
802808

803-
return Unsafe.As<T[]>(AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags));
809+
T[]? result = null;
810+
AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags, ObjectHandleOnStack.Create(ref result));
811+
return result!;
812+
}
804813
}
805814

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

821-
return Unsafe.As<T[]>(AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags));
830+
T[]? result = null;
831+
AllocateNewArray(RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle), length, flags, ObjectHandleOnStack.Create(ref result));
832+
return result!;
822833
}
823834

824835
[MethodImpl(MethodImplOptions.InternalCall)]

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public sealed partial class Thread
5858
// but those types of changes may race with the reset anyway, so this field doesn't need to be synchronized.
5959
private bool _mayNeedResetForThreadPool;
6060

61+
// Set in unmanaged and read in managed code.
62+
private bool _isDead;
63+
6164
private Thread() { }
6265

6366
public int ManagedThreadId
@@ -74,7 +77,7 @@ internal ThreadHandle GetNativeHandle()
7477
// This should never happen under normal circumstances.
7578
if (thread == IntPtr.Zero)
7679
{
77-
throw new ArgumentException(null, SR.Argument_InvalidHandle);
80+
throw new ThreadStateException(SR.Argument_InvalidHandle);
7881
}
7982

8083
return new ThreadHandle(thread);
@@ -211,26 +214,32 @@ public extern bool IsThreadPoolThread
211214
internal set;
212215
}
213216

217+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetPriority")]
218+
[return: MarshalAs(UnmanagedType.Bool)]
219+
private static partial void SetPriority(ObjectHandleOnStack thread, int priority);
220+
214221
/// <summary>Returns the priority of the thread.</summary>
215222
public ThreadPriority Priority
216223
{
217-
get => (ThreadPriority)GetPriorityNative();
224+
get
225+
{
226+
if (_isDead)
227+
{
228+
throw new ThreadStateException(SR.ThreadState_Dead_Priority);
229+
}
230+
return (ThreadPriority)_priority;
231+
}
218232
set
219233
{
220-
SetPriorityNative((int)value);
234+
Thread _this = this;
235+
SetPriority(ObjectHandleOnStack.Create(ref _this), (int)value);
221236
if (value != ThreadPriority.Normal)
222237
{
223238
_mayNeedResetForThreadPool = true;
224239
}
225240
}
226241
}
227242

228-
[MethodImpl(MethodImplOptions.InternalCall)]
229-
private extern int GetPriorityNative();
230-
231-
[MethodImpl(MethodImplOptions.InternalCall)]
232-
private extern void SetPriorityNative(int priority);
233-
234243
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetCurrentOSThreadId")]
235244
private static partial ulong GetCurrentOSThreadId();
236245

@@ -243,21 +252,31 @@ public ThreadPriority Priority
243252
[MethodImpl(MethodImplOptions.InternalCall)]
244253
private extern int GetThreadStateNative();
245254

246-
public ApartmentState GetApartmentState() =>
247-
#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
248-
(ApartmentState)GetApartmentStateNative();
249-
#else // !FEATURE_COMINTEROP_APARTMENT_SUPPORT
250-
ApartmentState.Unknown;
251-
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
252-
253255
/// <summary>
254256
/// An unstarted thread can be marked to indicate that it will host a
255257
/// single-threaded or multi-threaded apartment.
256258
/// </summary>
257259
#if FEATURE_COMINTEROP_APARTMENT_SUPPORT
260+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_GetApartmentState")]
261+
private static partial int GetApartmentState(ObjectHandleOnStack t);
262+
263+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_SetApartmentState")]
264+
private static partial int SetApartmentState(ObjectHandleOnStack t, int state);
265+
266+
public ApartmentState GetApartmentState()
267+
{
268+
Thread _this = this;
269+
return (ApartmentState)GetApartmentState(ObjectHandleOnStack.Create(ref _this));
270+
}
271+
258272
private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
259273
{
260-
ApartmentState retState = (ApartmentState)SetApartmentStateNative((int)state);
274+
ApartmentState retState;
275+
lock (this) // This lock is only needed when the this is not the current thread.
276+
{
277+
Thread _this = this;
278+
retState = (ApartmentState)SetApartmentState(ObjectHandleOnStack.Create(ref _this), (int)state);
279+
}
261280

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

285-
[MethodImpl(MethodImplOptions.InternalCall)]
286-
internal extern int GetApartmentStateNative();
287-
288-
[MethodImpl(MethodImplOptions.InternalCall)]
289-
internal extern int SetApartmentStateNative(int state);
290304
#else // FEATURE_COMINTEROP_APARTMENT_SUPPORT
305+
public ApartmentState GetApartmentState() => ApartmentState.Unknown;
306+
291307
private static bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
292308
{
293309
if (state != ApartmentState.Unknown)
@@ -331,18 +347,31 @@ public void Interrupt()
331347
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_Interrupt")]
332348
private static partial void Interrupt(ThreadHandle t);
333349

350+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_Join")]
351+
[return: MarshalAs(UnmanagedType.Bool)]
352+
private static partial bool Join(ObjectHandleOnStack thread, int millisecondsTimeout);
353+
334354
/// <summary>
335355
/// Waits for the thread to die or for timeout milliseconds to elapse.
336356
/// </summary>
337357
/// <returns>
338358
/// Returns true if the thread died, or false if the wait timed out. If
339359
/// -1 is given as the parameter, no timeout will occur.
340360
/// </returns>
341-
/// <exception cref="ArgumentException">if timeout &lt; -1 (Timeout.Infinite)</exception>
361+
/// <exception cref="ArgumentOutOfRangeException">if timeout &lt; -1 (Timeout.Infinite)</exception>
342362
/// <exception cref="ThreadInterruptedException">if the thread is interrupted while waiting</exception>
343363
/// <exception cref="ThreadStateException">if the thread has not been started yet</exception>
344-
[MethodImpl(MethodImplOptions.InternalCall)]
345-
public extern bool Join(int millisecondsTimeout);
364+
public bool Join(int millisecondsTimeout)
365+
{
366+
// Validate the timeout
367+
if (millisecondsTimeout < 0 && millisecondsTimeout != Timeout.Infinite)
368+
{
369+
throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
370+
}
371+
372+
Thread _this = this;
373+
return Join(ObjectHandleOnStack.Create(ref _this), millisecondsTimeout);
374+
}
346375

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

0 commit comments

Comments
 (0)