Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1
, '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

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

CopilotAI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, constchar *stubType);
// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, constchar *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/stubmgr.hRemoves StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cppRoutes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.hChanges StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cppAllocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.hUpdates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cppPasses LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cppUpdates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hppRemoves m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cppRemoves stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.incDrops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.hUpdates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cppUpdates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.hAdds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.hUpdates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hppRemoves Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cppRemoves Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hppRemoves AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inlRemoves AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cppUpdates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment threadsrc/coreclr/debug/daccess/request.cpp
Comment threadsrc/coreclr/vm/comdelegate.cpp Outdated
Comment threadsrc/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Comment threadsrc/coreclr/vm/loaderallocator.cpp
Comment threadsrc/coreclr/debug/daccess/request.cpp Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
Comment threadsrc/coreclr/vm/codeman.h Outdated
…EAP_*
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:27
CopilotAI requested a review from jkotasAugust 5, 2026 21:27
Comment threadsrc/coreclr/vm/stublink.cpp Outdated
Comment threadsrc/coreclr/vm/stublink.cpp Outdated

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

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
 // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
 "ExecutableStubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",

Comment threadsrc/coreclr/vm/datadescriptor/datadescriptor.inc
Comment threadsrc/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 5, 2026 21:42
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 6, 2026 14:33
CopilotAI requested a review from jkotasAugust 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

 DWORD dwHelperSize = 1;

CopilotAI review requested due to automatic review settings August 6, 2026 14:43

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

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
 StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
 DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment threadsrc/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
 case STUB_CODE_BLOCK_JUMPSTUB:
return "JumpStub";
case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
 if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
TRACE_LEVEL_INFORMATION,
CLR_JIT_KEYWORD))
{
DWORD dwHelperSize = 1;
ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment threadsrc/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

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

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
 case STUB_CODE_BLOCK_DYNAMICHELPER:
return "MethodCallThunk";
case STUB_CODE_BLOCK_FIXUPPRECODE:
return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

rcj1
rcj1 approved these changes Aug 7, 2026

@noahfalknoahfalk 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!

Comment threadsrc/coreclr/vm/stubmgr.cpp
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@jkotas@noahfalk@janvorli@rcj1