From ec7905dbbc8dc37d1bc3b724022d208eff641192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sat, 13 Dec 2025 14:19:24 +0100 Subject: [PATCH 1/6] Enable runtime async for native AOT testing --- .../System.Private.CoreLib/src/System.Private.CoreLib.csproj | 4 ++++ src/libraries/Directory.Build.props | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index a0626491c415f3..b0396a3dffb083 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -1,4 +1,8 @@  + + $(Features);runtime-async=on + + true diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 33938989e386de..9ea656dc04e28f 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -101,4 +101,9 @@ + + $(Features);runtime-async=on + $(NoWarn);xUnit1013;CS1998;SYSLIB5007 + + From e4dd562394601fc2e06a42239c75ac3142eadb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sat, 13 Dec 2025 06:14:24 -0800 Subject: [PATCH 2/6] Update Directory.Build.props --- src/libraries/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 9ea656dc04e28f..b9d16b1d2e777a 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -101,7 +101,7 @@ - + $(Features);runtime-async=on $(NoWarn);xUnit1013;CS1998;SYSLIB5007 From fd5b7c58cb72d97e60d38665e9448cce59952dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 15 Dec 2025 14:51:55 +0100 Subject: [PATCH 3/6] Some hijacking changes --- .../nativeaot/Runtime/amd64/AsmMacros.inc | 1 + src/coreclr/nativeaot/Runtime/amd64/GcProbe.S | 34 ++++++++++++------ .../nativeaot/Runtime/amd64/GcProbe.asm | 35 ++++++++++--------- .../Runtime/unix/unixasmmacrosamd64.inc | 1 + 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc b/src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc index d8ac587710f878..37e1f6d000dfcb 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc +++ b/src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc @@ -358,6 +358,7 @@ PTFF_SAVE_R15 equ 00000080h PTFF_SAVE_ALL_PRESERVED equ 000000F7h ;; NOTE: RBP is not included in this set! PTFF_SAVE_RSP equ 00008000h PTFF_SAVE_RAX equ 00000100h ;; RAX is saved in hijack handler - in case it contains a GC ref +PTFF_SAVE_RCX equ 00000200h ;; RCX is saved in hijack handler - in case it contains a GC ref PTFF_SAVE_ALL_SCRATCH equ 00007F00h PTFF_THREAD_HIJACK equ 00100000h ;; indicates that this is a frame for a hijacked call diff --git a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S index a41ad4752a6dfa..f5ecb93ca8025f 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S +++ b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S @@ -6,7 +6,7 @@ #include // -// See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves RAX/RDX and accepts the register +// See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves RAX/RCX/RDX and accepts the register // bitmask in RCX // // On entry: @@ -19,6 +19,7 @@ // - All preserved registers remain unchanged from their values in managed code. // .macro PUSH_PROBE_FRAME threadReg, trashReg, BITMASK + push_register rcx // save RCX, it might contain an objectref (async continuation) push_register rdx // save RDX, it might contain an objectref push_register rax // save RAX, it might contain an objectref lea \trashReg, [rsp + 0x18] @@ -36,7 +37,7 @@ lea \trashReg, [rsp + 0] // trashReg == address of frame // allocate space for xmm0, xmm1 and alignment - alloc_stack 0x28 + alloc_stack 0x20 // save xmm0 and xmm1 in case they are used as return values movdqa [rsp + 0x10], xmm0 @@ -53,7 +54,7 @@ .macro POP_PROBE_FRAME movdqa xmm1, [rsp + 0] movdqa xmm0, [rsp + 0x10] - add rsp, 0x28 + 8 // skip xmm0, xmm1 and discard RIP + add rsp, 0x20 + 8 // skip xmm0, xmm1 and discard RIP pop rbp pop rax // discard Thread* pop rax // discard BITMASK @@ -65,6 +66,7 @@ pop rax // discard caller RSP pop rax pop rdx + pop rcx .endm // @@ -76,28 +78,38 @@ // // Register state on exit: // R11: thread pointer -// RAX, RDX preserved, other volatile regs trashed +// RAX, RCX, RDX preserved, other volatile regs trashed // .macro FixupHijackedCallstack // preserve RAX, RDX as they may contain return values push rax push rdx + // preserve RCX as it may contain async continuation return value + push rcx + + // align stack + sub rsp, 0x8 + // rax = GetThread(), makes nested calls INLINE_GETTHREAD mov r11, rax + add rsp, 0x8 + + pop rcx + pop rdx pop rax // Fix the stack by pushing the original return address - mov rcx, [r11 + OFFSETOF__Thread__m_pvHijackedReturnAddress] - push rcx + mov r8, [r11 + OFFSETOF__Thread__m_pvHijackedReturnAddress] + push r8 // Clear hijack state - xor ecx, ecx - mov [r11 + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation], rcx - mov [r11 + OFFSETOF__Thread__m_pvHijackedReturnAddress], rcx + xor r8, r8 + mov [r11 + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation], r8 + mov [r11 + OFFSETOF__Thread__m_pvHijackedReturnAddress], r8 .endm // @@ -112,12 +124,12 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT, NoHandler ret LOCAL_LABEL(WaitForGC): - mov ecx, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RDX + PTFF_THREAD_HIJACK + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + PTFF_SAVE_RDX + PTFF_THREAD_HIJACK jmp C_FUNC(RhpWaitForGC) NESTED_END RhpGcProbeHijack, _TEXT NESTED_ENTRY RhpWaitForGC, _TEXT, NoHandler - PUSH_PROBE_FRAME r11, rax, rcx + PUSH_PROBE_FRAME r11, rax, r8 END_PROLOGUE mov rbx, r11 diff --git a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm index 3b11a832e9db45..4f2733cdd410de 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm +++ b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm @@ -4,12 +4,13 @@ include AsmMacros.inc ;; -;; See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves RAX and accepts +;; See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves RAX/RCX and accepts ;; the register bitmask ;; ;; On entry: ;; - BITMASK: bitmask describing pushes, a volatile register ;; - RAX: managed function return value, may be an object or byref +;; - RCX: managed function return value (async continuation), may be an object ;; - preserved regs: need to stay preserved, may contain objects or byrefs ;; ;; INVARIANTS @@ -18,6 +19,7 @@ include AsmMacros.inc ;; PUSH_PROBE_FRAME macro threadReg, trashReg, BITMASK + push_vol_reg rcx ; save RCX, it might contain an objectref (async continuation) push_vol_reg rax ; save RAX, it might contain an objectref lea trashReg, [rsp + 10h] push_vol_reg trashReg ; save caller's RSP @@ -36,7 +38,7 @@ PUSH_PROBE_FRAME macro threadReg, trashReg, BITMASK lea trashReg, [rsp + 0] ; trashReg == address of frame ;; allocate scratch space and any required alignment - alloc_stack 20h + 10h + alloc_stack 20h + 8h ;; save xmm0 in case it's being used as a return value movdqa [rsp + 20h], xmm0 @@ -52,7 +54,7 @@ endm ;; POP_PROBE_FRAME macro movdqa xmm0, [rsp + 20h] - add rsp, 20h + 10h + 8 ; deallocate stack and discard saved m_RIP + add rsp, 20h + 8 + 8 ; deallocate stack and discard saved m_RIP pop rbp pop rax ; discard Thread* pop rax ; discard BITMASK @@ -65,6 +67,7 @@ POP_PROBE_FRAME macro pop r15 pop rax ; discard caller RSP pop rax + pop rcx endm ;; @@ -76,20 +79,20 @@ endm ;; ;; Register state on exit: ;; RDX: thread pointer -;; RAX: preserved, other volatile regs trashed +;; RAX/RCX: preserved, other volatile regs trashed ;; FixupHijackedCallstack macro - ;; rdx <- GetThread(), TRASHES rcx - INLINE_GETTHREAD rdx, rcx + ;; rdx <- GetThread(), TRASHES r8 + INLINE_GETTHREAD rdx, r8 ;; Fix the stack by pushing the original return address - mov rcx, [rdx + OFFSETOF__Thread__m_pvHijackedReturnAddress] - push rcx + mov r8, [rdx + OFFSETOF__Thread__m_pvHijackedReturnAddress] + push r8 ;; Clear hijack state - xor ecx, ecx - mov [rdx + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation], rcx - mov [rdx + OFFSETOF__Thread__m_pvHijackedReturnAddress], rcx + xor r8, r8 + mov [rdx + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation], r8 + mov [rdx + OFFSETOF__Thread__m_pvHijackedReturnAddress], r8 endm ;; @@ -103,12 +106,12 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT jnz @f ret @@: - mov ecx, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_THREAD_HIJACK + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + PTFF_THREAD_HIJACK jmp RhpWaitForGC NESTED_END RhpGcProbeHijack, _TEXT NESTED_ENTRY RhpWaitForGC, _TEXT - PUSH_PROBE_FRAME rdx, rax, rcx + PUSH_PROBE_FRAME rdx, rax, r8 END_PROLOGUE mov rbx, rdx @@ -144,7 +147,7 @@ ifdef FEATURE_GC_STRESS ;; LEAF_ENTRY RhpGcStressHijack, _TEXT FixupHijackedCallstack - or ecx, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX jmp RhpGcStressProbe LEAF_END RhpGcStressHijack, _TEXT @@ -158,11 +161,11 @@ LEAF_END RhpGcStressHijack, _TEXT ;; RCX: register bitmask ;; ;; Register state on exit: -;; Scratch registers, except for RAX, have been trashed +;; Scratch registers, except for RAX/RCX, have been trashed ;; All other registers restored as they were when the hijack was first reached. ;; NESTED_ENTRY RhpGcStressProbe, _TEXT - PUSH_PROBE_FRAME rdx, rax, rcx + PUSH_PROBE_FRAME rdx, rax, r8 END_PROLOGUE call RhpStressGc diff --git a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc index c2b86f43423924..7138bfc4326fea 100644 --- a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc +++ b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc @@ -243,6 +243,7 @@ C_FUNC(\Name): #define PTFF_SAVE_ALL_PRESERVED 0x000000F1 // NOTE: RBP is not included in this set! #define PTFF_SAVE_RSP 0x00008000 #define PTFF_SAVE_RAX 0x00000100 // RAX is saved in hijack handler - in case it contains a GC ref +#define PTFF_SAVE_RCX 0x00000200 // RCX is saved in hijack handler - in case it contains a GC ref #define PTFF_SAVE_RDX 0x00000400 // RDX is saved in hijack handler - in case it contains a GC ref #define PTFF_SAVE_ALL_SCRATCH 0x00007F00 #define PTFF_THREAD_HIJACK 0x00100000 // indicates that this is a frame for a hijacked call From d537b2f01f3daf98029d79e5480722b53a5b43d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 15 Dec 2025 15:12:45 -0800 Subject: [PATCH 4/6] Apply suggestions from code review --- src/coreclr/nativeaot/Runtime/amd64/GcProbe.S | 2 +- src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S index f5ecb93ca8025f..3fc9d023b04b60 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S +++ b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S @@ -124,7 +124,7 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT, NoHandler ret LOCAL_LABEL(WaitForGC): - mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + PTFF_SAVE_RDX + PTFF_THREAD_HIJACK + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RDX + PTFF_THREAD_HIJACK jmp C_FUNC(RhpWaitForGC) NESTED_END RhpGcProbeHijack, _TEXT diff --git a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm index 4f2733cdd410de..68afabf248acf2 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm +++ b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm @@ -106,7 +106,7 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT jnz @f ret @@: - mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + PTFF_THREAD_HIJACK + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_THREAD_HIJACK jmp RhpWaitForGC NESTED_END RhpGcProbeHijack, _TEXT @@ -147,7 +147,7 @@ ifdef FEATURE_GC_STRESS ;; LEAF_ENTRY RhpGcStressHijack, _TEXT FixupHijackedCallstack - mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX jmp RhpGcStressProbe LEAF_END RhpGcStressHijack, _TEXT From 6c4f0bab92b34a60386018cd0e25faee766b252c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 16 Dec 2025 07:09:53 +0100 Subject: [PATCH 5/6] Try this --- src/coreclr/nativeaot/Runtime/amd64/GcProbe.S | 12 ++++++------ src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S index 3fc9d023b04b60..71b0b503af33e6 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S +++ b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.S @@ -19,10 +19,10 @@ // - All preserved registers remain unchanged from their values in managed code. // .macro PUSH_PROBE_FRAME threadReg, trashReg, BITMASK - push_register rcx // save RCX, it might contain an objectref (async continuation) push_register rdx // save RDX, it might contain an objectref + push_register rcx // save RCX, it might contain an objectref (async continuation) push_register rax // save RAX, it might contain an objectref - lea \trashReg, [rsp + 0x18] + lea \trashReg, [rsp + 0x20] push_register \trashReg // save caller`s RSP push_nonvol_reg r15 // save preserved registers push_nonvol_reg r14 // .. @@ -32,12 +32,12 @@ push_register \BITMASK // save the register bitmask passed in by caller push_register \threadReg // Thread * (unused by stackwalker) push_nonvol_reg rbp // save caller`s RBP - mov \trashReg, [rsp + 11*8] // Find the return address + mov \trashReg, [rsp + 12*8] // Find the return address push_register \trashReg // save m_RIP lea \trashReg, [rsp + 0] // trashReg == address of frame // allocate space for xmm0, xmm1 and alignment - alloc_stack 0x20 + alloc_stack 0x20 + 0 // save xmm0 and xmm1 in case they are used as return values movdqa [rsp + 0x10], xmm0 @@ -65,8 +65,8 @@ pop r15 pop rax // discard caller RSP pop rax - pop rdx pop rcx + pop rdx .endm // @@ -124,7 +124,7 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT, NoHandler ret LOCAL_LABEL(WaitForGC): - mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RDX + PTFF_THREAD_HIJACK + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + PTFF_SAVE_RDX + PTFF_THREAD_HIJACK jmp C_FUNC(RhpWaitForGC) NESTED_END RhpGcProbeHijack, _TEXT diff --git a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm index 68afabf248acf2..3088c75071e749 100644 --- a/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm +++ b/src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm @@ -21,7 +21,7 @@ PUSH_PROBE_FRAME macro threadReg, trashReg, BITMASK push_vol_reg rcx ; save RCX, it might contain an objectref (async continuation) push_vol_reg rax ; save RAX, it might contain an objectref - lea trashReg, [rsp + 10h] + lea trashReg, [rsp + 18h] push_vol_reg trashReg ; save caller's RSP push_nonvol_reg r15 ; save preserved registers push_nonvol_reg r14 ; .. @@ -33,12 +33,12 @@ PUSH_PROBE_FRAME macro threadReg, trashReg, BITMASK push_vol_reg BITMASK ; save the register bitmask passed in by caller push_vol_reg threadReg ; Thread * (unused by stackwalker) push_nonvol_reg rbp ; save caller's RBP - mov trashReg, [rsp + 12*8] ; Find the return address + mov trashReg, [rsp + 13*8] ; Find the return address push_vol_reg trashReg ; save m_RIP lea trashReg, [rsp + 0] ; trashReg == address of frame ;; allocate scratch space and any required alignment - alloc_stack 20h + 8h + alloc_stack 20h + 10h + 8 ;; save xmm0 in case it's being used as a return value movdqa [rsp + 20h], xmm0 @@ -54,7 +54,7 @@ endm ;; POP_PROBE_FRAME macro movdqa xmm0, [rsp + 20h] - add rsp, 20h + 8 + 8 ; deallocate stack and discard saved m_RIP + add rsp, 20h + 10h + 8 + 8 ; deallocate stack and discard saved m_RIP pop rbp pop rax ; discard Thread* pop rax ; discard BITMASK @@ -106,7 +106,7 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT jnz @f ret @@: - mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_THREAD_HIJACK + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX + PTFF_THREAD_HIJACK jmp RhpWaitForGC NESTED_END RhpGcProbeHijack, _TEXT @@ -147,7 +147,7 @@ ifdef FEATURE_GC_STRESS ;; LEAF_ENTRY RhpGcStressHijack, _TEXT FixupHijackedCallstack - mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX jmp RhpGcStressProbe LEAF_END RhpGcStressHijack, _TEXT From 2b0fdbb52a1329cc1c170e75734995bbaec7e82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 16 Dec 2025 21:30:15 -0800 Subject: [PATCH 6/6] Convert to async variant target --- .../Compiler/Dataflow/CompilerGeneratedState.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs index 84325bd9058439..400b643abf53cc 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs @@ -737,6 +737,10 @@ public bool TryGetUserMethodForCompilerGeneratedMember(TypeSystemEntity sourceMe if (sourceMember == null) return false; + Debug.Assert(sourceMember is not MethodDesc sourceMethod || sourceMethod.IsTypicalMethodDefinition); + if (sourceMember is AsyncMethodVariant asyncVariant) + sourceMember = asyncVariant.Target; + TypeSystemEntity member = sourceMember; MethodDesc? userMethodCandidate; while (TryGetOwningMethodForCompilerGeneratedMember(member, out userMethodCandidate))