Skip to content

Port more coreclr holders to the LifetimeHolder<Traits> pattern#128103

Merged
AaronRobinsonMSFT merged 7 commits into
dotnet:mainfrom
AaronRobinsonMSFT:holder_port_more
May 13, 2026
Merged

Port more coreclr holders to the LifetimeHolder<Traits> pattern#128103
AaronRobinsonMSFT merged 7 commits into
dotnet:mainfrom
AaronRobinsonMSFT:holder_port_more

Conversation

@AaronRobinsonMSFT
Copy link
Copy Markdown
Member

@AaronRobinsonMSFT AaronRobinsonMSFT commented May 12, 2026

Continues the migration of legacy Holder/Wrapper/SpecializedWrapper-based resource holders under src/coreclr/ to the newer LifetimeHolder<Traits> pattern (matches the shape already established by MapViewHolder, LocalAllocHolder, HKEYHolder, BSTRHolder).

Each commit ports one holder, in isolation, with the call-site updates required for the new API.

Commits

  1. HModuleHolderWrapper<HMODULE, ...>LifetimeHolder<HModuleTraits>

    • 3 call sites updated (vm/eetoprofinterfaceimpl.cpp, debug/di/rspriv.h/process.cpp, utilcode/util.cpp)
  2. ResetPointerHolderSpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>LifetimeHolder<ResetPointerTraits<T>>

    • The two ZeroMem partial specializations collapse into a single Free() using if constexpr (std::is_pointer<T>::value)
    • Removes the local VISIBLE macro and detail::ZeroMem helpers
    • No call-site changes (all 3 call sites use direct-init)
  3. CoTaskMemHolderSpecializedWrapper<_TYPE, DeleteCoTaskMem<_TYPE>>LifetimeHolder<CoTaskMemTraits<T>>

    • DeleteCoTaskMem helper removed
    • 5 call-site updates in debug/di/module.cpp
  4. StubHolderSpecializedWrapper<_TYPE, StubRelease<_TYPE>>LifetimeHolder<StubTraits<T>>

    • Call-site updates in vm/stublink.cpp and vm/stubcache.cpp
  5. ExceptionHolderSpecializedWrapper<Exception, Exception__Delete>LifetimeHolder<ExceptionTraits>

    • Removes the dead #if 1 / #else / #endif scaffold and the hand-rolled class ExceptionHolder in the dead branch
    • Removes the now-unused Exception__Delete inline helper
    • Updates EX_TRY macro internals in inc/ex.h (EX_RETHROW, GET_EXCEPTION(), EXTRACT_EXCEPTION()) and related call sites in vm/clrex.h / vm/threads.cpp

Recurring API mapping

For reference, the legacy → LifetimeHolder mappings used throughout these commits:

Legacy LifetimeHolder
Assign(v) operator=(v)
Clear() Free()
Extract() Detach()
SuppressRelease() + GetValue() Detach()
HolderType x = expr; HolderType x{ expr }; (value ctor is explicit)

Note

The contents of this pull request were drafted with the assistance of GitHub Copilot.

AaronRobinsonMSFT and others added 5 commits May 12, 2026 13:24
Replaces the legacy Wrapper<>-based HModuleHolder typedef with a
HModuleTraits struct used via LifetimeHolder<>, matching the pattern
already used by HKEYHolder, BSTRHolder, and MapViewHolder.

Call sites updated to use the LifetimeHolder API:
- Assign(v) -> operator=(v)
- Clear()   -> Free()
- Extract() / SuppressRelease()+GetValue() -> Detach()
- Copy-init 'HModuleHolder h = expr;' -> direct-init 'HModuleHolder h{ expr };'
  (LifetimeHolder's value constructor is explicit)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the legacy SpecializedWrapper-based ResetPointerHolder with a
ResetPointerTraits<T> struct used via LifetimeHolder<>. The two
ZeroMem<T> / ZeroMem<T*> partial specializations collapse into a single
Free() using 'if constexpr (std::is_pointer<T>::value)'. The local
VISIBLE macro and detail::ZeroMem helpers are removed.

Behavioral note: legacy Wrapper only invoked the release function when
the holder was 'acquired' (constructed non-null). LifetimeHolder invokes
Free unconditionally on destruction, so the new Free() guards against a
null slot pointer. All existing call sites direct-init from a real
address, so no call-site changes are required.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the legacy SpecializedWrapper-based CoTaskMemHolder typedef
(and its DeleteCoTaskMem free-function helper) with a CoTaskMemTraits<T>
struct used via LifetimeHolder<>. The new definition is moved to live
alongside the other LifetimeHolder-based aliases.

Call sites in src/coreclr/debug/di/module.cpp updated:
- holder.GetAddr()        -> std::addressof(holder)
  (legacy GetAddr returned 'this' (pointer-to-holder), used as an
  out-parameter target. LifetimeHolder's operator& is overloaded to
  return the inner Type*, so std::addressof is required to obtain
  the address of the holder itself.)
- holder.SuppressRelease() -> holder.Detach()
- pLocalBuffer->Assign(p)  -> *pLocalBuffer = p

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the legacy SpecializedWrapper-based StubHolder typedef with a
StubTraits<T> struct used via LifetimeHolder<>. The StubRelease<T,LOGGER>
function template is preserved verbatim (still supports the optional
LOGGER template parameter used for executable-allocator statistics)
and is now invoked from the trait's Free().

The new declaration is moved to live alongside the other
LifetimeHolder-based aliases in the file. The ExecutableWriterHolderNoLog
and ExecutableAllocator forward declarations travel with it.

Call sites updated:
- stublink.cpp:
  - 'StubHolder<Stub> pStub = Stub::NewStub(...);' -> brace direct-init
    (LifetimeHolder's value ctor is explicit)
  - pStub.Extract() -> pStub.Detach()
- stubcache.cpp (x2):
  - 'pstub.SuppressRelease(); RETURN pstub;' -> 'RETURN pstub.Detach();'
    (semantically equivalent: both yield the value to the caller and
    skip DecRef at scope exit)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the legacy SpecializedWrapper-based ExceptionHolder alias with
an ExceptionTraits struct used via LifetimeHolder<>. Also removes the
dead-code '#else' branch (a hand-rolled class ExceptionHolder that had
been preserved behind '#if 1 / #else / #endif'), and the now-unused
Exception__Delete inline helper.

EX_TRY macro internals updated:
- EX_RETHROW:        __pException.SuppressRelease() -> __pException.Detach()
- GET_EXCEPTION():   __pException.GetValue() -> static_cast<Exception*>(__pException)
                     (both ternary branches must yield Exception*)
- EXTRACT_EXCEPTION: __pException.Extract() -> __pException.Detach()

Behavioral note on EX_RETHROW: Detach() differs from legacy
SuppressRelease() in that it also resets m_value to nullptr. Since
control flow immediately PAL_CPP_RETHROWs and unwinds the scope, the
holder's destructor sees nullptr and short-circuits in Free(). Net
effect is identical: the in-flight exception object survives the rethrow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@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.

@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 11.0.0 milestone May 12, 2026
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

This PR continues the CoreCLR-internal migration from legacy Holder/Wrapper/SpecializedWrapper-based RAII to the newer LifetimeHolder<Traits> pattern, updating relevant call sites and a few exception-handling macros to use Detach()/Free() semantics.

Changes:

  • Introduces HModuleHolder, ResetPointerHolder<T>, CoTaskMemHolder<T>, and StubHolder<T> as LifetimeHolder<Traits> specializations in holder.h.
  • Ports multiple call sites to the new API shape (notably switching Extract()/SuppressRelease() patterns to Detach(), and Clear() to Free()).
  • Converts ExceptionHolder in ex.h to LifetimeHolder<ExceptionTraits> and updates EX_RETHROW / GET_EXCEPTION / EXTRACT_EXCEPTION usages accordingly.
Show a summary per file
File Description
src/coreclr/vm/threads.cpp Transfers exception ownership during thread startup using Detach() instead of suppressing release.
src/coreclr/vm/stublink.cpp Updates StubHolder construction and return path to use explicit construction + Detach().
src/coreclr/vm/stubcache.cpp Updates stub cache refcount/return flow to return raw stubs via Detach() (no RAII release on return).
src/coreclr/vm/eetoprofinterfaceimpl.cpp Moves HModuleHolder ownership into member field via Detach().
src/coreclr/vm/clrex.h Adjusts GET_EXCEPTION and EX_RETHROW internals to align with LifetimeHolder behavior.
src/coreclr/utilcode/util.cpp Updates DLL lifetime management to use brace-init for HModuleHolder and Detach() for handoff/leak-on-purpose cases.
src/coreclr/inc/holder.h Removes legacy holder aliases/helpers and adds new LifetimeHolder-based traits/aliases for HMODULE, CoTaskMem, stubs, and reset-pointer semantics.
src/coreclr/inc/ex.h Replaces ExceptionHolder specialized wrapper with LifetimeHolder<ExceptionTraits> and updates helper macros to use Detach().
src/coreclr/debug/di/rspriv.h Updates metadata-copy helper signature to take a VOID** out-parameter.
src/coreclr/debug/di/process.cpp Updates DAC module holder usage to the new assignment/free APIs (= and Free()).
src/coreclr/debug/di/module.cpp Updates metadata-copy call sites and implementation to fill a LifetimeHolder via its overloaded operator&.

Copilot's findings

  • Files reviewed: 11/11 changed files
  • Comments generated: 1

Comment thread src/coreclr/debug/di/module.cpp
Copilot AI review requested due to automatic review settings May 12, 2026 23:32
@AaronRobinsonMSFT AaronRobinsonMSFT enabled auto-merge (squash) May 12, 2026 23:34
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's findings

  • Files reviewed: 11/11 changed files
  • Comments generated: 1

Comment thread src/coreclr/inc/holder.h
@AaronRobinsonMSFT AaronRobinsonMSFT merged commit 37bcf38 into dotnet:main May 13, 2026
113 checks passed
@github-project-automation github-project-automation Bot moved this to Done in AppModel May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants