Skip to content

Conversation

@ericstj
Copy link
Member

@ericstj ericstj commented Sep 16, 2025

Fixes #119499

@jkotas let me know what you think. It turns out IsCollectible wasn't fast enough to put on this hot path. I'm assuming it's safe to cache it for a type and I found other fields were already cached. I made it cached lazily so that we don't impact every user of reflection that hits this cache.

CC @alexey-zakharov

Copilot AI review requested due to automatic review settings September 16, 2025 01:40
@ericstj ericstj self-assigned this Sep 16, 2025
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Sep 16, 2025
@ericstj ericstj added area-System.Reflection and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Sep 16, 2025
Copy link
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 improves performance by caching the IsCollectible property value for RuntimeType instances. The change addresses a performance issue where the IsCollectible property was being called frequently on a hot path but wasn't fast enough due to its underlying P/Invoke call.

Key changes:

  • Adds lazy caching of the IsCollectible value in the RuntimeTypeCache class
  • Replaces the direct P/Invoke implementation with a cached property accessor

Comment on lines +1556 to +1560
if (!m_isCollectible.HasValue)
{
RuntimeType type = m_runtimeType;
m_isCollectible = RuntimeTypeHandle.IsCollectible(new QCallTypeHandle(ref type)) != Interop.BOOL.FALSE;
}
Copy link

Copilot AI Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lazy initialization of m_isCollectible is not thread-safe. Multiple threads could simultaneously check HasValue, find it false, and then race to set the value. Consider using Volatile.Read/Volatile.Write or a lock to ensure thread safety, or accept that the P/Invoke might be called multiple times initially if that's acceptable for this use case.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is valid feedback

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usual way to deal with this problem is a tri-state enum like this:

private enum Tristate : byte
{
NotInitialized = 0,
False = 1,
True = 2
}

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

@MichalPetryka

This comment was marked as resolved.

@jkotas
Copy link
Member

jkotas commented Sep 16, 2025

@jkotas let me know what you think.

I would rather fix this by making the FCall faster.

@jkotas
Copy link
Member

jkotas commented Sep 16, 2025

I would rather fix this by making the FCall faster.

#119743

@jkotas
Copy link
Member

jkotas commented Sep 16, 2025

@EgorBot -intel

using BenchmarkDotNet.Attributes;

public class Bench
{
    [Benchmark]
    public bool IsCollectible() => typeof(object).IsCollectible;
}

@jkotas
Copy link
Member

jkotas commented Sep 16, 2025

#119743 makes the implementation even faster than the reflection cache while avoiding the extra memory footprint of the reflection cache.

@ericstj
Copy link
Member Author

ericstj commented Sep 16, 2025

Ok. I will close this for now. I'll benchmark your PR in the impacted TypeConverter benchmark this was fixing.

@ericstj ericstj closed this Sep 16, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Oct 17, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Windows/x64: 11 Regressions on 9/4/2025 12:05:32 AM +00:00

3 participants