Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Split up loader heap implementations - #114246

Merged
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations
Apr 12, 2025
Merged

Split up loader heap implementations#114246
davidwrighton merged 19 commits into
dotnet:mainfrom
davidwrighton:split_up_loader_heap_implementations

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Apr 3, 2025

Copy link
Copy Markdown
Member

We have long had 3 rather different heaps embedded in one structure called a LoaderHeap. They have shared ... some infrastructure, but there is a mess of confusing flags and code paths which only work for one or the other type of heap.

This PR changes that to supporting the 3 different types of heaps with separate codebases, and keeps as much of the shared infrastructure as I could manage. Its, not what I would call a pretty separation, as there is a bit of a mess around the way the DAC apis can access the heaps, but I think this is an improvement. Notably, in a followon PR I'm intending to provide a new mechanism for the interleaved heap to work off of contents of a file instead of creating unique pages per stub block. (This should slighly improve the cache locality of .NET programs, and is a prerequisite for running on some heavily locked down platforms.) This PR prepares for that by making the Interleaved heap its own thing, so adding new behavior variants is a reviewable piece of work.

The only functional change that happens with this PR is the newly added capability of the interleaved heaps to support freeing memory. (It was always possible to free, but for some reason the re-allocation behavior was not actually supported.)

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton changed the title [DRAFT] Split up loader heap implementationsSplit up loader heap implementationsApr 8, 2025
@davidwrighton
davidwrighton marked this pull request as ready for review April 8, 2025 21:57
CopilotAI review requested due to automatic review settings April 8, 2025 21:57

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.

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/coreclr/utilcode/CMakeLists.txt: Language not supported

Comment threadsrc/coreclr/vm/loaderallocator.hpp Outdated
Comment threadsrc/coreclr/utilcode/loaderheap_shared.cpp
Comment on lines +316 to +318
"\nset the following registry DWORD value:"
"\n"
"\n HKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"

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.

Suggested change
"\nset the following registry DWORD value:"
"\n"
"\nHKLM\\Software\\Microsoft\\.NETFramework\\LoaderHeapCallTracing = 1"
"\nset the following environment variable:"
"\n"
"\nDOTNET_LoaderHeapCallTracing=1"

@davidwrighton

Copy link
Copy Markdown
MemberAuthor

/ba-g the failing test is unrelated to this change and was fixed by Michal earlier today.

@am11

am11 commented Apr 10, 2025

Copy link
Copy Markdown
Member

Copilot spotted a typo #114246 (comment).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@janvorlijanvorli 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, thank you!

// and notify the user to provide more reserved mem.
_ASSERTE((dwSizeToCommit <= dwSizeToReserve) && "Loaderheap tried to commit more memory than reserved by user");

if (!fReleaseMemory)

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.

The fReleaseMemory is always set to TRUE at this point.

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'll fix that. Thanks.


INDEBUG(m_dwDebugWastedBytes += unusedRemainder;)

// For interleaved heaps, further allocations will start from the newly committed page as they cannot

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.

A nit - maybe remove the "For interleaved heap, " from multiple comments here, that was only usefull originally when the code for interleaved heaps stuff was intertwined with the other code.

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'll need to revisit these comments with the page remapping logic in my next PR. I'll address this then.

//
// Caller is responsible for synchronization. ExplicitControlLoaderHeap is
// not multithread safe.
// The LoaderHeap is the black-box heap and has a Backout() method but none

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.

This comment does not match InterleavedLoaderHeap


protected:
void *UnlockedAllocMemForCode_NoThrow(size_t dwHeaderSize, size_t dwCodeSize, DWORD dwCodeAlignment, size_t dwReserveForJumpStubs);
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by UnlockAllocMem. It's given this horrible name to emphasize
// This frees memory allocated by UnlockedAllocStub. It's given this horrible name to emphasize

void SetReservedRegion(BYTE* dwReservedRegionAddress, SIZE_T dwReservedRegionSize, BOOL fReleaseMemory)

public:
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize

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.

Suggested change
// This frees memory allocated by AllocMem. It's given this horrible name to emphasize
// This frees memory allocated by AllocStub. It's given this horrible name to emphasize

#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"

#ifndef DACCESS_COMPILE

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.

Move the file to (non-DAC) UTILCODE_SOURCES in CMakeLists.txt instead of end-to-end ifdef

m_codePageGenerator = codePageGenerator;
}

// ~LoaderHeap is not synchronised (obviously)

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.

Suggested change
// ~LoaderHeap is not synchronised (obviously)


size_t dwSize = dwRequestedSize;

// Interleaved heap cannot ad any extra to the requested size

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.

Suggested change
// Interleaved heap cannot ad any extra to the requested size

@davidwrighton
davidwrighton merged commit e6f38d7 into dotnet:mainApr 12, 2025
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 13, 2025
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.

5 participants

@davidwrighton@am11@jkotas@janvorli