') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); JIT: Enable implicit tailcalls for tail-awaits by jakobbotsch · Pull Request #129255 · dotnet/runtime · GitHub
Skip to content

JIT: Enable implicit tailcalls for tail-awaits - #129255

Merged
jakobbotsch merged 7 commits into
dotnet:mainfrom
jakobbotsch:real-tailcall-for-tailawaits
Jul 1, 2026
Merged

JIT: Enable implicit tailcalls for tail-awaits#129255
jakobbotsch merged 7 commits into
dotnet:mainfrom
jakobbotsch:real-tailcall-for-tailawaits

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Jun 10, 2026

Copy link
Copy Markdown
Member

We disabled tailcalls from async methods when we added the context restore logic, but now that have and use tail-awaits we can reenable implicit tailcalls for those cases.

Example:

privatestaticTaskFoo(boolb){returnb?Bar():Baz();}[MethodImpl(MethodImplOptions.NoInlining)]privatestaticasyncTaskBar(){}[MethodImpl(MethodImplOptions.NoInlining)]privatestaticasyncTaskBaz(){}
 G_M15357_IG01:
- sub rsp, 40- ;; size=4 bbWeight=1 PerfScore 0.25+ ;; size=0 bbWeight=1 PerfScore 0.00
G_M15357_IG02:
test dl, dl
- je SHORT G_M15357_IG04+ je SHORT G_M15357_IG05
;; size=4 bbWeight=1 PerfScore 1.25
G_M15357_IG03:
xor rcx, rcx
- call [Program:Bar()]- test rcx, rcx- jne SHORT G_M15357_IG09- jmp SHORT G_M15357_IG05- ;; size=15 bbWeight=0.50 PerfScore 3.25+ ;; size=2 bbWeight=0.50 PerfScore 0.12
G_M15357_IG04:
- xor rcx, rcx- call [Program:Baz()]- test rcx, rcx- jne SHORT G_M15357_IG08- ;; size=13 bbWeight=0.50 PerfScore 2.25+ tail.jmp [Program:Bar()]+ ;; size=6 bbWeight=0.50 PerfScore 1.00
G_M15357_IG05:
- xor ecx, ecx- ;; size=2 bbWeight=1 PerfScore 0.25+ xor rcx, rcx+ ;; size=2 bbWeight=0.50 PerfScore 0.12
G_M15357_IG06:
- add rsp, 40- ret - ;; size=5 bbWeight=1 PerfScore 1.25-G_M15357_IG07:- add rsp, 40- ret - ;; size=5 bbWeight=0 PerfScore 0.00-G_M15357_IG08:- jmp SHORT G_M15357_IG07- ;; size=2 bbWeight=0 PerfScore 0.00-G_M15357_IG09:- jmp SHORT G_M15357_IG07- ;; size=2 bbWeight=0 PerfScore 0.00+ tail.jmp [Program:Baz()]+ ;; size=6 bbWeight=0.50 PerfScore 1.00-; Total bytes of code 52, prolog size 4, PerfScore 8.50, instruction count 19, allocated bytes for code 52 (MethodHash=2415c402) for method Program:Foo(bool) (FullOpts)+; Total bytes of code 20, prolog size 0, PerfScore 3.50, instruction count 6, allocated bytes for code 20 (MethodHash=2415c402) for method Program:Foo(bool) (FullOpts)
; ============================================================

We disabled tailcalls from async methods when we added the context
restore, but now that have and use tail-awaits we can reenable implicit
tailcalls for those cases. That will also benefit async versions once
that PR merges.
CopilotAI review requested due to automatic review settings June 10, 2026 18:49
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jun 10, 2026

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 change adjusts JIT tailcall eligibility for async methods: instead of blanket-disabling tailcalls from async methods, it allows implicit tailcalls only when the call is a tail await, while continuing to disqualify all other tailcall candidates from async methods.

Changes:

  • Removed the early “caller is async method” tailcall disqualification.
  • Added a late-stage tailcall eligibility check that permits tailcalls from async methods only for calls marked as async + IsTailAwait.

