Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use a by-ref and explicitly use Cache vs CacheIfExists.
  • Loading branch information
jkoritzinsky committed May 14, 2024
commit dd7ae9e03ac6f1cab46193da015923d281d6115e
Original file line number Diff line number Diff line change
Expand Up @@ -1499,11 +1499,7 @@ private MemberInfoCache<T> GetMemberCache<T>(ref MemberInfoCache<T>? m_cache)

#region Internal Members

internal object? GenericCache
{
get => m_genericCache;
set => m_genericCache = value;
}
internal ref object? GenericCache => ref m_genericCache;

private sealed class FunctionPointerCache : IGenericCacheEntry<FunctionPointerCache>
{
Expand Down Expand Up @@ -1933,15 +1929,6 @@ internal FieldInfo GetField(RuntimeFieldHandleInternal field)
return retval;
}

/// <summary>
/// Generic cache for rare scenario specific data. See <see cref="IGenericCacheEntry" /> for more information on what data can be cached here.
/// </summary>
internal object? GenericCache
{
get => CacheIfExists?.GenericCache;
set => Cache.GenericCache = value;
}

internal T GetOrCreateCacheEntry<T>()
where T : class, IGenericCacheEntry<T>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace System
internal sealed partial class RuntimeType
{
/// <summary>
/// A base interface for all cache entries that can be stored in <see cref="RuntimeType.GenericCache"/>.
/// A base interface for all cache entries that can be stored in <see cref="RuntimeTypeCache.GenericCache"/>.
/// </summary>
internal interface IGenericCacheEntry
{
/// <summary>
/// The different kinds of entries that can be stored in <see cref="RuntimeType.GenericCache"/>.
/// The different kinds of entries that can be stored in <see cref="RuntimeTypeCache.GenericCache"/>.
/// </summary>
protected enum GenericCacheKind
{
Expand Down Expand Up @@ -74,7 +74,7 @@ public IGenericCacheEntry OverwriteNestedCache<T>(T cache)

/// <summary>
/// A typed cache entry. This type provides a base type that handles contruction of entries and maintenance of
/// the <see cref="RuntimeType.GenericCache"/> storage.
/// the <see cref="RuntimeTypeCache.GenericCache"/> in a <see cref="RuntimeType"/> .
/// </summary>
/// <typeparam name="TCache">The cache entry type.</typeparam>
internal interface IGenericCacheEntry<TCache> : IGenericCacheEntry
Expand All @@ -84,39 +84,33 @@ internal interface IGenericCacheEntry<TCache> : IGenericCacheEntry

public static abstract TCache Create(RuntimeType type);

private static CompositeCacheEntry GetOrUpgradeToCompositeCache(RuntimeType type)
private static CompositeCacheEntry GetOrUpgradeToCompositeCache(ref object currentCache)
{
// We may have multiple threads racing to add a new entry to the cache, causing an upgrade to a composite cache.
// If we lose the race, it's okay (we'll re-create the missing entry again on another thread)
// and trying to make the code resilient to this would be more expensive.
// Just make sure we read the cache field once and set it if we need to update it.
var maybeCompositeCache = type.GenericCache;

Debug.Assert(maybeCompositeCache is not null);
if (maybeCompositeCache is not CompositeCacheEntry composite)
if (currentCache is not CompositeCacheEntry composite)
{
// Convert the current cache into a composite cache.
composite = CompositeCacheEntry.Create((IGenericCacheEntry)maybeCompositeCache!);
type.GenericCache = composite;
composite = CompositeCacheEntry.Create((IGenericCacheEntry)currentCache);
currentCache = composite;
}

return composite;
}

public static TCache GetOrCreate(RuntimeType type)
{
if (type.GenericCache is null)
ref object? genericCache = ref type.Cache.GenericCache;
if (genericCache is null)
{
TCache newCache = TCache.Create(type);
type.GenericCache = newCache;
genericCache = newCache;
return newCache;
}
else if (type.GenericCache is TCache existing)
else if (genericCache is TCache existing)
{
return existing;
}

CompositeCacheEntry composite = GetOrUpgradeToCompositeCache(type);
CompositeCacheEntry composite = GetOrUpgradeToCompositeCache(ref genericCache);

if (composite.GetNestedCache(TCache.Kind) is TCache cache)
{
Expand All @@ -128,15 +122,16 @@ public static TCache GetOrCreate(RuntimeType type)

public static TCache? Find(RuntimeType type)
{
if (type.GenericCache is null)
object? genericCache = type.CacheIfExists?.GenericCache;
if (genericCache is null)
{
return null;
}
else if (type.GenericCache is TCache existing)
else if (genericCache is TCache existing)
{
return existing;
}
else if (type.GenericCache is CompositeCacheEntry composite)
else if (genericCache is CompositeCacheEntry composite)
{
return (TCache)composite.GetNestedCache(TCache.Kind);
}
Expand All @@ -148,9 +143,10 @@ public static TCache GetOrCreate(RuntimeType type)

public static void Overwrite(RuntimeType type, TCache cache)
{
if (type.GenericCache is null)
ref object? genericCache = ref type.Cache.GenericCache;
if (genericCache is null)
{
type.GenericCache = cache;
genericCache = cache;
return;
}

Expand All @@ -159,7 +155,7 @@ public static void Overwrite(RuntimeType type, TCache cache)
// but we can't easily do a lock-free CompareExchange with the current design,
// and we can't assume that we won't have one thread adding another item to the cache
// while another is trying to overwrite the (currently) only entry in the cache.
CompositeCacheEntry composite = GetOrUpgradeToCompositeCache(type);
CompositeCacheEntry composite = GetOrUpgradeToCompositeCache(ref genericCache);

composite.OverwriteNestedCache(cache);
}
Expand Down