Skip to content

Implicit byref arguments are never on the GC heap - #133304

Merged
EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:implicit-byref-not-on-heap
Sep 25, 2026
Merged

EgorBo merged 9 commits into
dotnet:mainfrom
EgorBo:implicit-byref-not-on-heap

Conversation

@EgorBo

@EgorBo EgorBo commented Sep 5, 2026 •

Copy link
Copy Markdown
Member

Implicit byref arguments (structs passed by reference under the hood: not 1/2/4/8 bytes on win-x64, larger than 16 bytes on arm64) are now guaranteed to never live on the GC heap, so callees can store into them without write barriers.

struct S16 { public object A; public object B; }

[MethodImpl(MethodImplOptions.NoInlining)]
static void Store(S16 s, object o) { s.A = o; Sink(ref s); }
 ; P:Store(S16,System.Object)   win-x64
-       push     rbx
-       sub      rsp, 32
-       mov      rbx, rcx
-       mov      rcx, rbx
-       call     CORINFO_HELP_CHECKED_ASSIGN_REF
-       mov      rcx, rbx
+       sub      rsp, 40
+       mov      gword ptr [rcx], rdx
        call     [P:Sink(byref)]
        nop
-       add      rsp, 32
-       pop      rbx
+       add      rsp, 40
        ret
-; Total bytes of code 32
+; Total bytes of code 19

Bumps READYTORUN_MAJOR_VERSION to 30: crossgen2 now emits barrier-free stores, so older runtimes must reject these images. MINIMUM_READYTORUN_MAJOR_VERSION stays at 26 - existing images can only forward an incoming implicit byref, never originate heap-backed storage for one.

Fixes #133961

Implicit byref argument storage must live outside the GC heap on all
architectures using this convention, so callees can store into these
arguments without write barriers.

Bumps READYTORUN_MAJOR_VERSION to 29: crossgen2 now emits barrier-free
stores, so older runtimes must reject these images.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2871fa5f-63ee-4a17-9721-6c4895a014b3
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 5, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).
10 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: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Copilot AI 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.

🟡 Changes recommended

The behavioral code-generation change lacks targeted regression coverage for write-barrier omission and GC reporting.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates the implicit-byref ABI contract so argument storage is guaranteed outside the GC heap, allowing the JIT to omit write barriers safely.

Changes:

  • Marks implicit-byref stores as non-heap and updates promotion costing.
  • Copies debugger func-eval arguments into GC-protected native memory.
  • Documents the contract and advances ReadyToRun to version 29.
File summaries
File Description
src/coreclr/vm/callhelpers.h Documents caller ownership and GC-reporting requirements.
src/coreclr/vm/callhelpers.cpp Asserts implicit-byref arguments are not heap-backed.
src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs Advances managed R2R version.
src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h Advances NativeAOT R2R version.
src/coreclr/jit/promotion.cpp Removes obsolete write-barrier costing.
src/coreclr/jit/morph.cpp Marks implicit-byref stores as non-heap.
src/coreclr/jit/lclvars.cpp Documents the new storage invariant.
src/coreclr/inc/readytorun.h Advances and documents R2R version 29.
src/coreclr/debug/ee/funceval.cpp Creates protected native copies for func-eval arguments.
docs/design/coreclr/botr/clr-abi.md Documents the revised ABI contract.
Review details
  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/coreclr/jit/morph.cpp
Comment thread docs/design/coreclr/botr/clr-abi.md Outdated
Comment thread docs/design/coreclr/botr/clr-abi.md Outdated
EgorBo and others added 3 commits September 5, 2026 17:41
Reword the implicit-byref section so it does not lead with the Windows
AMD64 calling convention, and move the AMD64 return-buffer-in-RAX note
into the "Return buffers" section.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2871fa5f-63ee-4a17-9721-6c4895a014b3
The Blob Service "List Blobs" API pages its results, and the first page is
not guaranteed to cover the whole prefix. Since the listing is ordered by
blob name, a truncated first page drops entire target directories, which
produced zero partitions for those targets and failed the Helix send with
"SendHelixJob given no WorkItems to send".

Follow the NextMarker until the listing is exhausted, and log the blob
count so a truncated listing is visible in the setup log.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2871fa5f-63ee-4a17-9721-6c4895a014b3
@EgorBo

EgorBo commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

Diffs aren't too motivating. Perhaps, a bit more can be improved with proper alias analysis (implicit byref never aliases with gc heap), but closing for now.

EgorBo and others added 2 commits September 24, 2026 19:01
Resolve ReadyToRun version conflicts by advancing the implicit-byref ABI change to version 30.0 while preserving main's 29.x changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore superpmi_diffs_setup.py to main so this PR does not modify Python files.

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

Copilot-Session: e3cbbf9d-9a2b-4a49-a4a9-905b60d41f15
Comment thread docs/design/coreclr/botr/clr-abi.md Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@EgorBo
EgorBo marked this pull request as ready for review September 24, 2026 17:55
Copilot AI review requested due to automatic review settings September 24, 2026 17:55
@azure-pipelines

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

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

The ABI documentation misstates ARM64 exceptions, and the PR description names the wrong ReadyToRun major version.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 3 Low severity

Open (3)
Resolved since last review (1)

Comment thread docs/design/coreclr/botr/clr-abi.md
Comment thread src/coreclr/inc/readytorun.h
Comment thread src/coreclr/jit/lclvars.cpp
Comment thread src/coreclr/debug/ee/funceval.cpp
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e3cbbf9d-9a2b-4a49-a4a9-905b60d41f15
Copilot AI review requested due to automatic review settings September 24, 2026 18:33

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

The ABI-wide code-generation change lacks targeted regression coverage, and its architecture table omits WebAssembly.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Resolved since last review (3)

Comment thread docs/design/coreclr/botr/clr-abi.md
Add WebAssembly ABI constraints for non-unwrappable structures.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 24, 2026 18:45

Copilot AI 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.

Copilot review overview

🔵 Needs a closer look

The GC-safety and barrier-elision behavior lacks targeted automated regression coverage.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@EgorBo

EgorBo commented Sep 24, 2026 •

Copy link
Copy Markdown
Member Author

@jkotas @jakobbotsch anything else here?

I assume it fixes a potential gc hole we theoretically had (see thread ^), closes #133961 and removes a couple of write barriers.

Follow up: stop representing it via BYREF (#82166) - this actually had some improvements and we can benefit from alias analysis: implicit byrefs never alias with GC heap objects and return buffer

@EgorBo
EgorBo merged commit 1613046 into dotnet:main Sep 25, 2026
136 of 140 checks passed
@EgorBo
EgorBo deleted the implicit-byref-not-on-heap branch September 25, 2026 09:04
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Sep 26, 2026
EgorBo added a commit that referenced this pull request Sep 26, 2026
Implicit byref args are never on the GC heap (#133304), so type them as
`TYP_I_IMPL` instead of `TYP_BYREF` (no GC reporting); async methods
keep `TYP_BYREF` since their storage changes on resumption.
Treat return buffers as non-null in `fgAddrCouldBeNull`, and use
`fgAddrCouldBeHeap` (now aware of implicit byrefs) for write barrier
selection.
Contributes to #82166

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5bb92e6b-deb1-4963-9107-87559f446347
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: (bug) can pass an implicit-byref parameter as a struct return buffer, violating the retbuf stack invariant

4 participants