Skip to content

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

Open
AaronRobinsonMSFT wants to merge 7 commits into
dotnet:mainfrom
AaronRobinsonMSFT:holder_port_more
Open

Port more coreclr holders to the LifetimeHolder<Traits> pattern#128103
AaronRobinsonMSFT wants to merge 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants