File: src\System\Runtime\CompilerServices\VirtualDispatchHelpers.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.InteropServices;
 
namespace System.Runtime.CompilerServices;
 
[StackTraceHidden]
[DebuggerStepThrough]
internal static unsafe partial class VirtualDispatchHelpers
{
    private struct VirtualResolutionData : IEquatable<VirtualResolutionData>
    {
        public int _hashCode;
        public MethodTable* _objectMethodTable;
        public IntPtr _classHandle;
        public IntPtr _methodHandle;
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public VirtualResolutionData(MethodTable* objectMethodTable, IntPtr classHandle, IntPtr methodHandle)
        {
            _hashCode = (int) ((uint)objectMethodTable + (BitOperations.RotateLeft((uint)classHandle, 5)) + (BitOperations.RotateRight((uint)methodHandle, 5)));
            _objectMethodTable = objectMethodTable;
            _classHandle = classHandle;
            _methodHandle = methodHandle;
        }
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool Equals(VirtualResolutionData other) =>
            _hashCode == other._hashCode &&
            (((nint)_objectMethodTable - (nint)other._objectMethodTable) |
            (_classHandle - other._classHandle) |
            (_methodHandle - other._methodHandle)) == 0;
 
        public override bool Equals(object? obj) => obj is VirtualResolutionData other && Equals(other);
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override int GetHashCode() => _hashCode;
    }
 
    private struct VirtualFunctionPointerArgs
    {
        public IntPtr classHnd;
        public IntPtr methodHnd;
    };
 
#if DEBUG
        // use smaller numbers to hit resizing/preempting logic in debug
        private const int InitialCacheSize = 8; // MUST BE A POWER OF TWO
        private const int MaximumCacheSize = 512;
#else
        private const int InitialCacheSize = 128; // MUST BE A POWER OF TWO
        private const int MaximumCacheSize = 8 * 1024;
#endif // DEBUG
 
    private static GenericCache<VirtualResolutionData, IntPtr> s_virtualFunctionPointerCache = new GenericCache<VirtualResolutionData, IntPtr>(InitialCacheSize, MaximumCacheSize);
 
    [LibraryImport(RuntimeHelpers.QCall)]
    private static unsafe partial IntPtr ResolveVirtualFunctionPointer(ObjectHandleOnStack obj, IntPtr classHandle, IntPtr methodHandle);
 
    [MethodImpl(MethodImplOptions.NoInlining)]
    [DebuggerHidden]
    private static unsafe IntPtr VirtualFunctionPointerSlow(object obj, IntPtr classHandle, IntPtr methodHandle)
    {
        IntPtr result = ResolveVirtualFunctionPointer(ObjectHandleOnStack.Create(ref obj), classHandle, methodHandle);
        s_virtualFunctionPointerCache.TrySet(new VirtualResolutionData(RuntimeHelpers.GetMethodTable(obj), classHandle, methodHandle), result);
        GC.KeepAlive(obj);
        return result;
    }
 
    [DebuggerHidden]
    private static unsafe IntPtr VirtualFunctionPointer(object obj, IntPtr classHandle, IntPtr methodHandle)
    {
        if (s_virtualFunctionPointerCache.TryGet(new VirtualResolutionData(RuntimeHelpers.GetMethodTable(obj), classHandle, methodHandle), out IntPtr result))
        {
            return result;
        }
        return VirtualFunctionPointerSlow(obj, classHandle, methodHandle);
    }
 
    [DebuggerHidden]
    private static unsafe IntPtr VirtualFunctionPointer_Dynamic(object obj, ref VirtualFunctionPointerArgs virtualFunctionPointerArgs)
    {
        IntPtr classHandle = virtualFunctionPointerArgs.classHnd;
        IntPtr methodHandle = virtualFunctionPointerArgs.methodHnd;
 
        if (s_virtualFunctionPointerCache.TryGet(new VirtualResolutionData(RuntimeHelpers.GetMethodTable(obj), classHandle, methodHandle), out IntPtr result))
        {
            return result;
        }
        return VirtualFunctionPointerSlow(obj, classHandle, methodHandle);
    }
}