Skip to content

Replace CoreCLR SList with NativeAOT-style design#126949

Merged
max-charlamb merged 20 commits intomainfrom
dev/max-charlamb/unify-slist
Apr 21, 2026
Merged

Replace CoreCLR SList with NativeAOT-style design#126949
max-charlamb merged 20 commits intomainfrom
dev/max-charlamb/unify-slist

Conversation

@max-charlamb
Copy link
Copy Markdown
Member

@max-charlamb max-charlamb commented Apr 15, 2026

Note

This PR was authored with the assistance of GitHub Copilot.

Summary

Unify the CoreCLR and NativeAOT SList implementations into a single shared header at src/coreclr/inc/slist.h. NativeAOT's slist.h becomes a redirect to this shared header. The old sentinel-based SLink/SList design is replaced with the NativeAOT-style design: no sentinel node, NULL means empty, traits-based next-pointer access.

Design

SListTraits and SListMode

A single SListTraits<T, Mode> template replaces the old DefaultSListTraits/DefaultSListTraitsWithTail classes. The SListMode enum controls which operations are permitted:

Mode Allowed Operations Use Case
Thin (default) InsertHead, RemoveHead, RemoveFirst, FindAndRemove, InsertAfter Head-only lists (CacheLine, ConnectionCookie, SyncBlock, etc.)
Tail + InsertTail, GetTail Tail-tracking lists (Thread, CallCountingManager, etc.)

Convenience Alias

template <typename T> using SListTail = SList<T, SListTraits<T, SListMode::Tail>>;

Other Features

  • Pointer-to-pointer Iterator with Begin()/End(), Insert/Remove at position, debug validation
  • SListElem<T> wrapper for non-intrusive list usage (available to both CoreCLR and NativeAOT)
  • SListTailBase conditional storage — m_pTail only exists when HasTail is true

Consumer Migrations

All method names preserved: InsertHead, InsertTail, RemoveHead, FindAndRemove, GetHead, GetNext, IsEmpty.

Consumer m_pNext type List type
CacheLine DPTR(CacheLine) SList<CacheLine>
CallCountingManager DPTR(CallCountingManager) SListTail<CallCountingManager>
ConnectionCookie DPTR(ConnectionCookie) SList<ConnectionCookie>
StoredProfilerNode DPTR(StoredProfilerNode) SList<StoredProfilerNode>
Thread PTR_Thread SListTail<Thread>
SyncBlock PTR_SyncBlock Raw pointers (free/cleanup lists — global instance needs trivial construction)
HandleCleanupListItem DPTR(...) SListTail<HandleCleanupListItem>
FailedTypeInitCleanupListItem DPTR(...) SListTail<FailedTypeInitCleanupListItem>
SListElem<NativeCodeVersion> DPTR(SListElem) SListTail<SListElem<NativeCodeVersion>>
OsModuleEntry (NativeAOT) PTR_OsModuleEntry SList<OsModuleEntry>
TypeManagerEntry (NativeAOT) TypeManagerEntry* SList<TypeManagerEntry>

DAC / cDAC Changes

  • SyncBlock_1.cs, Thread_1.cs: Removed SLink offset subtraction (links now point directly to objects)
  • datadescriptor.inc: Removed SLink type definition, ThreadStore.FirstThreadLink changed from TYPE(SLink) to T_POINTER
  • Mock descriptors: Removed dead LinkAddress/CleanupLinkAddress properties
  • SyncBlock.md: Updated pseudocode to remove offset subtraction
  • daccess.h: Updated stale SLink comments to reflect intrusive m_pNext design

NativeAOT Unification

  • nativeaot/Runtime/slist.h redirects to ../../inc/slist.h
  • Removed lock-free InsertHeadInterlocked — the two call sites run single-threaded; the previous volatile/CAS approach was also insufficient for weak memory models
  • Deleted both slist.inl files (no longer needed without interlocked support)
  • Removed rh::std::find/count helpers (single usage inlined)
  • All NativeAOT call sites updated to use unified method names (InsertHead/RemoveHead/Begin/End)

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Replaces CoreCLR’s sentinel-based SList with a NativeAOT-style, traits-based design (no sentinel; NULL = empty) and migrates affected consumers and DAC/cDAC descriptors to point directly at the owning objects.

Changes:

  • Reworked src/coreclr/inc/slist.h to a traits-based intrusive list with optional tail tracking and SListElem<T> for non-intrusive usage.
  • Migrated multiple CoreCLR consumers from SLink m_Link to m_pNext (DAC-safe pointer types) and updated list operations accordingly.
  • Updated DAC/cDAC contracts, descriptors, and mocks so list heads/links now point directly to objects (no offset subtraction / CONTAINING_RECORD).

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.Thread.cs Updates mock thread store/list wiring to use direct Thread.Address links.
src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.SyncBlock.cs Updates mock cleanup list to use direct SyncBlock.Address links.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Thread_1.cs Removes SLink offset logic; treats thread links as direct thread pointers.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/SyncBlock_1.cs Removes link-offsetof subtraction; iterates cleanup list via direct pointers.
src/coreclr/vm/tieredcompilation.h Introduces OptimizationQueue typedef using tail-enabled SList for optimization queue.
src/coreclr/vm/threads.h Replaces SLink m_Link with PTR_Thread m_pNext; updates ThreadList and cdac offsets.
src/coreclr/vm/threads.cpp Updates FindAndRemove usage to new boolean-return API.
src/coreclr/vm/syncblk.h Replaces SLink usage with PTR_SyncBlock m_pNext; updates cdac offsets and cache list types.
src/coreclr/vm/syncblk.cpp Removes offsetof(SyncBlock, m_Link) arithmetic; cleanup/free lists now store SyncBlock* directly.
src/coreclr/vm/loaderallocator.hpp Replaces SLink with m_pNext in cleanup list items; adds tail-enabled list typedefs.
src/coreclr/vm/loaderallocator.cpp Updates list iteration/removal to match new next-pointer layout.
src/coreclr/vm/datadescriptor/datadescriptor.inc Removes SLink type and switches FirstThreadLink descriptor to a pointer.
src/coreclr/vm/comconnectionpoints.h Replaces SLink with m_pNext in ConnectionCookie; updates list typedef.
src/coreclr/vm/comconnectionpoints.cpp Removes CONTAINING_RECORD/InsertAfter usage; performs direct pointer chaining.
src/coreclr/vm/callcounting.h Replaces SLink with m_pNext; introduces tail-enabled CallCountingManagerList.
src/coreclr/vm/callcounting.cpp Updates static list declaration and iteration to new list type/API.
src/coreclr/vm/cachelinealloc.h Replaces SLink with m_pNext; updates list typedefs and initialization.
src/coreclr/vm/cachelinealloc.cpp Removes now-unneeded SList::Init() calls in allocator ctor.
src/coreclr/inc/slist.h Core redesign: traits-based next-pointer access, optional tail tracking, SListElem<T>, and updated iterator/API.
src/coreclr/inc/profilepriv.h Migrates StoredProfilerNode to m_pNext; updates profiler list typedef.
src/coreclr/debug/daccess/request.cpp Updates DAC traversal of syncblock lists to use direct m_pNext pointers.
docs/design/datacontracts/SyncBlock.md Updates docs to reflect cleanup list head now points to SyncBlock objects directly.

Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h
Comment thread src/coreclr/inc/slist.h Outdated
Copilot AI requested a review from jkotas April 15, 2026 18:34
Copilot AI review requested due to automatic review settings April 15, 2026 19:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Copilot AI review requested due to automatic review settings April 16, 2026 21:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread src/coreclr/inc/slist.h
Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/vm/syncblk.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
@github-actions

This comment has been minimized.

Comment thread src/coreclr/inc/slist.h Outdated
@max-charlamb max-charlamb force-pushed the dev/max-charlamb/unify-slist branch from cb65de6 to 84d3e34 Compare April 16, 2026 22:13
Copilot AI review requested due to automatic review settings April 16, 2026 22:23
@max-charlamb max-charlamb force-pushed the dev/max-charlamb/unify-slist branch 2 times, most recently from 4e843f7 to b73b3b5 Compare April 16, 2026 22:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

@github-actions

This comment has been minimized.

@max-charlamb max-charlamb force-pushed the dev/max-charlamb/unify-slist branch from b73b3b5 to b5cad54 Compare April 16, 2026 23:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread src/coreclr/vm/threads.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

@AaronRobinsonMSFT Any feedback about the C++ specifics?

Comment thread src/coreclr/nativeaot/Runtime/slist.h Outdated
Comment thread src/coreclr/nativeaot/Runtime/slist.h Outdated
Comment thread src/coreclr/nativeaot/Runtime/slist.inl Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
max-charlamb and others added 3 commits April 20, 2026 16:42
-nostdlib only affects linking, not header inclusion. std::forward
from <utility> is header-only with no link dependency, so it works
fine under NativeAOT's -nostdlib flag.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Inline the single rh::std::count usage in threadstore.cpp as a
debug-only loop. Remove rh::std::find/count/SList-find helpers
from slist.inl, making it a plain forwarder to ../../inc/slist.inl.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread src/coreclr/inc/slist.h
Comment thread src/coreclr/inc/slist.h
Comment thread src/coreclr/nativeaot/Runtime/threadstore.cpp Outdated
max-charlamb and others added 2 commits April 20, 2026 17:06
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread src/coreclr/inc/slist.inl Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
max-charlamb and others added 2 commits April 20, 2026 18:47
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Comment thread src/coreclr/inc/slist.inl Outdated
@github-actions
Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #126949

Note

This review was generated by GitHub Copilot using multi-model analysis (Claude Opus 4.6, Claude Sonnet 4.5, GPT-5.3-Codex). All three models contributed findings.

Holistic Assessment

Motivation: The PR is well-justified. Maintaining two divergent SList implementations (CoreCLR's sentinel-based SLink/CONTAINING_RECORD design vs. NativeAOT's cleaner direct-m_pNext design) is a genuine maintenance burden and source of error-prone pointer arithmetic. Unifying them into one shared template is a clear win.

Approach: The traits-based design with SListMode enum (Thin, Tail, Interlocked) and static_assert guards to prevent mode misuse is clean and well-structured. The migration of all consumers is thorough — every SLink m_LinkDPTR(T) m_pNext, every CONTAINING_RECORD pattern removed, and the cDAC contracts simplified to eliminate offset arithmetic.

Summary: ⚠️ Needs Human Review. All code changes are correct across all three review models. One documentation pseudocode section was not updated to match the new semantics, and there are stale comments from the removed SLink type. A human reviewer should confirm the SyncBlock.md pseudocode issue and decide whether the minor suggestions merit fixing in this PR or follow-up.


Detailed Findings

✅ InsertHeadInterlocked CAS loop — Correct

The CAS loop in slist.inl correctly reads the volatile m_pHead into pItem->m_pNext, captures expected, and performs CAS. The static_assert guards (!HasTail, IsInterlocked) are appropriate. Verified equivalent to the old NativeAOT PushHeadInterlocked. (Confirmed by all 3 models)

✅ Tail pointer maintenance — Correct

All four mutation operations correctly handle m_pTail:

  • InsertHead: sets tail when list transitions empty→non-empty
  • RemoveHead: clears tail when list transitions non-empty→empty
  • InsertTail: updates both head (if empty) and tail
  • RemoveFirst: updates tail when removed item was the tail element (this->m_pTail = prev)

Edge cases (empty, single-element, multi-element) all handled. (Confirmed by all 3 models)

✅ SyncBlock free/cleanup list migration — Correct

The elimination of SLink/CONTAINING_RECORD from syncblk.h/cpp and request.cpp is correct. m_pCleanupBlockList and m_FreeBlockList are now directly PTR_SyncBlock, and traversal via m_pNext gives the next SyncBlock directly without offset arithmetic. (Confirmed by all 3 models)

✅ cDAC contract simplification — Correct

SyncBlock_1.cs and Thread_1.cs correctly remove _syncBlockLinkOffset and _threadLinkOffset adjustments. ThreadStore.FirstThreadLink now uses offsetof(ThreadList, m_pHead) which is correct for the new layout where SListTailBase::m_pTail precedes m_pHead. (Confirmed by all 3 models)

✅ NativeAOT redirect — Complete

slist.h#include "../../inc/slist.h" and slist.inl#include "../../inc/slist.inl". All NativeAOT consumers migrated: PushHeadInsertHead, PopHeadRemoveHead, PushHeadInterlockedInsertHeadInterlocked. The rh::std helpers (count, find) correctly removed. (Confirmed by all 3 models)

✅ static_assert guards — Comprehensive

All mode-incompatible operations are gated: InsertHead/RemoveHead/InsertTail/RemoveFirst/FindAndRemove/InsertAfter/Insert/Remove all block IsInterlocked lists. InsertAfter/Insert/Remove also block HasTail lists. InsertHeadInterlocked requires IsInterlocked and blocks HasTail.

⚠️ SyncBlock.md pseudocode not updated — Documentation bug

docs/design/datacontracts/SyncBlock.md lines 152 and 161 still show:

return cleanupBlockList - /* SyncBlock::LinkNext offset */;
return linkNext - /* SyncBlock::LinkNext offset */;

With the new design, CleanupBlockList and LinkNext point directly to SyncBlock objects — no offset subtraction is needed. The PR correctly updated the table description at line 27 but missed updating this pseudocode. The actual C# implementation in SyncBlock_1.cs is correct (it returns the pointers directly without subtraction). (Flagged by Opus 4.6 and Sonnet 4.5)

💡 Stale SLink comments in daccess.h — Follow-up

src/coreclr/inc/daccess.h lines 241–250 still describe the old SLink-based SList pattern. These comments are now misleading since SLink no longer exists. Consider updating in this PR or a follow-up. (Flagged by Opus 4.6 and GPT-5.3-Codex)

💡 Consider static_assert for m_pNext field validation

The old SList used a member pointer template parameter (SLink T::*LinkPtr = &T::m_Link) which gave compile-time validation that T has the expected link field. The new SListTraits::GetNextPtr uses offsetof(T, m_pNext) which will fail to compile if m_pNext doesn't exist, but doesn't validate its type. A static_assert like static_assert(sizeof(T::m_pNext) == sizeof(void*)) could add an extra safety layer. Not blocking. (Flagged by GPT-5.3-Codex)

Generated by Code Review for issue #126949 ·

max-charlamb and others added 3 commits April 20, 2026 19:11
Include Pal.h (NativeAOT) and utilcode.h (CoreCLR) directly in
slist.inl so consumers don't need to worry about include order.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Match the declaration guard in slist.h so slist.inl is safe to
include in DAC builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- SyncBlock.md: remove offset subtraction from pseudocode (links
  now point directly to objects, not embedded SLink nodes)
- daccess.h: update SList description to reflect intrusive m_pNext
  design instead of removed SLink/CONTAINING_RECORD pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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

Copy link
Copy Markdown
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

LGTM otherwise

Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Comment thread src/coreclr/inc/slist.h Outdated
Per review feedback, the two NativeAOT InsertHeadInterlocked call
sites run single-threaded, so lock-free support is unnecessary.
The volatile m_pHead was also insufficient for weak memory models.

- Remove SListMode::Interlocked, IsInterlocked, FailFastPolicy
- Remove DoNothingFailFastPolicy, SListThin alias, SListInterlocked alias
- Remove all IsInterlocked static_asserts
- Remove InsertHeadInterlocked declaration and volatile m_pHead
- Delete inc/slist.inl and nativeaot/Runtime/slist.inl
- NativeAOT: InsertHeadInterlocked → InsertHead, remove volatile m_pNext

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@max-charlamb
Copy link
Copy Markdown
Member Author

/ba-g

Sign up for free to 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.

5 participants