Comment threadsrc/coreclr/jit/importercalls.cpp Outdated
Comment threadsrc/coreclr/jit/importercalls.cpp
CopilotAI review requested due to automatic review settings June 26, 2026 13:58

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 1 out of 1 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/jit/importercalls.cpp
Comment threadsrc/coreclr/jit/importercalls.cpp
CopilotAI review requested due to automatic review settings June 26, 2026 16:10

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 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadsrc/coreclr/jit/importer.cpp
CopilotAI review requested due to automatic review settings June 29, 2026 15:13

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 2 out of 2 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/jit/importer.cpp
Comment threadsrc/coreclr/jit/importercalls.cpp
@jakobbotsch
jakobbotsch marked this pull request as ready for review June 29, 2026 17:49
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @EgorBo

Diffs. Real diffs should be larger, just that we see a significant number of misses due to canTailCall.

@jakobbotsch
jakobbotsch requested a review from EgorBoJune 29, 2026 17:51
@jakobbotsch
jakobbotsch merged commit 334e58b into dotnet:mainJul 1, 2026
137 checks passed
@jakobbotsch
jakobbotsch deleted the real-tailcall-for-tailawaits branch July 1, 2026 11:08
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 2, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
We disabled tailcalls from async methods when we added the context
restore logic, but now that have and use tail-awaits we can reenable
implicit tailcalls for those cases.
Example:
```csharp
private static Task Foo(bool b)
{
return b ? Bar() : Baz();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static async Task Bar()
{
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static async Task Baz()
{
}
```
```diff
G_M15357_IG01:
- sub rsp, 40
- ;; size=4 bbWeight=1 PerfScore 0.25
+ ;; size=0 bbWeight=1 PerfScore 0.00
G_M15357_IG02:
test dl, dl
- je SHORT G_M15357_IG04
+ je SHORT G_M15357_IG05
;; size=4 bbWeight=1 PerfScore 1.25
G_M15357_IG03:
xor rcx, rcx
- call [Program:Bar()]
- test rcx, rcx
- jne SHORT G_M15357_IG09
- jmp SHORT G_M15357_IG05
- ;; size=15 bbWeight=0.50 PerfScore 3.25
+ ;; size=2 bbWeight=0.50 PerfScore 0.12
G_M15357_IG04:
- xor rcx, rcx
- call [Program:Baz()]
- test rcx, rcx
- jne SHORT G_M15357_IG08
- ;; size=13 bbWeight=0.50 PerfScore 2.25
+ tail.jmp [Program:Bar()]
+ ;; size=6 bbWeight=0.50 PerfScore 1.00
G_M15357_IG05:
- xor ecx, ecx
- ;; size=2 bbWeight=1 PerfScore 0.25
+ xor rcx, rcx
+ ;; size=2 bbWeight=0.50 PerfScore 0.12
G_M15357_IG06:
- add rsp, 40
- ret - ;; size=5 bbWeight=1 PerfScore 1.25
-G_M15357_IG07:
- add rsp, 40
- ret - ;; size=5 bbWeight=0 PerfScore 0.00
-G_M15357_IG08:
- jmp SHORT G_M15357_IG07
- ;; size=2 bbWeight=0 PerfScore 0.00
-G_M15357_IG09:
- jmp SHORT G_M15357_IG07
- ;; size=2 bbWeight=0 PerfScore 0.00
+ tail.jmp [Program:Baz()]
+ ;; size=6 bbWeight=0.50 PerfScore 1.00
-; Total bytes of code 52, prolog size 4, PerfScore 8.50, instruction count 19, allocated bytes for code 52 (MethodHash=2415c402) for method Program:Foo(bool) (FullOpts)
+; Total bytes of code 20, prolog size 0, PerfScore 3.50, instruction count 6, allocated bytes for code 20 (MethodHash=2415c402) for method Program:Foo(bool) (FullOpts)
; ============================================================
```
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 1, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIruntime-async

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jakobbotsch@EgorBo@am11