Skip to content

[Foundation] Simplify memory management of NSObjectData for CoreCLR. - #25507

Merged
rolfbjarne merged 1 commit into
mainfrom
dev/rolf/coreclr-simplified-nsobjectdata
May 25, 2026
Merged

rolfbjarne merged 1 commit into
mainfrom
dev/rolf/coreclr-simplified-nsobjectdata

Conversation

@rolfbjarne

Copy link
Copy Markdown
Member

On CoreCLR, the tagged memory returned by ObjectiveCMarshal.CreateReferenceTrackingHandle
is guaranteed to be stable (same pointer per object) and its lifetime is tied to the GC
freeing the instance. This means we can use it directly as our NSObjectData storage,
removing the need for:

  • The TrackedObjectInfo indirection struct (both in C# and native code).
  • The ConditionalWeakTable used to prevent premature
    collection of separately-allocated native memory.
  • The Interlocked.CompareExchange synchronization (since the pointer is always the same).

On CoreCLR, the tagged memory returned by ObjectiveCMarshal.CreateReferenceTrackingHandle
is guaranteed to be stable (same pointer per object) and its lifetime is tied to the GC
freeing the instance. This means we can use it directly as our NSObjectData storage,
removing the need for:

- The TrackedObjectInfo indirection struct (both in C# and native code).
- The ConditionalWeakTable used to prevent premature
  collection of separately-allocated native memory.
- The Interlocked.CompareExchange synchronization (since the pointer is always the same).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 22, 2026 10:19

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.

Pull request overview

This PR refactors CoreCLR toggle-ref support by using the tagged memory returned by ObjectiveCMarshal.CreateReferenceTrackingHandle as the NSObjectData storage directly, removing the previous TrackedObjectInfo indirection and reducing the need for separately allocated native memory on CoreCLR.

Changes:

  • Removed the TrackedObjectInfo indirection and updated CoreCLR bridge code to treat the tagged memory as struct NSObjectData.
  • Added Runtime.GetTaggedMemory (NSObject) and updated NSObject.GetData to use tagged memory directly on CoreCLR.
  • Avoided initializing the ConditionalWeakTable on CoreCLR (since the separate native allocation path is no longer used there).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/ObjCRuntime/Runtime.CoreCLR.cs Removes tagged-memory indirection and adds GetTaggedMemory to retrieve tagged memory for CoreCLR.
src/Foundation/NSObject2.cs Switches CoreCLR NSObjectData storage to tagged memory and skips data_table initialization on CoreCLR.
runtime/coreclr-bridge.m Updates native CoreCLR GC callbacks to interpret the tagged pointer as NSObjectData* directly.
Comments suppressed due to low confidence (1)

src/ObjCRuntime/Runtime.CoreCLR.cs:234

  • GetTaggedMemory allocates a reference-tracking GCHandle via ObjectiveCMarshal.CreateReferenceTrackingHandle and then immediately frees it, returning a raw pointer derived from the returned tagged memory span. This adds per-NSObject overhead and also makes correctness depend on a subtle contract: the returned tagged memory pointer must be (a) the same as the tagged memory associated with the long-lived tracking handle created in Runtime.RegisterNSObject, and (b) remain valid even though this temporary handle is freed. To reduce risk and avoid the extra handle churn, consider plumbing the tagged-memory pointer from the existing CreateTrackingGCHandle/Runtime.RegisterNSObject path into NSObject so GetData can use that pointer directly (or otherwise ensure GetData uses the tagged memory from the same tracking handle that native GC callbacks will see).
		internal unsafe static void* GetTaggedMemory (NSObject obj)
		{
			// If https://github.com/dotnet/runtime/issues/128476 is accepted and implemented,
			// can just call that new API instead of calling ObjectiveCMarshal.CreateReferenceTrackingHandle and
			// freeing the returned handle.

			var gchandle = ObjectiveCMarshal.CreateReferenceTrackingHandle (obj, out var info);
			// We only care about the tagged memory ('info'), so just free the GCHandle.
			// We might want to request an API to just get the tagged memory at some point.
			gchandle.Free ();
			// The tagged memory pointer is guaranteed to be the same for every call to ObjectiveCMarshal.CreateReferenceTrackingHandle,
			// and it will automatically be freed once the 'obj' is freed by the GC (in particular _once the instance is freed_,
			// not _once the instance is collectible_, which is a very important distinction for us).
			return Unsafe.AsPointer (ref info.GetPinnableReference ());

Comment thread src/ObjCRuntime/Runtime.CoreCLR.cs
Comment thread src/Foundation/NSObject2.cs
@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #78a34cf] Build passed (Detect API changes) ✅

Pipeline on Agent
Hash: 78a34cf349bde65fc57f876dda37912d737a9b0b [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #78a34cf] Build passed (Build packages) ✅

Pipeline on Agent
Hash: 78a34cf349bde65fc57f876dda37912d737a9b0b [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 78a34cf349bde65fc57f876dda37912d737a9b0b [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #78a34cf] Build passed (Build macOS tests) ✅

Pipeline on Agent
Hash: 78a34cf349bde65fc57f876dda37912d737a9b0b [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🚀 [CI Build #78a34cf] Test results 🚀

Test results

✅ All tests passed on VSTS: test results.

🎉 All 183 tests passed 🎉

Tests counts

✅ cecil: All 1 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ dotnettests (iOS): All 1 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 6 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ linker (iOS): All 11 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 11 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 11 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 11 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ monotouch (iOS): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 20 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 20 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 18 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Ventura (13): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

✅ Linux build succeeded

Pipeline on Agent
Hash: 78a34cf349bde65fc57f876dda37912d737a9b0b [PR build]

@rolfbjarne
rolfbjarne merged commit e3f0f38 into main May 25, 2026
56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants