Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly - #124834

Merged
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2
Mar 2, 2026
Merged

Convert exception-related MethodDescCallSite calls to UnmanagedCallersOnly#124834
AaronRobinsonMSFT merged 19 commits into
dotnet:mainfrom
AaronRobinsonMSFT:uco-excep-priority2

Conversation

@AaronRobinsonMSFT

@AaronRobinsonMSFTAaronRobinsonMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Replace MethodDescCallSite/CallDescrWorker calls with more efficient UnmanagedCallersOnly reverse P/Invoke calls in exception handling code paths (priority 2 from #123864).

Changes

Convert the following call sites in excep.cpp to use UnmanagedCallersOnlyCaller:

  • GetExceptionMessage: Object.ToString via UCO (METHOD__RUNTIMEHELPERS__CALL_TO_STRING)
  • ExceptionPreserveStackTrace: InternalPreserveStackTrace via UCO
  • WrapNonCompliantException: RuntimeWrappedException construction via UCO
  • CreateTypeInitializationExceptionObject: TypeInitializationException construction via UCO
  • GetResourceStringFromManaged: Environment.GetResourceStringLocal via UCO
  • GetEventArgsForNotification: FirstChanceExceptionEventArgs construction via UCO

Pattern

Each conversion follows the established pattern:

  1. Add [UnmanagedCallersOnly] static wrapper in managed code with Exception* out-parameter
  2. Add corresponding metasig in metasig.h and DEFINE_METHOD in corelib.h
  3. Replace MethodDescCallSite + ARG_SLOT with UnmanagedCallersOnlyCaller::InvokeThrowing
  4. Remove now-unused DEFINE_METHOD entries for old constructors

All GC references passed to InvokeThrowing are in GCPROTECT'd locations.

…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>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/CallDescrWorker with UnmanagedCallersOnlyCaller::InvokeThrowing for 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
FileDescription
src/coreclr/vm/metasig.hAdds 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.hUpdates 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.cppConverts 6 call sites to use UnmanagedCallersOnlyCaller: GetExceptionMessage, ExceptionPreserveStackTrace, WrapNonCompliantException, CreateTypeInitializationExceptionObject, GetResourceStringFromManaged, GetEventArgsForNotification
src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.csAdds GetToString UnmanagedCallersOnly wrapper with Exception* out-parameter
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.csAdds 4 UnmanagedCallersOnly wrappers: InternalPreserveStackTrace, CreateRuntimeWrappedException, CreateTypeInitializationException, CreateFirstChanceExceptionEventArgs
src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.csConverts GetResourceStringLocal to UnmanagedCallersOnly pattern with string* in/out parameters

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs Outdated
Comment threadsrc/coreclr/vm/corelib.h Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
AaronRobinsonMSFTand others added 3 commits February 25, 2026 10:43
- 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>
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
@AaronRobinsonMSFT

Copy link
Copy Markdown
MemberAuthor

@EgorBot -linux_amd -osx_arm64

usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem;BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);publicclassBench{privateException_cachedException=newInvalidOperationException("test");[Benchmark]publicvoidThrowCatch_NoHandler(){try{throw_cachedException;}catch{}}[Benchmark]publicvoidThrowCatch_WithHandler(){AppDomain.CurrentDomain.FirstChanceException+=Handler;try{throw_cachedException;}catch{}finally{AppDomain.CurrentDomain.FirstChanceException-=Handler;}}privatestaticvoidHandler(object?sender,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgse){}}

AaronRobinsonMSFTand others added 2 commits February 25, 2026 16:47
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>
CopilotAI review requested due to automatic review settings February 26, 2026 02:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment threadsrc/coreclr/vm/excep.cpp
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppDomain.cs
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/coreclr/vm/excep.cpp Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/AppContext.cs Outdated
CopilotAI review requested due to automatic review settings February 27, 2026 01:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

CopilotAI review requested due to automatic review settings February 27, 2026 18:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

CopilotAI review requested due to automatic review settings March 2, 2026 04:46

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/vm/excep.cpp
@AaronRobinsonMSFT
AaronRobinsonMSFT merged commit 77f0e35 into dotnet:mainMar 2, 2026
163 of 168 checks passed
@AaronRobinsonMSFT
AaronRobinsonMSFT deleted the uco-excep-priority2 branch March 2, 2026 16:30
steveisok added a commit that referenced this pull request Mar 6, 2026
…124854)
First set of priority 3 conversions from #123864 — replace
`MethodDescCallSite`/`CallDescrWorker` calls with `UnmanagedCallersOnly`
reverse P/Invoke calls.
## Converted call sites
| File | Call site | Method |
|------|-----------|--------|
| `appdomain.cpp` | `AppDomain::RaiseExitProcessEvent` |
`ON_PROCESS_EXIT` |
| `appdomain.cpp` | `AppDomain::OnUnhandledException` |
`ON_UNHANDLED_EXCEPTION` |
| `assembly.cpp` | `RunManagedStartup` | `MANAGED_STARTUP` |
| `assembly.cpp` | `RunMainInternal` (TARGET_BROWSER) |
`HANDLE_ASYNC_ENTRYPOINT` |
| `invokeutil.cpp` | `InvokeUtil::CreateClassLoadExcept` |
`ReflectionTypeLoadException` ctor |
| `invokeutil.cpp` | `InvokeUtil::CreateTargetExcept` |
`TargetInvocationException` ctor |
## Remaining priority 3 items (follow ups)
- Main entry point in `RunMainInternal` (dynamic MethodDesc)
- `CustomAttribute_CreateCustomAttributeInstance` (dynamic ctor, already
a QCall)
- `CorHost2::ExecuteAssembly` (dynamic method lookup)
- `FuncEvalWrapper`/`DoNormalFuncEval` (debugger func-eval)
## Pattern
Follows the same conversion pattern as #124834 (priority 2). Each
conversion adds an `[UnmanagedCallersOnly]` managed wrapper with an
`Exception*` out-parameter and replaces the native `MethodDescCallSite`
+ `ARG_SLOT` with
`UnmanagedCallersOnlyCaller::InvokeThrowing`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 2, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@AaronRobinsonMSFT@jkoritzinsky@jkotas