Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
Merged
AaronRobinsonMSFT merged 19 commits intodotnet:mainfrom Mar 2, 2026
Merged
Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834AaronRobinsonMSFT merged 19 commits intodotnet:mainfrom
AaronRobinsonMSFT merged 19 commits intodotnet:mainfrom
Conversation
…sOnly Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from dotnet#123864): - GetExceptionMessage: Object.ToString via UCO - ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO - WrapNonCompliantException: RuntimeWrappedException ctor via UCO - CreateTypeInitializationExceptionObject: TypeInitializationException via UCO - GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO - GetEventArgsForNotification: FirstChanceExceptionEventArgs ctor via UCO Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request converts six exception-related MethodDescCallSite call sites in excep.cpp to use the more efficient UnmanagedCallersOnly reverse P/Invoke pattern, following the established approach from priority 1 and 2 tasks in issue #123864.
Changes:
- Replaces
MethodDescCallSite/CallDescrWorkerwithUnmanagedCallersOnlyCaller::InvokeThrowingfor six exception-handling methods - Adds six new UnmanagedCallersOnly wrapper methods in managed code (Object.CoreCLR.cs, Exception.CoreCLR.cs, Environment.CoreCLR.cs)
- Updates metasig.h with six new method signatures and corelib.h with updated DEFINE_METHOD entries, removing obsolete constructor definitions
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/vm/metasig.h | Adds 6 new metasig definitions for UnmanagedCallersOnly wrappers (PtrObj_PtrStr, PtrObj_PtrObj, PtrStr_PtrStr, PtrException_PtrException, PtrChar_PtrException_PtrObj, PtrException_PtrObj, all with PtrException_RetVoid suffix) |
| src/coreclr/vm/corelib.h | Updates DEFINE_METHOD entries for the 6 converted methods and removes 3 obsolete constructor entries (TYPE_INIT_EXCEPTION.STR_EX_CTOR, RUNTIME_WRAPPED_EXCEPTION.OBJ_CTOR, FIRSTCHANCE_EVENTARGS.CTOR) |
| src/coreclr/vm/excep.cpp | Converts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification |
| src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs | Adds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter |
| src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs | Adds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs |
| src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs | Converts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters |
jkotas
reviewed
Feb 25, 2026
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs
Outdated
Show resolved
Hide resolved
jkotas
reviewed
Feb 25, 2026
jkotas
reviewed
Feb 25, 2026
jkotas
reviewed
Feb 25, 2026
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
Outdated
Show resolved
Hide resolved
jkotas
reviewed
Feb 25, 2026
jkotas
reviewed
Feb 25, 2026
- Move GetToString from System.Object to System.Exception to avoid breaking reflection in user code - Clean up stale comment about SystemException fallback in CreateTypeInitializationExceptionObject - Rename GetResourceStringLocal to GetResourceString, drop Local suffix - Delete unused DEFINE_CLASS(FIRSTCHANCE_EVENTARGS) from corelib.h - Fold GetResourceStringFromManaged into its single caller ResMgrGetString, pass key as char* and move string creation to managed side - Add GCPROTECT around ResMgrGetString caller in clrex.cpp Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…o single UCO call Combine event args construction and delegate invocation into a single managed DeliverFirstChanceNotification UCO method. Multicast delegate iteration is now handled by managed Delegate.Invoke. Remove the native DeliverExceptionNotification and GetEventArgsForNotification methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jkotas
reviewed
Feb 25, 2026
Member
Author
|
@EgorBot -linux_amd -osx_arm64 using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);
public class Bench
{
private Exception _cachedException = new InvalidOperationException("test");
[Benchmark]
public void ThrowCatch_NoHandler()
{
try
{
throw _cachedException;
}
catch
{
}
}
[Benchmark]
public void ThrowCatch_WithHandler()
{
AppDomain.CurrentDomain.FirstChanceException += Handler;
try
{
throw _cachedException;
}
catch
{
}
finally
{
AppDomain.CurrentDomain.FirstChanceException -= Handler;
}
}
private static void Handler(object? sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
{
}
} |
…dd OnFirstChanceException method
Replace the CanDeliverNotificationToCurrentAppDomain check, which read the managed FirstChanceException delegate field via CoreLibBinder in cooperative GC mode, with a native Volatile<BOOL> flag set via a SuppressGCTransition QCall when a handler is first registered. This avoids the GCX_COOP transition in DeliverFirstChanceNotification on every exception throw when no handler is registered. The flag is sticky: once set to TRUE it is never cleared, avoiding race conditions between concurrent add/remove operations. - Remove CanDeliverNotificationToCurrentAppDomain and FIELD__APPCONTEXT__FIRST_CHANCE_EXCEPTION - Add AppDomain_SetFirstChanceExceptionHandler QCall (SuppressGCTransition) - Move GCX_COOP inside the handler check in DeliverFirstChanceNotification Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
68 tasks
jkotas
reviewed
Feb 26, 2026
jkotas
reviewed
Feb 26, 2026
jkotas
reviewed
Feb 26, 2026
- Remove unused using in Exception.CoreCLR.cs - Move SetFirstChanceExceptionHandler and OnFirstChanceException UCO from AppDomain.CoreCLR.cs to new AppContext.CoreCLR.cs - Move OnFirstChanceException shared logic to AppContext.cs following the OnUnhandledException pattern (RuntimeExport for NativeAOT, UCO for CoreCLR) - Update NativeAOT to use per-handler try/catch - Pass AppDomain.CurrentDomain as sender on CoreCLR, null on NativeAOT - Rename QCall entrypoint to AppContext_SetFirstChanceExceptionHandler Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jkotas
reviewed
Feb 27, 2026
This was referenced Feb 27, 2026
Open
This was referenced Feb 27, 2026
This was referenced Feb 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace
MethodDescCallSite/CallDescrWorkercalls with more efficientUnmanagedCallersOnlyreverse P/Invoke calls in exception handling code paths (priority 2 from #123864).Changes
Convert the following call sites in
excep.cppto useUnmanagedCallersOnlyCaller:GetExceptionMessage:Object.ToStringvia UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)ExceptionPreserveStackTrace:InternalPreserveStackTracevia UCOWrapNonCompliantException:RuntimeWrappedExceptionconstruction via UCOCreateTypeInitializationExceptionObject:TypeInitializationExceptionconstruction via UCOGetResourceStringFromManaged:Environment.GetResourceStringLocalvia UCOGetEventArgsForNotification:FirstChanceExceptionEventArgsconstruction via UCOPattern
Each conversion follows the established pattern:
[UnmanagedCallersOnly]static wrapper in managed code withException*out-parametermetasig.handDEFINE_METHODincorelib.hMethodDescCallSite+ARG_SLOTwithUnmanagedCallersOnlyCaller::InvokeThrowingDEFINE_METHODentries for old constructorsAll GC references passed to
InvokeThrowingare in GCPROTECT'd locations.