Skip to content

Optimize and simplify delegate layout - #99200

Merged
jkotas merged 102 commits into
dotnet:mainfrom
MichalPetryka:immutable-delegates
Jul 14, 2026
Merged

Optimize and simplify delegate layout#99200
jkotas merged 102 commits into
dotnet:mainfrom
MichalPetryka:immutable-delegates

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Mar 3, 2024

Copy link
Copy Markdown
Contributor

Reduce size of delegate instance by one pointer field

Contributes to #85014.

@ghostghost added the area-VM-coreclr label Mar 3, 2024
@MichalPetryka

MichalPetryka commented Mar 4, 2024

Copy link
Copy Markdown
ContributorAuthor

I'm not sure what's up with the failures here, tests that are failing on the CI seem to pass on my machine.
EDIT: I was testing with R2R disabled locally since VS kept complaining about being unable to load PDBs for it.

Comment threadsrc/coreclr/vm/object.cpp Outdated
MichalPetrykaand others added 3 commits March 4, 2024 16:40
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka
MichalPetryka marked this pull request as ready for review March 4, 2024 23:28
@AndyAyersMS

Copy link
Copy Markdown
Member

/azp run runtime-coreclr gcstress0x3-gcstress0xc

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotas

Copy link
Copy Markdown
Member

Could you please collect some perf numbers to give us an idea about the improvements and regressions in the affected areas? We may want to do some optimizations to mitigate the regressions.

@jkotas

Copy link
Copy Markdown
Member

One small point of concern is that this might make delegate equality checks slower since they rely on checking the methods in the last "slow path" check, which is however always hit for different delegates AFAIR.

The existing code tries to compare MethodInfos as a cheap fast path. Most delegates do not have cached MethodInfo, so this fast path is hit rarely - but it is very cheap, so it is still worth it.

This cheap fast path is not cheap anymore with this change. It may be best to delete the fast path that is trying to compare the MethodInfos and potentially optimize Delegate_InternalEqualMethodHandles instead.

@MichalPetryka

MichalPetryka commented Mar 5, 2024

Copy link
Copy Markdown
ContributorAuthor

Could you please collect some perf numbers to give us an idea about the improvements and regressions in the affected areas? We may want to do some optimizations to mitigate the regressions.

I think the thing that'd need benchmarking here are equality checks and maybe the impact of collectible delegates being stored in the CWT on the GC, the rest of things shouldn't be performance sensitive enough to matter I think? I'm not fully sure what'd be the proper way for benchmarking the latter.

This cheap fast path is not cheap anymore with this change. It may be best to delete the fast path that is trying to compare the MethodInfos and potentially optimize Delegate_InternalEqualMethodHandles instead.

I am going to benchmark the impact of the equality change tomorrow, I feel like if the impact won't be big, potential optimizations to it can be done later.

@jkotas

Copy link
Copy Markdown
Member

I'm not fully sure what'd be the proper way for benchmarking the latter.

Write a small program that loads an assembly as collectible and calls a method in it. The method in collectible assembly can create delegates in a loop. (If you would like to do it under benchmarknet, it works too - but it is probably more work.)

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.

Pull request overview

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

Comments suppressed due to low confidence (1)

src/native/managed/cdac/tests/UnitTests/ObjectTests.cs:450

  • GetDelegateInfo now has explicit multicast detection via Delegate.HelperObject being an array, but the unit tests no longer exercise that path (the previous "Multicast" test was repurposed to "Unmanaged"). Please add a multicast test that sets HelperObject to an array object and verifies DelegateType.Unknown (and zeroed Target/MethodPtr) for multicast delegates.
 [Theory]
[ClassData(typeof(MockTarget.StdArch))]
public void GetDelegateInfo_Unmanaged(MockTarget.Architecture arch)
{
const ulong TestMethodTable = 0x00000000_10000200;
const ulong TestMethodPtr = 0x00000000_aaaa0000;
const long TestExtraData = -1;
TargetPointer delegateAddress = default;
IObject contract = CreateObjectContract(
arch,
objectBuilder =>
{
delegateAddress = objectBuilder.AddDelegateObject(
methodTable: TestMethodTable,
target: 0,
methodPtr: TestMethodPtr,
methodPtrAux: 0,
extraData: TestExtraData);
});
DelegateInfo info = contract.GetDelegateInfo(delegateAddress);
Assert.Equal(DelegateType.Unknown, info.DelegateType);
Assert.Equal(0ul, info.TargetObject.Value);
Assert.Equal(0ul, info.TargetMethodPtr.Value);
}

Comment threadsrc/coreclr/vm/stubmgr.cpp
Comment threaddocs/design/datacontracts/Object.md
@jkotas

Copy link
Copy Markdown
Member

LGTM once the remaining feedback is addressed

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

LGTM once the remaining feedback is addressed

I'll get to it tomorrow

Comment threadsrc/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs Outdated
AaronRobinsonMSFT added a commit that referenced this pull request Jul 14, 2026
Fix Delegate.GetHashCode to return same hashcodes for type-equivalent
delegates pointing to the same method. Delegate.Equals returns true for
such delegates. GetHashCode contract requires hashcode to be the same in
that case.
Found during codereview of #99200
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Michał Petryka <35800402+MichalPetryka@users.noreply.github.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas I think everything should be ready, I decided to go with IsClosed after looking at all the places and it seemed cleaner to me everywhere but I can revert it if you don't like it.

@jkotas

Copy link
Copy Markdown
Member

/ba-g infrastructure timeouts

@jkotas
jkotas merged commit 3549857 into dotnet:mainJul 14, 2026
179 of 181 checks passed
@jkotas

Copy link
Copy Markdown
Member

Thank you! There are two follow up changes that I would like to see (two separate PRs):

  • Move everything from MulticastDelegate.CoreCLR.cs to Delegate.CoreCLR.cs
  • Change object[] to Wrapper[] like what it is in NativeAOT to avoid casts and covariance checks
    Do you plan to work on these?

@jkotasjkotas added the tenet-performance Performance related issue label Jul 14, 2026
@jkotas

Copy link
Copy Markdown
Member

Move everything from MulticastDelegate.CoreCLR.cs to Delegate.CoreCLR.cs

Actually, let me do this one - it is trivial and it is going to fix app compat break #130612

eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Fix Delegate.GetHashCode to return same hashcodes for type-equivalent
delegates pointing to the same method. Delegate.Equals returns true for
such delegates. GetHashCode contract requires hashcode to be the same in
that case.
Found during codereview of #99200
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Michał Petryka <35800402+MichalPetryka@users.noreply.github.com>
Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 15, 2026
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 15, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrtenet-performancePerformance related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@MichalPetryka@AndyAyersMS@jkotas@MichalStrehovsky@Sergio0694@jakobbotsch@max-charlamb@rcj1