| File: Internal\Runtime\CompilerServices\OpenMethodResolver.cs | Web Access |
| Project: src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\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; using System.Collections.Generic; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.Augments; namespace Internal.Runtime.CompilerServices { // This structure is used to resolve a instance method given an object instance. To use this type // 1) New up an instance using one of the constructors below. // 2) Use the ToIntPtr() method to get the interned instance of this type. This will permanently allocate // a block of memory that can be used to represent a virtual method resolution. This memory is interned // so that repeated allocation of the same resolver will not leak. // 3) Use the ResolveMethod function to do the virtual lookup. public unsafe struct OpenMethodResolver : IEquatable<OpenMethodResolver> { public const short DispatchResolve = 0; public const short GVMResolve = 1; public const short OpenNonVirtualResolve = 2; public const short OpenNonVirtualResolveLookthruUnboxing = 3; private readonly short _resolveType; private readonly GCHandle _readerGCHandle; private readonly int _handle; private readonly IntPtr _methodHandleOrSlotOrCodePointer; private readonly IntPtr _nonVirtualOpenInvokeCodePointer; private readonly MethodTable* _declaringType; public OpenMethodResolver(RuntimeTypeHandle declaringTypeOfSlot, int slot, GCHandle readerGCHandle, int handle) { _resolveType = DispatchResolve; _declaringType = declaringTypeOfSlot.ToMethodTable(); _methodHandleOrSlotOrCodePointer = new IntPtr(slot); _handle = handle; _readerGCHandle = readerGCHandle; _nonVirtualOpenInvokeCodePointer = IntPtr.Zero; } public OpenMethodResolver(RuntimeTypeHandle declaringTypeOfSlot, RuntimeMethodHandle gvmSlot, GCHandle readerGCHandle, int handle) { _resolveType = GVMResolve; _methodHandleOrSlotOrCodePointer = *(IntPtr*)&gvmSlot; _declaringType = declaringTypeOfSlot.ToMethodTable(); _handle = handle; _readerGCHandle = readerGCHandle; _nonVirtualOpenInvokeCodePointer = IntPtr.Zero; } public OpenMethodResolver(RuntimeTypeHandle declaringType, IntPtr codePointer, GCHandle readerGCHandle, int handle, short resolveType) { _resolveType = resolveType; _methodHandleOrSlotOrCodePointer = codePointer; _declaringType = declaringType.ToMethodTable(); _handle = handle; _readerGCHandle = readerGCHandle; if (resolveType == OpenNonVirtualResolve) _nonVirtualOpenInvokeCodePointer = codePointer; else if (resolveType == OpenNonVirtualResolveLookthruUnboxing) _nonVirtualOpenInvokeCodePointer = RuntimeAugments.TypeLoaderCallbacks.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(codePointer, declaringType); else throw new NotSupportedException(); } public short ResolverType { get { return _resolveType; } } public RuntimeTypeHandle DeclaringType { get { return new RuntimeTypeHandle(_declaringType); } } public RuntimeMethodHandle GVMMethodHandle { get { IntPtr localIntPtr = _methodHandleOrSlotOrCodePointer; IntPtr* pMethodHandle = &localIntPtr; return *(RuntimeMethodHandle*)pMethodHandle; } } public bool IsOpenNonVirtualResolve { get { switch (_resolveType) { case OpenNonVirtualResolve: case OpenNonVirtualResolveLookthruUnboxing: return true; default: return false; } } } public IntPtr CodePointer { get { return _methodHandleOrSlotOrCodePointer; } } public object Reader { get { return _readerGCHandle.Target; } } public int Handle { get { return _handle; } } private IntPtr ResolveMethod(object thisObject) { if (_resolveType == DispatchResolve) { return RuntimeImports.RhResolveDispatch(thisObject, _declaringType, (ushort)_methodHandleOrSlotOrCodePointer); } else if (_resolveType == GVMResolve) { return GVMMethodHandle.ResolveGenericVirtualMethodTarget(thisObject); } else { throw new NotSupportedException(); // Should never happen, in this case, the dispatch should be resolved in the other ResolveMethod function } } internal static IntPtr ResolveMethodWorker(IntPtr resolver, object thisObject) { return ((OpenMethodResolver*)resolver)->ResolveMethod(thisObject); } public static IntPtr ResolveMethod(IntPtr resolver, object thisObject) { IntPtr nonVirtualOpenInvokeCodePointer = ((OpenMethodResolver*)resolver)->_nonVirtualOpenInvokeCodePointer; if (nonVirtualOpenInvokeCodePointer != IntPtr.Zero) return nonVirtualOpenInvokeCodePointer; return TypeLoaderExports.OpenInstanceMethodLookup(resolver, thisObject); } public static IntPtr ResolveMethod(IntPtr resolverPtr, RuntimeTypeHandle thisType) { OpenMethodResolver* resolver = ((OpenMethodResolver*)resolverPtr); IntPtr nonVirtualOpenInvokeCodePointer = resolver->_nonVirtualOpenInvokeCodePointer; if (nonVirtualOpenInvokeCodePointer != IntPtr.Zero) return nonVirtualOpenInvokeCodePointer; return RuntimeImports.RhResolveDispatchOnType(thisType.ToMethodTable(), resolver->_declaringType, (ushort)resolver->_methodHandleOrSlotOrCodePointer); } private static int CalcHashCode(int hashCode1, int hashCode2, int hashCode3, int hashCode4) { int length = 4; int hash1 = 0x449b3ad6; int hash2 = (length << 3) + 0x55399219; hash1 = (hash1 + int.RotateLeft(hash1, 5)) ^ hashCode1; hash2 = (hash2 + int.RotateLeft(hash2, 5)) ^ hashCode2; hash1 = (hash1 + int.RotateLeft(hash1, 5)) ^ hashCode3; hash2 = (hash2 + int.RotateLeft(hash2, 5)) ^ hashCode4; hash1 += int.RotateLeft(hash1, 8); hash2 += int.RotateLeft(hash2, 8); return hash1 ^ hash2; } public override int GetHashCode() { return CalcHashCode(_resolveType, _handle, _methodHandleOrSlotOrCodePointer.GetHashCode(), _declaringType == null ? 0 : (int)_declaringType->HashCode); } public bool Equals(OpenMethodResolver other) { if (other._resolveType != _resolveType) return false; if (other._handle != _handle) return false; if (other._methodHandleOrSlotOrCodePointer != _methodHandleOrSlotOrCodePointer) return false; return other._declaringType == _declaringType; } public override bool Equals(object? obj) { if (!(obj is OpenMethodResolver)) { return false; } return ((OpenMethodResolver)obj).Equals(this); } private static LowLevelDictionary<OpenMethodResolver, IntPtr> s_internedResolverHash = new LowLevelDictionary<OpenMethodResolver, IntPtr>(); public IntPtr ToIntPtr() { lock (s_internedResolverHash) { IntPtr returnValue; if (s_internedResolverHash.TryGetValue(this, out returnValue)) return returnValue; returnValue = (IntPtr)NativeMemory.Alloc((nuint)sizeof(OpenMethodResolver)); *((OpenMethodResolver*)returnValue) = this; s_internedResolverHash.Add(this, returnValue); return returnValue; } } } }