') + ')', '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: Fix for IV opt to preserve updates to a counter that is live into an EH handler by JulieLeeMSFT · Pull Request #129058 · dotnet/runtime · GitHub
Skip to content

JIT: Fix for IV opt to preserve updates to a counter that is live into an EH handler - #129058

Merged
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:fix-jit-128392-iv-eh-liveness
Jun 19, 2026
Merged

JIT: Fix for IV opt to preserve updates to a counter that is live into an EH handler#129058
JulieLeeMSFT merged 4 commits into
dotnet:mainfrom
JulieLeeMSFT:fix-jit-128392-iv-eh-liveness

Conversation

@JulieLeeMSFT

Copy link
Copy Markdown
Member

optLocalHasNonLoopUses relied on lvDoNotEnregister to detect locals live into exceptional exits. PR #127932 decoupled DNER from liveness (DNER is now set during LSRA/lowering, after optInductionVariables runs), so an induction variable live into a catch handler was no longer detected and its in-loop self-update was removed by optRemoveUnusedIVs, producing wrong results under full-opt codegen (crossgen2, jitstress, AggressiveOptimization).

Add an explicit lvTracked && IsLiveInOutOfHandler() check, since VisitRegularExitBlocks deliberately excludes handler blocks.

Fixes#128392.

…handlers
optLocalHasNonLoopUses relied on lvDoNotEnregister to detect locals live
into exceptional exits. PR dotnet#127932 decoupled DNER from liveness (DNER is
now set during LSRA/lowering, after optInductionVariables runs), so an
induction variable live into a catch handler was no longer detected and
its in-loop self-update was removed by optRemoveUnusedIVs, producing wrong
results under full-opt codegen (crossgen2, jitstress, AggressiveOptimization).
Add an explicit lvTracked && IsLiveInOutOfHandler() check, since
VisitRegularExitBlocks deliberately excludes handler blocks. Update two
stale comments referencing the old DNER behavior.
Fixesdotnet#128392.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 5, 2026 21:59
@github-actionsgithub-actionsBot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jun 5, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@JulieLeeMSFTJulieLeeMSFT added this to the 11.0.0 milestone Jun 5, 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 PR fixes a correctness hole in CoreCLR JIT induction-variable optimizations where a loop IV update could be removed even though the IV is live into an EH handler (e.g., used by a catch). The change makes optLocalHasNonLoopUses explicitly treat “live into handler” as a non-loop use, preventing optRemoveUnusedIVs from dropping the in-loop update.

Changes:

  • Update optLocalHasNonLoopUses to conservatively return true when a tracked local is IsLiveInOutOfHandler().
  • Adjust a comment in IV widening logic to reflect that exceptional-exit-live IVs are not profitable candidates (rather than relying on DNER being set).
  • Add a JIT regression test (Runtime_128392) and include it in the regression csproj.

Reviewed changes

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

FileDescription
src/coreclr/jit/inductionvariableopts.cppAdds an explicit EH-handler liveness check in optLocalHasNonLoopUses to avoid removing IV updates that are observable via exceptional control flow.
src/tests/JIT/Regression/JitBlue/Runtime_128392/Runtime_128392.csNew xUnit regression covering an IV read in a catch after an exception thrown mid-loop.
src/tests/JIT/Regression/Regression_ro_2.csprojIncludes the new regression test source file in the build.

@JulieLeeMSFTJulieLeeMSFT changed the title IV opt preserves updates to a counter that is live into an EH handlerJIT: IV opt preserves updates to a counter that is live into an EH handlerJun 5, 2026
@JulieLeeMSFTJulieLeeMSFT changed the title JIT: IV opt preserves updates to a counter that is live into an EH handlerJIT: Fix for IV opt to preserve updates to a counter that is live into an EH handlerJun 5, 2026
@AndyAyersMS

Copy link
Copy Markdown
Member

Is this 11.0 or 10.0?

@jakobbotsch

Copy link
Copy Markdown
Member

Is this 11.0 or 10.0?

This is a regression from #127932

Comment threadsrc/coreclr/jit/inductionvariableopts.cpp Outdated
Comment threadsrc/coreclr/jit/inductionvariableopts.cpp Outdated
@jakobbotsch

Copy link
Copy Markdown
Member

Can you introduce a similar assert as

#ifdef DEBUG
// We currently do not expect to ever widen IVs that are live into
// exceptional exits. Such IVs are not currently register candidates (EH
// write-thru is only for single def locals) which makes it unprofitable.
// If this ever changes we need some more expansive handling here.
loop->VisitLoopBlocks([=](BasicBlock* block) {
block->VisitAllSuccs(this, [=](BasicBlock* succ) {
if (!loop->ContainsBlock(succ) && bbIsHandlerBeg(succ))
{
assert(!optLocalIsLiveIntoBlock(lclNum, succ) &&
"Candidate IV for widening is live into exceptional exit");
}
return BasicBlockVisit::Continue;
});
return BasicBlockVisit::Continue;
});
#endif

at the end of optLocalHasNonLoopUses?

Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
CopilotAI review requested due to automatic review settings June 8, 2026 20:31

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

@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

#ifdef DEBUG
// We currently do not expect to ever widen IVs that are live into
// exceptional exits. Such IVs are not currently register candidates (EH
// write-thru is only for single def locals) which makes it unprofitable.
// If this ever changes we need some more expansive handling here.
loop->VisitLoopBlocks([=](BasicBlock* block) {
block->VisitAllSuccs(this, [=](BasicBlock* succ) {
if (!loop->ContainsBlock(succ) && bbIsHandlerBeg(succ))
{
assert(!optLocalIsLiveIntoBlock(lclNum, succ) &&
"Candidate IV for widening is live into exceptional exit");
}

 return BasicBlockVisit::Continue; }); return BasicBlockVisit::Continue; }); 

#endif

@copilot, please add this code to the end of optLocalHasNonLoopUses before return false;.

…assert for EH-live IVs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch, it's ready for review.
cc @dotnet/jit-contrib.

CopilotAI review requested due to automatic review settings June 19, 2026 08:57

@jakobbotschjakobbotsch 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.

Code LGTM, just pushed a rephrasing of the comment. Thanks!

@jakobbotsch

Copy link
Copy Markdown
Member

@dotnet/jit-contrib Since I pushed a comment update my review is not sufficient. Can someone else also approve?

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

Comment threadsrc/coreclr/jit/inductionvariableopts.cpp
@JulieLeeMSFT

Copy link
Copy Markdown
MemberAuthor

/ba-g tracing/userevents/custommetadata test failure is unrelated.

@JulieLeeMSFT
JulieLeeMSFT merged commit 44baabb into dotnet:mainJun 19, 2026
141 of 145 checks passed
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
…o an EH handler (#129058)
`optLocalHasNonLoopUses` relied on `lvDoNotEnregister` to detect locals
live into exceptional exits. PR #127932 decoupled DNER from liveness
(DNER is now set during LSRA/lowering, after `optInductionVariables`
runs), so an induction variable live into a catch handler was no longer
detected and its in-loop self-update was removed by
`optRemoveUnusedIVs`, producing wrong results under full-opt codegen
(crossgen2, jitstress, AggressiveOptimization).
Add an explicit `lvTracked && IsLiveInOutOfHandler()` check, since
`VisitRegularExitBlocks` deliberately excludes handler blocks.
Fixes#128392.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
ManickaP pushed a commit to ManickaP/runtime that referenced this pull request Jul 22, 2026
…o an EH handler (dotnet#129058)
`optLocalHasNonLoopUses` relied on `lvDoNotEnregister` to detect locals
live into exceptional exits. PR dotnet#127932 decoupled DNER from liveness
(DNER is now set during LSRA/lowering, after `optInductionVariables`
runs), so an induction variable live into a catch handler was no longer
detected and its in-loop self-update was removed by
`optRemoveUnusedIVs`, producing wrong results under full-opt codegen
(crossgen2, jitstress, AggressiveOptimization).
Add an explicit `lvTracked && IsLiveInOutOfHandler()` check, since
`VisitRegularExitBlocks` deliberately excludes handler blocks.
Fixesdotnet#128392.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 23, 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 SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test failure: System.Security.Cryptography.X509Certificates.Tests.CollectionTests.X509Certificate2CollectionRemoveRangeArray

4 participants

@JulieLeeMSFT@AndyAyersMS@jakobbotsch