| File: parent\parent\Common\Compiler\CachingVirtualMethodAlgorithm.cs | Web Access |
| Project: ILCompiler.Compiler.csproj (ILCompiler.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using Internal.TypeSystem; namespace ILCompiler { public class CachingVirtualMethodAlgorithm : MetadataVirtualMethodAlgorithm { private readonly ConcurrentDictionary<TypeDesc, (MethodDesc Slot, MethodDesc Implementation)[]> _vtableCache = new ConcurrentDictionary<TypeDesc, (MethodDesc Slot, MethodDesc Implementation)[]>(); private readonly Func<TypeDesc, (MethodDesc Slot, MethodDesc Implementation)[]> _vtableCreator; public CachingVirtualMethodAlgorithm() => _vtableCreator = ComputeVtable; private (MethodDesc Slot, MethodDesc Implementation)[] ComputeVtable(TypeDesc type) { // Do not recompute the same things for all the generics Debug.Assert(type.IsTypeDefinition); var result = new ArrayBuilder<(MethodDesc Slot, MethodDesc Implementation)>(3 /* At least Equals/GetHashCode/ToString */); foreach (MethodDesc slotDecl in base.ComputeAllVirtualSlots(type)) { result.Add((slotDecl, base.FindVirtualFunctionTargetMethodOnObjectType(slotDecl, type))); } return result.ToArray(); } public override IEnumerable<MethodDesc> ComputeAllVirtualSlots(TypeDesc type) { // This just enumerates virtual methods, not worth caching. if (type.IsInterface) return base.ComputeAllVirtualSlots(type); return GetCachedSlots(this, type); static IEnumerable<MethodDesc> GetCachedSlots(CachingVirtualMethodAlgorithm thisObj, TypeDesc type) { foreach ((MethodDesc slot, _) in thisObj._vtableCache.GetOrAdd(type.GetTypeDefinition(), thisObj._vtableCreator)) { yield return type.FindMethodOnTypeWithMatchingTypicalMethod(slot); } } } public override MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, TypeDesc objectType) { MetadataType uninstantiatedType = (MetadataType)objectType.GetTypeDefinition(); MethodDesc targetMethodDefinition = targetMethod.GetMethodDefinition(); MethodDesc slotDefiningMethod = targetMethodDefinition; if (uninstantiatedType != objectType) { slotDefiningMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(slotDefiningMethod); } slotDefiningMethod = FindSlotDefiningMethodForVirtualMethod(slotDefiningMethod); foreach (var kvp in _vtableCache.GetOrAdd(objectType.GetTypeDefinition(), _vtableCreator)) { if (kvp.Slot == slotDefiningMethod) { MethodDesc result = kvp.Implementation; if (uninstantiatedType != objectType) result = objectType.FindMethodOnTypeWithMatchingTypicalMethod(result); if (targetMethod != targetMethodDefinition) result = result.MakeInstantiatedMethod(targetMethod.Instantiation); return result; } } return null; } } }