') + ')', '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); } })(); })(); Enable "Allocate on stack" for NAOT/R2R by EgorBo · Pull Request #104411 · dotnet/runtime · GitHub
Skip to content

Enable "Allocate on stack" for NAOT/R2R - #104411

Merged
EgorBo merged 21 commits into
dotnet:mainfrom
EgorBo:alloc-stack-naot
Jul 14, 2024
Merged

Enable "Allocate on stack" for NAOT/R2R#104411
EgorBo merged 21 commits into
dotnet:mainfrom
EgorBo:alloc-stack-naot

Conversation

@EgorBo

@EgorBoEgorBo commented Jul 4, 2024

Copy link
Copy Markdown
Member

Closes#104350
Fixes#104337
This PR adds NAOT/R2R support for #103361

Example:

staticintTest1(){MyClassobj=newMyClass(42);// MyClass allocation never escapesreturnobj.X;}staticintTest2(){objecto=42;// boxing (allocation)return(int)o;// unboxing}publicclassMyClass(intx){publicintX=>x;}

Old codegen for Test() on NAOT (and R2R):

; Assembly listing for method Proga:Test1():int (FullOpts); NativeAOT compilationsubrsp,40learcx,[(reloc 0x40000000004211a8)] ; MyClasscall CORINFO_HELP_NEWSFASTmov dword ptr [rax+0x08],42moveax, dword ptr [rax+0x08]addrsp,40ret; Assembly listing for method Proga:Test2():int (FullOpts); NativeAOT compilationsubrsp,40learcx,[(reloc 0x4000000000421008)] ; Int32call CORINFO_HELP_NEWSFASTmov dword ptr [rax+0x08],42moveax, dword ptr [rax+0x08]addrsp,40ret

New codegen:

; Assembly listing for method Proga:Test1():int (FullOpts); NativeAOT compilationmoveax,42ret; Assembly listing for method Proga:Test2():int (FullOpts); NativeAOT compilationmoveax,42ret

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 4, 2024
@ShreyasJejurkar

Copy link
Copy Markdown
Contributor

Is the .NET main branch broken on CE somehow? Checking the codegen for the example, yields older code.

https://godbolt.org/z/aveWzrfvv

image

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Is the .NET main branch broken on CE somehow? Checking the codegen for the example, yields older code.

#104442

@AndyAyersMS

Copy link
Copy Markdown
Member

I'm surprised that you don't need to do anything on the runtime side to implement CORINFO_HELP_UNBOX_TYPETEST.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

I'm surprised that you don't need to do anything on the runtime side to implement CORINFO_HELP_UNBOX_TYPETEST.

CI is currently failing with:

EXEC : error : One or more errors occurred. (Code generation failed for method '[Microsoft.Extensions.Logging.Configuration]Microsoft.Extensions.Configuration.Binder.SourceGeneration.<BindingExtensions_g>F7FD99DEF4D1E9898A126F6C62635605FA12A7F83D698AD1B212E573AF4334BC7__BindingExtensions.GetValue<bool>(IConfiguration,string,bool)') [D:\a\_work\1\s\artifacts\bin\aotTests\projects\Microsoft.Extensions.Logging.Console.TrimmingTests\JsonFormattingTests\win-x64\project.csproj]
##[error]EXEC(0,0): error : (NETCORE_ENGINEERING_TELEMETRY=Build) One or more errors occurred. (Code generation failed for method '[Microsoft.Extensions.Logging.Configuration]Microsoft.Extensions.Configuration.Binder.SourceGeneration.<BindingExtensions_g>F7FD99DEF4D1E9898A126F6C62635605FA12A7F83D698AD1B212E573AF4334BC7__BindingExtensions.GetValue<bool>(IConfiguration,string,bool)')
System.AggregateException: One or more errors occurred. (Code generation failed for method '[Microsoft.Extensions.Logging.Configuration]Microsoft.Extensions.Configuration.Binder.SourceGeneration.<BindingExtensions_g>F7FD99DEF4D1E9898A126F6C62635605FA12A7F83D698AD1B212E573AF4334BC7__BindingExtensions.GetValue<bool>(IConfiguration,string,bool)')
---> ILCompiler.CodeGenerationFailedException: Code generation failed for method '[Microsoft.Extensions.Logging.Configuration]Microsoft.Extensions.Configuration.Binder.SourceGeneration.<BindingExtensions_g>F7FD99DEF4D1E9898A126F6C62635605FA12A7F83D698AD1B212E573AF4334BC7__BindingExtensions.GetValue<bool>(IConfiguration,string,bool)'
---> System.NotImplementedException: CORINFO_HELP_UNBOX_TYPETEST
at Internal.JitInterface.CorInfoImpl.GetHelperFtnUncached(CorInfoHelpFunc) + 0xa60
at Internal.JitInterface.CorInfoImpl.getHelperFtn(CorInfoHelpFunc, Void*&) + 0x34

🙂

@EgorBoEgorBo added area-NativeAOT-coreclr and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 4, 2024
Comment threadsrc/coreclr/inc/corinfoinstructionset.h
@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@EgorBo
EgorBo marked this pull request as ready for review July 5, 2024 11:25
@github-actionsgithub-actionsBot mentioned this pull request Jul 5, 2024
@EgorBo

Copy link
Copy Markdown
MemberAuthor

I think this is ready, PTAL @jkotas@MichalStrehovsky@AndyAyersMS

Comment threadsrc/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs Outdated
for (int i = 0; i < ptrsCount; i++)
gcPtrs[i] = (byte)CorInfoGCType.TYPE_GC_NONE;
uint size = type.IsValueType ? getClassSize(cls) : getHeapClassSize(cls);
new Span<byte>(gcPtrs, (int)((size + PointerSize - 1) / PointerSize)).Clear();

@EgorBoEgorBoJul 5, 2024

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This was copied from CoreCLR impl, it does a similar memset (see this)

Previously, getClassGClayout used InstanceFieldSize.AsInt which for ref types always return just pointer-size while we need the real size. Since it has never been used for ref-types before, it wasn't an issue.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

Outerloops:

@MichalStrehovsky

Copy link
Copy Markdown
Member
  • also a weird AVE in System.Net.Sockets.Tests but it's not my PR specific

This is #104500.

Comment on lines +182 to +183
if (attribs.Length == 0)
return true; // Assume corelib is optimized in this case

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.

Adding <DebuggerSupport>true</DebuggerSupport> to the project file would make the attribute visible, but ILC has its own optimization switch so CoreLib having this attribute still doesn't necessarily imply how optimized it is.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

@MichalStrehovsky do we run runtime tests with NativeAOT in full debug mode?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

So can you tell me how to properly check it here?

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.

@MichalStrehovsky do we run runtime tests with NativeAOT in full debug mode?

We do have such legs, I'm not sure if they include this test too. It would be in the runtime or runtime-nativeaot-outerloop if it exists.

So can you tell me how to properly check it here?

Native AOT will use the same settings for optimizing both CoreLib and user code so enabling the attribute and looking for the attribute on Assembly.GetEntryAssembly would give the answer.

I guess I don't understand why this is looking at whether corelib is optimized. Why does that affect stack allocations in this test?

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.

I guess I don't understand why this is looking at whether corelib is optimized. Why does that affect stack allocations in this test?

Maybe the way we build the tests, optimization of CoreLib always matches optimization of the test?

If that's the case, all that's needed is to add <DebuggerSupport>true</DebuggerSupport> to the test project and this will work the same. It will also fail the same if there's ever mismatch between test optimization and corelib optimization.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I guess I don't understand why this is looking at whether corelib is optimized. Why does that affect stack allocations in this test?

I am not the original author (I presume the authors no longer work in the team), but looks like the test tries to be agile and validate that nothing is stack-allocated under debug maybe? 🤷

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.

I am not the original author (I presume the authors no longer work in the team), but looks like the test tries to be agile and validate that nothing is stack-allocated under debug maybe?

Right, but for that one would check whether the test is optimized, not corelib. One can build the test with <Optimize>true</Optimize> and have corelib from a debug build. I assume the test would fail in that case.

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.

(I mean in the JIT case. It would also fail in the AOT case because I believe the test is looking at the wrong assembly.)

@EgorBoEgorBoJul 13, 2024

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I ended up removing these bits and the test is still working fine (it's always optimized due to <Optimize>true</Optimize>)

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-coreclr runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@EgorBo

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@EgorBo

Copy link
Copy Markdown
MemberAuthor

@jkotas@MichalStrehovsky can this be merged then? All nativeaot-outerloop failures are either #104862 or #104500

Comment threadsrc/tests/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj Outdated
Comment threadsrc/tests/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj Outdated

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

LGTM otherwise. Thank you!

@EgorBo
EgorBo merged commit af5e715 into dotnet:mainJul 14, 2024
@EgorBo
EgorBo deleted the alloc-stack-naot branch July 14, 2024 23:12
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 14, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NativeAOT] Enable object stack allocation Test failure: JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests/ObjectStackAllocationTests.cmd

5 participants

@EgorBo@ShreyasJejurkar@AndyAyersMS@jkotas@MichalStrehovsky