Skip to content

Add preemptive-only cooperative GC transition holder - #133276

Open
davidwrighton wants to merge 1 commit into
dotnet:mainfrom
davidwrighton:gcx-coop-from-preemp
Open

Add preemptive-only cooperative GC transition holder#133276
davidwrighton wants to merge 1 commit into
dotnet:mainfrom
davidwrighton:gcx-coop-from-preemp

Conversation

@davidwrighton

Copy link
Copy Markdown
Member

Summary

  • add GCX_COOP_FROM_PREEMP(), a cooperative-mode holder for sites that are guaranteed to enter in preemptive mode
  • restore preemptive mode unconditionally on scope exit, removing the saved incoming-mode state and conditional escape-path logic
  • use the holder at 235 proven-preemptive transition sites, including 171 QCall-body sites and 64 additional sites covered by preemptive contracts or explicit transitions
  • retain GCX_COOP() at 132 sites where the incoming mode is not guaranteed or unwind behavior requires its defensive restoration

The new holder uses the existing non-nestable assertions in DisablePreemptiveGC() and EnablePreemptiveGC() to detect invalid use in Checked and Debug builds.

Size impact

Measured using build.cmd clr -os browser -c release against a baseline build from the same checkout:

WASM sectionBaseline bytesChanged bytesBytes removedSection removed
FUNCTION10,08910,08810.009912%
CODE3,773,4333,758,61314,8200.392746%
DATA712,583712,58300%
Whole corerun.wasm4,512,8224,498,00114,8210.328420%

As a representative example, the Browser WASM body for the AppDomain_CreateDynamicAssembly QCall decreased from 721 bytes to 611 bytes, a reduction of 110 bytes or 15.257%.

Validation

  • build.cmd -subset clr -configuration Checked
  • build.cmd clr -os browser -c release

Note

This pull request description was generated with GitHub Copilot.

Introduce GCX_COOP_FROM_PREEMP for call sites that are known to enter in preemptive mode, avoiding conditional mode restoration on normal and exceptional exits.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7c53d414-704b-43fe-86cd-a4f5e0dc0446
CopilotAI lite review requested due to automatic review settings September 4, 2026 22:53
@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.

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

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.

🔵 Needs a closer look

It changes GC mode transition semantics across a large number of VM/QCall sites, so the regression blast radius is high and needs focused human validation of the “always-enter-preemptive” assumption per call site category.

Pull request overview

This PR introduces a new GC mode transition holder, GCX_COOP_FROM_PREEMP(), intended for call sites that are guaranteed to enter in preemptive mode, and updates a large set of existing GCX_COOP() usages to use the new holder where that precondition is believed to hold.

Changes:

  • Add GCX_COOP_FROM_PREEMP() macro + GCCoopFromPreemp holder to provide a smaller preemptive→cooperative scope and an unconditional return to preemptive mode.
  • Update many QCall and VM sites that previously used GCX_COOP() to use GCX_COOP_FROM_PREEMP() under the assumption they always enter preemptive.
  • Keep GCX_COOP() at sites where the incoming mode is not guaranteed (per PR description).
File summaries
FileDescription
src/coreclr/vm/weakreferencenative.cppSwitch select COM interop QCall regions to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/varargsnative.cppSwitch ArgIterator QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/util.hppAdd GCX_COOP_FROM_PREEMP() macro and document usage.
src/coreclr/vm/threads.hAdd GCCoopFromPreemp holder + internal enter/pop helpers for the new transition pattern.
src/coreclr/vm/threads.cppSwitch arg-buffer swap to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/stubhelpers.cppSwitch multiple interop QCall bodies to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/stdinterfaces.cppSwitch COM type info helper scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/runtimehandles.cppSwitch multiple reflection/runtime-handle QCall scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/reflectioninvocation.cppSwitch reflection invocation QCall scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/qcall.cppSwitch QCall handle helpers to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/prestub.cppSwitch debug/slow-path GC-triggering regions to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/olevariant.cppSwitch VARIANT conversion QCall scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/nativelibrary.cppSwitch ALC resolve/managed callback scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/mlinfo.cppSwitch marshaling metadata/handle scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/methodtable.cppSwitch interface method-table resolution scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/marshalnative.cppSwitch many marshal/COM QCall scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/managedmdimport.cppSwitch managed metadata import array allocation scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/loaderallocator.cppSwitch loader allocator GC/suspend + tracking setup scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/jitinterface.cppSwitch various JIT-EE helper scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/jithelpers.cppSwitch selected helper QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/interoplibinterface_objc.cppSwitch ObjC reference tracking handle operations to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/interoplibinterface_java.cppSwitch Java bridge initialization/handle operations to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/interoplibinterface_comwrappers.cppSwitch ComWrappers handle/cache setup to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/ilstubresolver.cppSwitch IL stub string literal construction scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/ilmarshalers.cppSwitch SafeArray marshaling QCall scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/finalizerthread.cppSwitch browser/WASI finalizer iteration KickOff scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/exceptionhandling.cppSwitch filter/stackwalk-related QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/dynamicmethod.cppSwitch multiple LCG resolver scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/dwbucketmanager.hppSwitch exception-name retrieval scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/dispatchinfo.cppSwitch managed view synchronization scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/debugdebugger.cppSwitch debugger-related QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/custommarshalerinfo.cppSwitch marshaler object setup scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/customattribute.cppSwitch custom attribute instantiation/data creation scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/crst.cppSwitch debugger suspend-forbid holder scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/comutilnative.cppSwitch numerous core QCalls (GC interface, failfast, etc.) to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/comsynchronizable.cppSwitch thread/lock object QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/commodule.cppSwitch reflection module RVAs/types QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/comdynamic.cppSwitch dynamic type creation scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/comdependenthandle.cppSwitch dependent handle alloc/free QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/comdelegate.cppSwitch delegate init/reflection helper QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/comconnectionpoints.cppSwitch connection enumeration scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/class.cppSwitch EnC static field creation scope to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/ceeload.cppSwitch module init/profiler callback + stringref resolution scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/assemblynative.cppSwitch many assembly QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/assembly.cppSwitch loader-allocator association + profiler callback scopes to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/arraynative.cppSwitch array allocation/ctor QCalls to GCX_COOP_FROM_PREEMP().
src/coreclr/vm/appdomainnative.cppSwitch dynamic assembly + intern QCalls to GCX_COOP_FROM_PREEMP().
Review details
  • Files reviewed: 47/47 changed files
  • Comments generated: 0
  • Review effort level: Lite

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.

3 participants

@davidwrighton@jkotas