Async Profiler: Emit the method's native code start address as the async-profiler V1 MethodID.#130420
Open
lateralusX wants to merge 7 commits into
Open
Conversation
Contributor
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR changes the async-profiler V1 (StateMachineAsync) “MethodId” from a managed method handle/pointer to the method’s native code start address, aligning it with how V2 (RuntimeAsync) and normal stack frames are symbolicated. It adds runtime primitives in both CoreCLR (QCall) and Mono (icall + runtime callback) to retrieve a method’s native code start and wires AsyncStateMachineDiagnostics.ResolveMethodId to use that value.
Changes:
- CoreCLR: add
RuntimeMethodHandle_GetNativeCodeQCall returningPCODE, with managed wrapper inRuntimeMethodHandle. - Mono: add
RuntimeMethodHandle.GetNativeCodeicall and a new runtime callback to locate a method’s native code start. - Shared CoreLib: update
AsyncStateMachineDiagnostics.ResolveMethodIdto return native code start forMoveNext.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncStateMachineDiagnostics.cs | Switch V1 method id resolution from method handle to native code start. |
| src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs | Add managed wrapper for the new CoreCLR QCall. |
| src/coreclr/vm/runtimehandles.h | Declare new RuntimeMethodHandle_GetNativeCode QCall entrypoint. |
| src/coreclr/vm/runtimehandles.cpp | Implement QCall logic to return native code start (including unboxing-stub handling). |
| src/coreclr/vm/qcallentrypoints.cpp | Register the new QCall entrypoint. |
| src/mono/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs | Add managed InternalCall/wrapper for Mono native code lookup. |
| src/mono/mono/metadata/object-internals.h | Add a new runtime callback for “method code start”. |
| src/mono/mono/mini/mini-runtime.c | Implement and install the callback using existing JIT/AOT/interp lookup logic. |
| src/mono/mono/metadata/icall.c | Implement ves_icall_RuntimeMethodHandle_GetNativeCode. |
| src/mono/mono/metadata/icall-def.h | Register the new RuntimeMethodHandle icall. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This was referenced Jul 9, 2026
This was referenced Jul 10, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
The async profiler's V1 (StateMachineAsync) path identifies each async frame by a method id. Until now
AsyncStateMachineDiagnostics.ResolveMethodIdemitted the state machine'sMoveNextMethodDesc/MonoMethodpointer as that id.That has two problems:
• Symbolication is fragile and divergent. A raw
MethodDescpointer is not an instruction pointer, so a trace consumer has to depend on EventPipe rundown events to do symbolication. That doesn't work cleanly cross-process/offline and doesn't match how any other frame gets symbolized (perfmap/ETW-EventPipe rundown/ProcessSymbol).• Inconsistent with V2. The V2 (RuntimeAsync) path already reports continuation native IPs, which symbolicate like ordinary frames. V1 should behave the same so a single resolution path covers both.
Change
Introduce a runtime primitive to retrieve the native code start address of a method and use it as the V1 method id. V1 frames now symbolicate uniformly as native IPs - exactly like V2 continuation IPs and regular stack frames - removing the special
MethodDesc-dereference path in consumers.CoreCLR
• New QCall
RuntimeMethodHandle_GetNativeCodereturningPCODE.• Managed
RuntimeMethodHandle.GetNativeCodeInternal(IRuntimeMethodInfo)wrapper.Mono
• New icall
RuntimeMethodHandle.GetNativeCodereturninggpointer.• Managed
RuntimeMethodHandle.GetNativeCodeInternal(IntPtr)wrapper.Shared
•
AsyncStateMachineDiagnostics.ResolveMethodIdnow returns the native code start ofMoveNextinstead ofMethodHandle.Value.All output from runtime related to internal symbol to native code mappings emits all versions of the method to the same symbol, so that means a tier0 address will still resolve to the same symbol even if a tier1 version outdates it, the same for a re-jitted method.
Testing
• Existing async-profiler V1 tests pass on CoreCLR and Mono.
• Validated end-to-end with custom perfview TraceEvent async-profiler parser.