diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 55e5f4c77a7680..46ee97b9842b92 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -232,6 +232,41 @@ public static void PrepareDelegate(Delegate d) PrepareDelegate(ObjectHandleOnStack.Create(ref d)); } + [MethodImpl(MethodImplOptions.NoInlining)] + private static unsafe TDelegate CreateSharedDelegate(nint method, ref TDelegate? storage) where TDelegate : Delegate + { + Debug.Assert(typeof(TDelegate) is RuntimeType); + Debug.Assert(typeof(TDelegate).IsAssignableTo(typeof(Delegate))); + + MethodTable* methodTable = ((RuntimeType)typeof(TDelegate)).GetNativeTypeHandle().AsMethodTable(); + + Delegate newDelegate = CreateSharedDelegateHelper(method, ref Unsafe.As(ref storage), methodTable); + Debug.Assert(newDelegate is TDelegate); + return Unsafe.As(newDelegate); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static unsafe Delegate CreateSharedDelegateHelper(nint method, ref Delegate? storage, MethodTable* pMT) + { + ArgumentNullException.ThrowIfNull(method); + + Debug.Assert(RuntimeTypeHandle.GetRuntimeType(pMT).IsDelegate()); + + Delegate? newDelegate = null; + CreateDelegate(method, pMT, ObjectHandleOnStack.Create(ref newDelegate)); + + if (newDelegate is null) + { + throw new NotSupportedException(); + } + + Debug.Assert(newDelegate.GetType() == RuntimeTypeHandle.GetRuntimeType(pMT)); + return Interlocked.CompareExchange(ref storage, newDelegate, null) ?? newDelegate; + } + + [LibraryImport(QCall, EntryPoint = "Delegate_CreateDelegate")] + private static unsafe partial void CreateDelegate(nint method, MethodTable* pMT, ObjectHandleOnStack objHandle); + /// /// If a hash code has been assigned to the object, it is returned. Otherwise zero is /// returned. diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 93c37d0a7e5c3a..07aee298ebbb50 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -590,6 +590,8 @@ enum CorInfoHelpFunc CORINFO_HELP_ALLOC_CONTINUATION_METHOD, CORINFO_HELP_ALLOC_CONTINUATION_CLASS, + CORINFO_HELP_CREATE_DELEGATE, + CORINFO_HELP_COUNT, }; diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 281302ccbc742c..1af81ae9c838ff 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -369,6 +369,8 @@ DYNAMICJITHELPER(CORINFO_HELP_ALLOC_CONTINUATION_METHOD, NULL, METHOD__ASYNC_HELPERS__ALLOC_CONTINUATION_METHOD) DYNAMICJITHELPER(CORINFO_HELP_ALLOC_CONTINUATION_CLASS, NULL, METHOD__ASYNC_HELPERS__ALLOC_CONTINUATION_CLASS) + DYNAMICJITHELPER(CORINFO_HELP_CREATE_DELEGATE, NULL, METHOD__RUNTIME_HELPERS__CREATE_SHARED_DELEGATE_HELPER) + #undef JITHELPER #undef DYNAMICJITHELPER #undef JITHELPER diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7fd54532ce41b3..4ab87733f47d40 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3550,6 +3550,7 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, case NI_System_Activator_AllocatorOf: case NI_System_Activator_DefaultConstructorOf: case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences: + case NI_System_Runtime_CompilerServices_RuntimeHelpers_GetDelegate: mustExpand = true; break; @@ -3694,6 +3695,126 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, break; } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_GetDelegate: + { + assert(sig->sigInst.methInstCount == 1); + + GenTree* aotInfo = nullptr; + if (IsNativeAot()) + { + StackEntry methodStack = impStackTop(1); + + CORINFO_METHOD_HANDLE targetMethod = NO_METHOD_HANDLE; + if (methodStack.val->OperIs(GT_FTN_ADDR)) + { + targetMethod = methodStack.val->AsFptrVal()->gtFptrMethod; + } + else if (methodStack.seTypeInfo.IsMethod()) + { + targetMethod = methodStack.seTypeInfo.GetMethodPointerInfo()->m_token.hMethod; + } + + if (targetMethod == NO_METHOD_HANDLE) + { + JITDUMP("Delegate literals on NativeAOT require a direct ftn ptr\n"); + return nullptr; + } + + CORINFO_SIG_INFO callSig; + info.compCompHnd->getMethodSig(targetMethod, &callSig); + + CORINFO_CLASS_HANDLE closureType = NO_CLASS_HANDLE; + if (callSig.hasThis()) + { + closureType = info.compCompHnd->getMethodClass(targetMethod); + } + else if (callSig.numArgs != 0) + { + info.compCompHnd->getArgType(&callSig, callSig.args, &closureType); + } + + bool throwIfClosed = closureType == NO_CLASS_HANDLE || eeIsValueClass(closureType); + if (!throwIfClosed && callSig.hasThis()) + { + assert(closureType != NO_CLASS_HANDLE); + TypeCompareState state = info.compCompHnd->isGenericType(closureType); + // we should always see the declaring type enough to know if it's generic + assert(state != TypeCompareState::May); + + throwIfClosed = state == TypeCompareState::Must; + } + + uint32_t infoBits = callSig.hasThis() ? 0 : 1; + infoBits |= throwIfClosed ? 2 : 0; + infoBits |= callSig.totalILArgs() << 2; + aotInfo = gtNewIconNode(infoBits); + + JITDUMP( + "NativeAOT delegate creation info: method %s closure %s static %u throw if closed %u args %u\n", + eeGetMethodFullName(targetMethod), + closureType == NO_CLASS_HANDLE ? "none" : eeGetClassName(closureType), infoBits & 1, + infoBits >> 1 & 1, infoBits >> 2); + } + + CORINFO_SIG_INFO exactSig; + info.compCompHnd->getMethodSig(pResolvedToken->hMethod, &exactSig); + CORINFO_CLASS_HANDLE delegateType = exactSig.sigInst.methInst[0]; + + GenTree* delegateMT; + bool isShared = eeIsSharedInst(delegateType); + if (isShared) + { + if (!IsNativeAot()) + { + // TODO: impl lookups for delegate type on CoreCLR + return nullptr; + } + + CORINFO_RESOLVED_TOKEN resolvedToken; + resolvedToken.tokenContext = impTokenLookupContextHandle; + resolvedToken.tokenScope = info.compScopeHnd; + resolvedToken.token = memberRef; + resolvedToken.tokenType = CORINFO_TOKENKIND_Method; + + CORINFO_GENERICHANDLE_RESULT embedInfo; + info.compCompHnd->expandRawHandleIntrinsic(&resolvedToken, info.compMethodHnd, &embedInfo); + + delegateMT = + impLookupToTree(&embedInfo.lookup, gtTokenToIconFlags(memberRef), embedInfo.compileTimeHandle); + } + else + { + delegateMT = gtNewIconEmbClsHndNode(delegateType); + } + + GenTree* storage = impPopStack().val; + GenTree* methodPtr = impPopStack().val; + + GenTree* storageClone; + storage = impCloneExpr(storage, &storageClone, CHECK_SPILL_ALL, + nullptr DEBUGARG("RuntimeHelpers.GetDelegate storage")); + + unsigned delegateSlot = lvaGrabTemp(false DEBUGARG("delegateSlot")); + impStoreToTemp(delegateSlot, gtNewIndir(TYP_REF, storage), CHECK_SPILL_ALL); + + GenTreeOp* nullcheck = gtNewOperNode(GT_EQ, TYP_INT, gtNewLclVarNode(delegateSlot), gtNewNull()); + + GenTreeCall* helper = gtNewHelperCallNode(CORINFO_HELP_CREATE_DELEGATE, TYP_REF, methodPtr, + storageClone, delegateMT, aotInfo); + + GenTree* storeCold = gtNewTempStore(delegateSlot, helper); + GenTreeColon* colon = gtNewColonNode(TYP_VOID, storeCold, gtNewNothingNode()); + GenTreeQmark* qmark = gtNewQmarkNode(TYP_VOID, nullcheck, colon); + qmark->SetThenNodeLikelihood(0); + + impAppendTree(qmark, CHECK_SPILL_ALL, impCurStmtDI); + + lvaSetClass(delegateSlot, delegateType, !isShared); + retNode = gtNewLclVarNode(delegateSlot); + JITDUMP("Expanded GetDelegate for %s\n", eeGetClassName(delegateType)); + break; + } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: { GenTree* op1 = impPopStack().val; @@ -11185,6 +11306,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray; } + else if (strcmp(methodName, "GetDelegate") == 0) + { + result = NI_System_Runtime_CompilerServices_RuntimeHelpers_GetDelegate; + } else if (strcmp(methodName, "IsKnownConstant") == 0) { result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 80c1fea64ad444..68aaa49c295496 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -122,6 +122,7 @@ enum NamedIntrinsic : unsigned short NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan, NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray, + NI_System_Runtime_CompilerServices_RuntimeHelpers_GetDelegate, NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant, NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences, NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable, diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 86300e47383b0f..d47690167e1a9b 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1771,6 +1771,11 @@ void HelperCallProperties::init() isAllocator = true; break; + case CORINFO_HELP_CREATE_DELEGATE: + mutatesHeap = true; + nonNullReturn = true; + break; + default: // The most pessimistic results are returned for these helpers. mutatesHeap = true; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/FrozenObjectHeapManager.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/FrozenObjectHeapManager.cs index e9b41c447b84e5..c04d49f5599dba 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/FrozenObjectHeapManager.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/FrozenObjectHeapManager.cs @@ -27,7 +27,13 @@ internal unsafe partial class FrozenObjectHeapManager public T? TryAllocateObject() where T : class { MethodTable* pMT = MethodTable.Of(); - return Unsafe.As(TryAllocateObject(pMT, pMT->BaseSize)); + return Unsafe.As(TryAllocateObject(pMT)); + } + + public object TryAllocateObject(MethodTable* pMT) + { + Debug.Assert(!pMT->IsValueType); + return TryAllocateObject(pMT, pMT->BaseSize); } private object? TryAllocateObject(MethodTable* type, nuint objectSize) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs index 9968de32d01574..f1bf889edcd4ad 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Delegate.cs @@ -416,6 +416,12 @@ internal static unsafe Delegate CreateDelegate(MethodTable* delegateEEType, IntP Delegate del = (Delegate)RuntimeImports.RhNewObject(delegateEEType); + FillDelegate(del, ldftnResult, thisObject, isStatic, isOpen); + return del; + } + + internal static void FillDelegate(Delegate del, nint ldftnResult, object thisObject, bool isStatic, bool isOpen) + { // What? No constructor call? That's right, and it's not an oversight. All "construction" work happens in // the Initialize() methods. This helper has a hard dependency on this invariant. @@ -444,7 +450,6 @@ internal static unsafe Delegate CreateDelegate(MethodTable* delegateEEType, IntP del.InitializeClosedInstanceWithoutNullCheck(thisObject, ldftnResult); } } - return del; } private unsafe Delegate NewMulticastDelegate(Wrapper[] invocationList, int invocationCount, bool thisIsMultiCastAlready = false) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs index 5d25312088a767..d5304a5fe74b57 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs @@ -1,14 +1,17 @@ // 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.CodeAnalysis; using System.Numerics; +using System.Reflection; +using System.Reflection.Runtime.General; +using System.Reflection.Runtime.MethodInfos; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Threading; using Internal.Reflection.Augments; -using Internal.Reflection.Core.Execution; using Internal.Runtime; using Internal.Runtime.Augments; @@ -277,6 +280,113 @@ public static void PrepareDelegate(Delegate d) { } + [MethodImpl(MethodImplOptions.NoInlining)] + private static unsafe TDelegate CreateSharedDelegate(nint method, ref TDelegate? storage) where TDelegate : Delegate + { + ArgumentNullException.ThrowIfNull(method); + + Debug.Assert(typeof(TDelegate).IsAssignableTo(typeof(Delegate))); + + MethodBase? methodBase = ReflectionAugments.GetMethodBaseFromStartAddressIfAvailable(method); + + if (methodBase == null) + { + throw new PlatformNotSupportedException(); + } + + ReadOnlySpan parameters = methodBase.GetParametersAsSpan(); + + int paramCount = parameters.Length; + bool isStatic = methodBase.IsStatic; + + Type? closureType; + if (isStatic) + { + closureType = parameters.Length > 0 ? parameters[0].ParameterType : null; + } + else + { + closureType = methodBase.DeclaringType; + paramCount++; // count 'this' + } + bool throwIfClosed = closureType is null || closureType.IsValueType || + (!isStatic && closureType.IsGenericType); + + uint info = isStatic ? 1u : 0u; + info |= throwIfClosed ? 2u : 0u; + info |= (uint)paramCount << 2; + + Delegate newDelegate = CreateSharedDelegateHelper(method, ref Unsafe.As(ref storage), MethodTable.Of(), info); + Debug.Assert(newDelegate is TDelegate); + return Unsafe.As(newDelegate); + } + + // This method is used by the JIT as a helper + [MethodImpl(MethodImplOptions.NoInlining)] + private static unsafe Delegate CreateSharedDelegateHelper(nint method, ref Delegate? storage, MethodTable* pMT, uint info) + { + RuntimeType delegateType = Type.GetTypeFromMethodTable(pMT); + Debug.Assert(delegateType.GetRuntimeTypeInfo().IsDelegate); + + bool isStatic = (info & 1) != 0; + bool throwIfClosed = (info & 2) != 0; + int paramCount = (int)(info >> 2); + + MethodInfo invokeMethod = Delegate.GetInvokeMethod(delegateType); + int invokeCount = invokeMethod.GetParametersAsSpan().Length; + + bool isOpen = invokeCount == paramCount; + + // reject cases needing valid instances + // we block delegates closed over null valuetypes since we'd just always NRE in the unboxing stub + // reject instance methods on generic types, those require proper targets + if (!isOpen && throwIfClosed) + { + throw new NotSupportedException(); + } + + Delegate? newDelegate = null; + lock (FrozenDelegateCache.CacheLock) + { + ref Delegate? reference = ref CollectionsMarshal.GetValueRefOrAddDefault(FrozenDelegateCache.Cache, (method, delegateType), out bool exists); + if (exists) + { + Debug.Assert(reference.GetType() == delegateType); + newDelegate = reference; + } + else + { + object frozen = FrozenObjectHeapManager.Instance.TryAllocateObject(pMT); + if (frozen is not null) + { + Debug.Assert(frozen.GetType() == delegateType); + newDelegate = Unsafe.As(frozen); + Delegate.FillDelegate(newDelegate, method, null, isStatic, isOpen); + + reference = newDelegate; + } + } + } + + if (newDelegate is null) + { + object nonPinned = RuntimeImports.RhNewObject(pMT); + + Debug.Assert(nonPinned.GetType() == delegateType); + newDelegate = Unsafe.As(nonPinned); + Delegate.FillDelegate(newDelegate, method, null, isStatic, isOpen); + } + + Debug.Assert(newDelegate is not null); + return Interlocked.CompareExchange(ref storage, newDelegate, null) ?? newDelegate; + } + + private static class FrozenDelegateCache + { + public static readonly Lock CacheLock = new(); + public static readonly Dictionary<(nint, Type), Delegate> Cache = []; + } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:UnrecognizedReflectionPattern", Justification = "Constructed MethodTable of a Nullable forces a constructed MethodTable of the element type")] public static unsafe object GetUninitializedObject( diff --git a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs index f70b278f2de695..c43246bf84c714 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs @@ -401,6 +401,8 @@ public enum ReadyToRunHelper TypeHandleToRuntimeType, GetRefAny, TypeHandleToRuntimeTypeHandle, + + CreateSharedDelegate, } // Enum used for HFA type recognition. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index 68f7b52f6ec048..bdf102c7f5f228 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -287,6 +287,8 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_ALLOC_CONTINUATION_METHOD, CORINFO_HELP_ALLOC_CONTINUATION_CLASS, + CORINFO_HELP_CREATE_DELEGATE, + CORINFO_HELP_COUNT, } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index 332aa401bca13b..d9d8a42dd08811 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -339,6 +339,10 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, methodDesc = context.GetCoreLibEntryPoint("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8, "AllocContinuation"u8, null); break; + case ReadyToRunHelper.CreateSharedDelegate: + methodDesc = context.GetCoreLibEntryPoint("System.Runtime.CompilerServices"u8, "RuntimeHelpers"u8, "CreateSharedDelegateHelper"u8, null); + break; + default: throw new NotImplementedException(id.ToString()); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index c61590199c91f9..da8a581181cf7f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -592,6 +592,46 @@ private void ImportCall(ILOpcode opcode, MethodDesc method, MethodDesc runtimeDe return; } + if (IsRuntimeHelpersGetDelegate(method)) + { + if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod) + { + _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.ObjectAllocator, runtimeDeterminedMethod.Instantiation[0]), reason); + _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, runtimeDeterminedMethod.Instantiation[0]), reason); + } + else + { + _dependencies.Add(_compilation.ComputeConstantLookup(ReadyToRunHelperId.ObjectAllocator, method.Instantiation[0]), reason); + _dependencies.Add(_factory.ConstructedTypeSymbol(method.Instantiation[0]), reason); + } + + // Is this a verifiable delegate creation sequence? + if (_currentOffset >= 11 + && _basicBlocks[_currentOffset] == null + && _ilBytes[_currentOffset - 11] == (byte)ILOpcode.prefix1 + && (_ilBytes[_currentOffset - 10] == unchecked((byte)ILOpcode.ldftn) || + _ilBytes[_currentOffset - 10] == unchecked((byte)ILOpcode.ldvirtftn))) + { + int targetToken = ReadILTokenAt(_currentOffset - 9); + var delegateMethod = (MethodDesc)_methodIL.GetObject(targetToken); + if (!delegateMethod.Signature.IsStatic) + { + var owningType = delegateMethod.OwningType; + if (owningType.IsRuntimeDeterminedSubtype) + { + _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, owningType), reason); + } + else + { + _dependencies.Add(_factory.ConstructedTypeSymbol(owningType), reason); + } + } + } + + _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.CreateSharedDelegate), reason); + // do not return here, we want the method itself rooted too + } + if (opcode != ILOpcode.ldftn) { if (IsRuntimeHelpersIsReferenceOrContainsReferences(method)) @@ -1685,6 +1725,20 @@ private static bool IsEETypePtrOf(MethodDesc method) return false; } + private static bool IsRuntimeHelpersGetDelegate(MethodDesc method) + { + if (method.IsIntrinsic && method.Name == "GetDelegate"u8 && method.Instantiation.Length == 1) + { + MetadataType owningType = method.OwningType as MetadataType; + if (owningType != null) + { + return owningType.Name == "RuntimeHelpers"u8 && owningType.Namespace == "System.Runtime.CompilerServices"u8; + } + } + + return false; + } + private static bool IsRuntimeHelpersIsReferenceOrContainsReferences(MethodDesc method) { if (method.IsIntrinsic && method.Name == "IsReferenceOrContainsReferences"u8 && method.Instantiation.Length == 1) diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index 185f3863a3eb8f..6f22b91f262e55 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -760,6 +760,10 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) id = ReadyToRunHelper.AllocContinuation; break; + case CorInfoHelpFunc.CORINFO_HELP_CREATE_DELEGATE: + id = ReadyToRunHelper.CreateSharedDelegate; + break; + case CorInfoHelpFunc.CORINFO_HELP_GETSYNCFROMCLASSHANDLE: return _compilation.NodeFactory.MethodEntrypoint(_compilation.NodeFactory.TypeSystemContext.GetCoreLibEntryPoint("System"u8, "Type"u8, "GetTypeFromMethodTable"u8, null)); case CorInfoHelpFunc.CORINFO_HELP_GETCLASSFROMMETHODPARAM: @@ -1903,6 +1907,10 @@ private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ComputeLookup(ref pResolvedToken, method.Instantiation[0], ReadyToRunHelperId.ObjectAllocator, HandleToObject(callerHandle), ref pResult.lookup); pResult.handleType = CorInfoGenericHandleType.CORINFO_HANDLETYPE_UNKNOWN; break; + case "GetDelegate": + ComputeLookup(ref pResolvedToken, method.Instantiation[0], ReadyToRunHelperId.TypeHandle, HandleToObject(callerHandle), ref pResult.lookup); + pResult.handleType = CorInfoGenericHandleType.CORINFO_HANDLETYPE_CLASS; + break; default: Debug.Fail("Unexpected raw handle intrinsic"); break; diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index ffa068c905d405..25f4549c64d7e5 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -1808,6 +1808,92 @@ extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, Q END_QCALL; } +DELEGATEREF COMDelegate::CreateShared(MethodDesc* pTargetMD, MethodTable* pMT) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + assert(pTargetMD != NULL); + assert(pMT != NULL); + + if (TypeHandle(pMT).IsCanonicalSubtype()) + { + // this should only be reachable from the JIT + return NULL; + } + + assert(pMT->IsDelegate()); + + MethodTable* declaringType = pTargetMD->GetMethodTable(); + MethodDesc* pDelegateInvoke = FindDelegateInvokeMethod(pMT); + + UINT invokeCount = MethodDescToNumFixedArgs(pDelegateInvoke); + UINT methodCount = MethodDescToNumFixedArgs(pTargetMD); + bool isStatic = pTargetMD->IsStatic(); + if (!isStatic) + { + methodCount++; // count 'this' + } + + bool isOpen = invokeCount == methodCount; + + // reject cases needing valid instances + if (!isOpen) + { + // we block delegates closed over null valuetypes since we'd just always NRE in the unboxing stub + if (isStatic) + { + MetaSig sig(pTargetMD); + if (sig.NextArgNormalized() == ELEMENT_TYPE_END || sig.GetLastTypeHandleThrowing().IsValueType()) + { + return NULL; + } + } + else + { + // reject instance methods on generic types, those require proper targets + if (declaringType->IsValueType() || declaringType->GetNumGenericArgs() != 0) + { + return NULL; + } + } + } + + // we create delegates without a target here + OBJECTREF target = NULL; + DELEGATEREF delegate = NULL; + + GCPROTECT_BEGIN(delegate); + delegate = (DELEGATEREF)AllocateObject(pMT); + BindToMethod(&delegate, &target, pTargetMD, declaringType, isOpen); + GCPROTECT_END(); + + return delegate; +} + +extern "C" void QCALLTYPE Delegate_CreateDelegate(PCODE method, MethodTable* pMT, QCall::ObjectHandleOnStack objHandle) +{ + QCALL_CONTRACT; + + _ASSERTE(method != (PCODE)NULL); + BEGIN_QCALL; + + MethodDesc* methodDesc = NonVirtualEntry2MethodDesc(method); + + { + GCX_COOP(); + DELEGATEREF delegate = COMDelegate::CreateShared(methodDesc, pMT); + objHandle.Set(delegate); + } + + END_QCALL; +} + MethodDesc *COMDelegate::GetMethodDescForOpenVirtualDelegate(OBJECTREF orDelegate) { CONTRACTL diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index 1c95811d017131..0f8924e7300f35 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -41,6 +41,7 @@ class COMDelegate static BOOL NeedsWrapperDelegate(MethodDesc* pTargetMD); // on entry delegate points to the delegate to wrap static DELEGATEREF CreateWrapperDelegate(DELEGATEREF delegate, MethodDesc* pTargetMD); + static DELEGATEREF CreateShared(MethodDesc* pTargetMD, MethodTable* pMT); // Marshals a delegate to a unmanaged callback. static LPVOID ConvertToCallback(OBJECTREF pDelegate); @@ -96,6 +97,7 @@ class COMDelegate }; extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, QCall::ObjectHandleOnStack target, PCODE method); +extern "C" void QCALLTYPE Delegate_CreateDelegate(PCODE method, MethodTable* pMT, QCall::ObjectHandleOnStack objHandle); extern "C" PCODE QCALLTYPE Delegate_GetMulticastInvokeSlow(MethodTable* pDelegateMT); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 5d453720aa0ebb..54a40143b1d7e1 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -691,6 +691,7 @@ DEFINE_METHOD(RUNTIME_HELPERS, ENUM_EQUALS, EnumEquals, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, ENUM_COMPARE_TO, EnumCompareTo, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, ALLOC_TAILCALL_ARG_BUFFER, AllocTailCallArgBuffer, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, DISPATCH_TAILCALLS, DispatchTailCalls, NoSig) +DEFINE_METHOD(RUNTIME_HELPERS, CREATE_SHARED_DELEGATE_HELPER, CreateSharedDelegateHelper, NoSig) #ifdef FEATURE_IJW DEFINE_METHOD(RUNTIME_HELPERS, COPY_CONSTRUCT, CopyConstruct, NoSig) #endif // FEATURE_IJW diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 85b240951b7ca1..e4691367690b9d 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -107,6 +107,7 @@ static const Entry s_QCall[] = DllImportEntry(Delegate_GetMulticastInvokeSlow) DllImportEntry(Delegate_AdjustTarget) DllImportEntry(Delegate_Construct) + DllImportEntry(Delegate_CreateDelegate) DllImportEntry(Delegate_FindMethodHandle) DllImportEntry(Delegate_InternalEqualMethodHandles) DllImportEntry(Environment_Exit) diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index 6efa9f48554fad..e1b143f7f21692 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; @@ -208,5 +209,13 @@ public bool MoveNext() return !ReferenceEquals(d2, d1) && !d2.Equals(d1); } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", + Justification = "The trimmer will never remove the Invoke method from delegates.")] + internal static MethodInfo GetInvokeMethod(RuntimeType delegateType) + { + Debug.Assert(delegateType.IsAssignableTo(typeof(Delegate))); + return delegateType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)!; + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index f9f228e6aea688..fca8cfc1ac3de3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -1,10 +1,12 @@ // 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.Concurrent; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Versioning; namespace System.Runtime.CompilerServices { @@ -162,6 +164,14 @@ public static ReadOnlySpan CreateSpan(RuntimeFieldHandle fldHandle) => new ReadOnlySpan(ref Unsafe.As(ref GetSpanDataFrom(fldHandle, typeof(T).TypeHandle, out int length)), length); #endif + [Intrinsic] + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [RequiresDynamicCode("AOT must recognize usages of the method to preserve reflection info and generate stubs")] + public static TDelegate GetDelegate(nint method, ref TDelegate? storage) where TDelegate : Delegate + { + return storage ?? CreateSharedDelegate(method, ref storage); + } // The following intrinsics return true if input is a compile-time constant // Feel free to add more overloads on demand diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a5ba94532bf8e5..2952ac1924de5e 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -14258,6 +14258,8 @@ public static void PrepareConstrainedRegionsNoOP() { } [System.ObsoleteAttribute("The Constrained Execution Region (CER) feature is not supported.", DiagnosticId="SYSLIB0004", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public static void PrepareContractedDelegate(System.Delegate d) { } public static void PrepareDelegate(System.Delegate d) { } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("AOT must recognize usages of the method to preserve reflection info and generate stubs")] + public static TDelegate GetDelegate(nint method, ref TDelegate? storage) where TDelegate : Delegate { throw null; } public static void PrepareMethod(System.RuntimeMethodHandle method) { } public static void PrepareMethod(System.RuntimeMethodHandle method, System.RuntimeTypeHandle[]? instantiation) { } [System.ObsoleteAttribute("The Constrained Execution Region (CER) feature is not supported.", DiagnosticId="SYSLIB0004", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] diff --git a/src/mono/System.Private.CoreLib/src/System/Delegate.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Delegate.Mono.cs index de3120dac128f2..898d1417e4f05f 100644 --- a/src/mono/System.Private.CoreLib/src/System/Delegate.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Delegate.Mono.cs @@ -559,6 +559,51 @@ internal static bool InternalEqualTypes(object source, object value) return source.GetType() == value.GetType(); } + internal static TDelegate CreateShared(nint ptr) where TDelegate : Delegate + { + RuntimeType rtType = (RuntimeType)typeof(TDelegate); + TDelegate del = Unsafe.As(CreateShared_internal(new QCallTypeHandle(ref rtType), ptr)) ?? throw new NotSupportedException(); + + MethodInfo methodBase = del.Method; + MethodInfo invokeMethod = GetInvokeMethod(rtType); + + ReadOnlySpan parameters = methodBase.GetParametersAsSpan(); + + int invokeCount = invokeMethod.GetParametersAsSpan().Length; + int paramCount = parameters.Length; + bool isStatic = methodBase.IsStatic; + if (!isStatic) + { + paramCount++; // count 'this' + } + + bool isOpen = invokeCount == paramCount; + + // reject cases needing valid instances + if (!isOpen) + { + // we block delegates closed over null valuetypes since we'd just always NRE in the unboxing stub + if (isStatic) + { + if (parameters.Length == 0 || parameters[0].ParameterType.IsValueType) + { + throw new NotSupportedException(); + } + } + else + { + Type? declaringType = methodBase.DeclaringType; + // reject instance methods on generic types, those require proper targets + if (declaringType is null || declaringType.IsValueType || declaringType.IsGenericType) + { + throw new NotSupportedException(); + } + } + } + + return del; + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] private protected static extern MulticastDelegate AllocDelegateLike_internal(Delegate d); @@ -567,5 +612,8 @@ internal static bool InternalEqualTypes(object source, object value) [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern MethodInfo GetVirtualMethod_internal(); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern Delegate? CreateShared_internal(QCallTypeHandle type, nint ptr); } } diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs index c689cc5f954ddd..0e1bde15823a27 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Runtime.InteropServices; using System.Runtime.Serialization; +using System.Threading; namespace System.Runtime.CompilerServices { @@ -132,6 +133,17 @@ public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[] } } + [MethodImpl(MethodImplOptions.NoInlining)] + private static TDelegate CreateSharedDelegate(nint method, ref TDelegate? storage) where TDelegate : Delegate + { + ArgumentNullException.ThrowIfNull(method); + + Debug.Assert(typeof(TDelegate).IsAssignableTo(typeof(Delegate))); + + TDelegate newDelegate = Delegate.CreateShared(method); + return Interlocked.CompareExchange(ref storage, newDelegate, null) ?? newDelegate; + } + public static void RunModuleConstructor(ModuleHandle module) { if (module == ModuleHandle.EmptyHandle) diff --git a/src/mono/mono/metadata/icall-def.h b/src/mono/mono/metadata/icall-def.h index 0158888234e080..48ab51feada557 100644 --- a/src/mono/mono/metadata/icall-def.h +++ b/src/mono/mono/metadata/icall-def.h @@ -145,6 +145,7 @@ ICALL_TYPE(DELEGATE, "System.Delegate", DELEGATE_1) HANDLES(DELEGATE_1, "AllocDelegateLike_internal", ves_icall_System_Delegate_AllocDelegateLike_internal, MonoMulticastDelegate, 1, (MonoDelegate)) HANDLES(DELEGATE_2, "CreateDelegate_internal", ves_icall_System_Delegate_CreateDelegate_internal, MonoObject, 4, (MonoQCallTypeHandle, MonoObject, MonoReflectionMethod, MonoBoolean)) HANDLES(DELEGATE_3, "GetVirtualMethod_internal", ves_icall_System_Delegate_GetVirtualMethod_internal, MonoReflectionMethod, 1, (MonoDelegate)) +HANDLES(DELEGATE_4, "CreateShared_internal", ves_icall_System_Delegate_CreateShared_internal, MonoObject, 2, (MonoQCallTypeHandle, gpointer)) ICALL_TYPE(DEBUGR, "System.Diagnostics.Debugger", DEBUGR_1) NOHANDLES(ICALL(DEBUGR_1, "IsAttached_internal", ves_icall_System_Diagnostics_Debugger_IsAttached_internal)) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 5c8a35a367ca9c..2c415a238b0a01 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -6124,6 +6124,23 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoQCallTypeHandle type_hand return delegate; } +MonoObjectHandle +ves_icall_System_Delegate_CreateShared_internal (MonoQCallTypeHandle type_handle, gpointer ptr, MonoError *error) +{ + MonoType *type = type_handle.type; + MonoClass *delegate_class = mono_class_from_mono_type_internal (type); + + mono_class_init_checked (delegate_class, error); + return_val_if_nok (error, NULL_HANDLE); + + MonoObjectHandle delegate = mono_object_new_handle (delegate_class, error); + return_val_if_nok (error, NULL_HANDLE); + + mono_delegate_ctor (delegate, NULL_HANDLE, ptr, NULL, error); + return_val_if_nok (error, NULL_HANDLE); + return delegate; +} + MonoMulticastDelegateHandle ves_icall_System_Delegate_AllocDelegateLike_internal (MonoDelegateHandle delegate, MonoError *error) { diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate.cs b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate.cs new file mode 100644 index 00000000000000..49848ecdd09619 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate.cs @@ -0,0 +1,503 @@ +// 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.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using Xunit; + +public static class Program +{ + private static int _errors; + + [Fact] + public static int TestEntryPoint() + { + TestNonGeneric(); + + TestGeneric(); + TestGeneric(); + TestGeneric(); + TestGeneric(); + TestGeneric(); + TestGeneric(); + + TestGeneric(); + TestGeneric(); + TestGeneric(); + TestGeneric(); + TestGeneric(); + TestGeneric(); + + AssertThrows(() => + { + Action? a = null; + RuntimeHelpers.GetDelegate(0, ref a); + }); + + // the JIT can optimize out accesses to the ref while expanding the intrinsic so disable optimizations here + [MethodImpl(MethodImplOptions.NoOptimization)] + static unsafe void NullTest() + { + RuntimeHelpers.GetDelegate((nint)(delegate*)&NullTest, ref Unsafe.NullRef()); + } + + AssertThrows(NullTest); + + return 100 + _errors; + } + + public static void TestNonGeneric() + { + AssertValid(NonGenericIl.GetInstanceBasicClosed, + del => del(), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceBasic), Constants.InstanceFlags)); + AssertValid(NonGenericIl.GetInstanceBasicOpen, + del => del(new NonGeneric()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceBasic), Constants.InstanceFlags)); + AssertValid(NonGenericIl.GetInstanceReturnClosed, + del => AssertEquals(Constants.TestInt, del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceReturn), Constants.InstanceFlags)); + AssertValid(NonGenericIl.GetInstanceReturnOpen, + del => AssertEquals(Constants.TestInt, del(new NonGeneric())), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceReturn), Constants.InstanceFlags)); + AssertValid(NonGenericIl.GetInstanceParamClosed, + del => AssertEquals(Constants.TestString, del(Constants.TestString)), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceParam), Constants.InstanceFlags)); + AssertValid(NonGenericIl.GetInstanceParamOpen, + del => AssertEquals(Constants.TestString, del(new NonGeneric(), Constants.TestString)), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceParam), Constants.InstanceFlags)); + + AssertValid(NonGenericIl.GetInstanceVirtualClosed, + del => AssertEquals(Constants.TestString, del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.Virtual), Constants.InstanceFlags)); + AssertValid(NonGenericIl.GetInstanceVirtualOpen, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.Virtual), Constants.InstanceFlags)); + + AssertValid(NonGeneric.GetStaticBasicClosed, + del => del(), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticBasic), Constants.StaticFlags)); + AssertValid(NonGeneric.GetStaticReturnClosed, + del => AssertEquals(Constants.TestInt, del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticReturn), Constants.StaticFlags)); + AssertValid(NonGeneric.GetStaticParamClosed, + del => AssertEquals(null, del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticParam), Constants.StaticFlags)); + AssertValid(NonGeneric.GetStaticParamOpen, + del => AssertEquals(Constants.TestString, del(Constants.TestString)), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticParam), Constants.StaticFlags)); + + AssertValid(StaticResolver.GetInterfaceStaticAbstract, + del => AssertEquals(Constants.TestString, del()), + typeof(NonGeneric).GetMethod(nameof(IStaticInterface.InterfaceStaticAbstract), Constants.StaticFlags)); + AssertValid(StaticResolver.GetInterfaceStaticVirtual, + del => AssertEquals(Constants.TestString, del()), + typeof(IStaticInterface).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtual), Constants.StaticFlags)); + AssertValid(StaticResolver.GetInterfaceStaticVirtualOverriden, + del => AssertEquals(Constants.TestString, del()), + typeof(NonGeneric).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtualOverriden), Constants.StaticFlags)); + + AssertValid(VirtualCache.GetInterfaceInstance, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstance), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDim, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDim), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDimOverriden, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDimOverriden), Constants.InstanceFlags)); + + AssertValid(VirtualCache.GetBaseAbstract, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(BaseClass).GetMethod(nameof(BaseClass.BaseAbstract), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetBaseVirtual, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(BaseClass).GetMethod(nameof(BaseClass.BaseVirtual), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetBaseVirtualOverriden, + del => AssertEquals(Constants.TestString, del(new NonGeneric())), + typeof(BaseClass).GetMethod(nameof(BaseClass.BaseVirtualOverriden), Constants.InstanceFlags)); + + AssertValid(NonGenericStructIl.GetInstanceBasicOpen, + del => del(new NonGenericStruct()), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.InstanceBasic), Constants.InstanceFlags)); + AssertValid(NonGenericStructIl.GetInstanceReturnOpen, + del => AssertEquals(Constants.TestInt, del(new NonGenericStruct())), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.InstanceReturn), Constants.InstanceFlags)); + AssertValid(NonGenericStructIl.GetInstanceParamOpen, + del => AssertEquals(Constants.TestString, del(new NonGenericStruct(), Constants.TestString)), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.InstanceParam), Constants.InstanceFlags)); + + AssertValid(NonGenericStruct.GetStaticBasicClosed, + del => del(), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticBasic), Constants.StaticFlags)); + AssertValid(NonGenericStruct.GetStaticReturnClosed, + del => AssertEquals(Constants.TestInt, del()), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticReturn), Constants.StaticFlags)); + AssertValid(NonGenericStruct.GetStaticParamClosed, + del => AssertEquals(null, del()), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticParam), Constants.StaticFlags)); + AssertValid(NonGenericStruct.GetStaticParamOpen, + del => AssertEquals(Constants.TestString, del(Constants.TestString)), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticParam), Constants.StaticFlags)); + + AssertValid(StaticResolver.GetInterfaceStaticAbstract, + del => AssertEquals(Constants.TestString, del()), + typeof(NonGenericStruct).GetMethod(nameof(IStaticInterface.InterfaceStaticAbstract), Constants.StaticFlags)); + AssertValid(StaticResolver.GetInterfaceStaticVirtual, + del => AssertEquals(Constants.TestString, del()), + typeof(IStaticInterface).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtual), Constants.StaticFlags)); + AssertValid(StaticResolver.GetInterfaceStaticVirtualOverriden, + del => AssertEquals(Constants.TestString, del()), + typeof(NonGenericStruct).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtualOverriden), Constants.StaticFlags)); + + AssertValid(VirtualCache.GetInterfaceInstance, + del => AssertEquals(Constants.TestString, del(new NonGenericStruct())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstance), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDim, + del => AssertEquals(Constants.TestString, del(new NonGenericStruct())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDim), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDimOverriden, + del => AssertEquals(Constants.TestString, del(new NonGenericStruct())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDimOverriden), Constants.InstanceFlags)); + + AssertThrows(() => NonGenericStructIl.GetInstanceBasicClosed()); + AssertThrows(() => NonGenericStructIl.GetInstanceBasicClosed()); + AssertThrows(() => NonGenericStructIl.GetInstanceReturnClosed()); + AssertThrows(() => NonGenericStructIl.GetInstanceParamClosed()); + } + + public static void TestGeneric() + { + TestNonGenericClass(); + + TestGenericClass(); + + TestNonGenericStruct(); + + TestGenericStruct(); + } + + public static void TestNonGenericClass() + { + AssertValid(NonGenericIl.GetInstanceGenericClosed, + del => AssertEquals(typeof(T), del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceGeneric), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + AssertValid(NonGenericIl.GetInstanceGenericOpen, + del => AssertEquals(typeof(T), del(new NonGeneric())), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceGeneric), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + AssertValid(NonGenericIl.GetInstanceGenericParamClosed, + del => AssertEquals(typeof(T), del(default)), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceGenericParam), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + AssertValid(NonGenericIl.GetInstanceGenericParamOpen, + del => AssertEquals(typeof(T), del(new NonGeneric(), default)), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.InstanceGenericParam), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + + AssertValid(NonGeneric.GetStaticGenericClosed, + del => AssertEquals(typeof(T), del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticGeneric), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + AssertValid(NonGeneric.GetStaticGenericParamOpen, + del => AssertEquals(typeof(T), del(default)), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticGenericParam), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + + if (typeof(T).IsValueType) + { + AssertThrows(() => NonGeneric.GetStaticGenericParamClosed()); + } + else + { + AssertValid(NonGeneric.GetStaticGenericParamClosed, + del => AssertEquals(typeof(T), del()), + typeof(NonGeneric).GetMethod(nameof(NonGeneric.StaticGenericParam), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + } + } + + public static void TestGenericClass() + { + AssertValid(GenericIl.GetInstanceBasicOpen, + del => del(new Generic()), + typeof(Generic).GetMethod(nameof(Generic<>.InstanceBasic), Constants.InstanceFlags)); + AssertValid(GenericIl.GetInstanceReturnOpen, + del => AssertEquals(Constants.TestInt, del(new Generic())), + typeof(Generic).GetMethod(nameof(Generic<>.InstanceReturn), Constants.InstanceFlags)); + AssertValid(GenericIl.GetInstanceParamOpen, + del => AssertEquals(Constants.TestString, del(new Generic(), Constants.TestString)), + typeof(Generic).GetMethod(nameof(Generic<>.InstanceParam), Constants.InstanceFlags)); + AssertValid(GenericIl.GetInstanceGenericOpen, + del => AssertEquals(typeof(T), del(new Generic())), + typeof(Generic).GetMethod(nameof(Generic<>.InstanceGeneric), Constants.InstanceFlags)); + AssertValid(GenericIl.GetInstanceGenericParamOpen, + del => AssertEquals(typeof(T), del(new Generic(), default)), + typeof(Generic).GetMethod(nameof(Generic<>.InstanceGenericParam), Constants.InstanceFlags)); + AssertValid(GenericIl.GetInstanceDoubleGenericOpen, + del => AssertEquals((typeof(T), typeof(T)), del(new Generic())), + typeof(Generic).GetMethod(nameof(Generic<>.InstanceDoubleGeneric), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + + AssertValid(GenericIl.GetInstanceVirtualOpen, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(Generic).GetMethod(nameof(Generic<>.Virtual), Constants.InstanceFlags)); + + AssertValid(Generic.GetStaticBasicClosed, + del => del(), + typeof(Generic).GetMethod(nameof(Generic<>.StaticBasic), Constants.StaticFlags)); + AssertValid(Generic.GetStaticReturnClosed, + del => AssertEquals(Constants.TestInt, del()), + typeof(Generic).GetMethod(nameof(Generic<>.StaticReturn), Constants.StaticFlags)); + AssertValid(Generic.GetStaticParamClosed, + del => AssertEquals(null, del()), + typeof(Generic).GetMethod(nameof(Generic<>.StaticParam), Constants.StaticFlags)); + AssertValid(Generic.GetStaticParamOpen, + del => AssertEquals(Constants.TestString, del(Constants.TestString)), + typeof(Generic).GetMethod(nameof(Generic<>.StaticParam), Constants.StaticFlags)); + AssertValid(Generic.GetStaticGenericClosed, + del => AssertEquals(typeof(T), del()), + typeof(Generic).GetMethod(nameof(Generic<>.StaticGeneric), Constants.StaticFlags)); + AssertValid(Generic.GetStaticGenericParamOpen, + del => AssertEquals(typeof(T), del(default)), + typeof(Generic).GetMethod(nameof(Generic<>.StaticGenericParam), Constants.StaticFlags)); + AssertValid(Generic.GetStaticDoubleGenericOpen, + del => AssertEquals((typeof(T), typeof(T)), del()), + typeof(Generic).GetMethod(nameof(Generic<>.StaticDoubleGeneric), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + + AssertValid(StaticResolver>.GetInterfaceStaticAbstract, + del => AssertEquals(Constants.TestString, del()), + typeof(Generic).GetMethod(nameof(IStaticInterface.InterfaceStaticAbstract), Constants.StaticFlags)); + AssertValid(StaticResolver>.GetInterfaceStaticVirtual, + del => AssertEquals(Constants.TestString, del()), + typeof(IStaticInterface).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtual), Constants.StaticFlags)); + AssertValid(StaticResolver>.GetInterfaceStaticVirtualOverriden, + del => AssertEquals(Constants.TestString, del()), + typeof(Generic).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtualOverriden), Constants.StaticFlags)); + + AssertValid(VirtualCache.GetInterfaceInstance, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstance), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDim, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDim), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDimOverriden, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDimOverriden), Constants.InstanceFlags)); + + AssertValid(VirtualCache.GetBaseAbstract, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(BaseClass).GetMethod(nameof(BaseClass.BaseAbstract), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetBaseVirtual, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(BaseClass).GetMethod(nameof(BaseClass.BaseVirtual), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetBaseVirtualOverriden, + del => AssertEquals(Constants.TestString, del(new Generic())), + typeof(BaseClass).GetMethod(nameof(BaseClass.BaseVirtualOverriden), Constants.InstanceFlags)); + + if (typeof(T).IsValueType) + { + AssertThrows(() => Generic.GetStaticGenericParamClosed()); + } + else + { + AssertValid(Generic.GetStaticGenericParamClosed, + del => AssertEquals(typeof(T), del()), + typeof(Generic).GetMethod(nameof(Generic<>.StaticGenericParam), Constants.StaticFlags)); + } + + AssertThrows(() => GenericIl.GetInstanceBasicClosed()); + AssertThrows(() => GenericIl.GetInstanceReturnClosed()); + AssertThrows(() => GenericIl.GetInstanceParamClosed()); + AssertThrows(() => GenericIl.GetInstanceGenericClosed()); + AssertThrows(() => GenericIl.GetInstanceGenericParamClosed()); + AssertThrows(() => GenericIl.GetInstanceDoubleGenericClosed()); + AssertThrows(() => GenericIl.GetInstanceVirtualClosed()); + } + + public static void TestNonGenericStruct() + { + AssertValid(NonGenericStructIl.GetInstanceGenericOpen, + del => AssertEquals(typeof(T), del(new NonGenericStruct())), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.InstanceGeneric), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + AssertValid(NonGenericStructIl.GetInstanceGenericParamOpen, + del => AssertEquals(typeof(T), del(new NonGenericStruct(), default)), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.InstanceGenericParam), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + + AssertValid(NonGenericStruct.GetStaticGenericClosed, + del => AssertEquals(typeof(T), del()), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticGeneric), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + AssertValid(NonGenericStruct.GetStaticGenericParamOpen, + del => AssertEquals(typeof(T), del(default)), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticGenericParam), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + + if (typeof(T).IsValueType) + { + AssertThrows(() => NonGenericStruct.GetStaticGenericParamClosed()); + } + else + { + AssertValid(NonGenericStruct.GetStaticGenericParamClosed, + del => AssertEquals(typeof(T), del()), + typeof(NonGenericStruct).GetMethod(nameof(NonGenericStruct.StaticGenericParam), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + } + + AssertThrows(() => NonGenericStructIl.GetInstanceGenericClosed()); + AssertThrows(() => NonGenericStructIl.GetInstanceGenericParamClosed()); + } + + public static void TestGenericStruct() + { + AssertValid(GenericStructIl.GetInstanceBasicOpen, + del => del(new GenericStruct()), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.InstanceBasic), Constants.InstanceFlags)); + AssertValid(GenericStructIl.GetInstanceReturnOpen, + del => AssertEquals(Constants.TestInt, del(new GenericStruct())), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.InstanceReturn), Constants.InstanceFlags)); + AssertValid(GenericStructIl.GetInstanceParamOpen, + del => AssertEquals(Constants.TestString, del(new GenericStruct(), Constants.TestString)), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.InstanceParam), Constants.InstanceFlags)); + AssertValid(GenericStructIl.GetInstanceGenericOpen, + del => AssertEquals(typeof(T), del(new GenericStruct())), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.InstanceGeneric), Constants.InstanceFlags)); + AssertValid(GenericStructIl.GetInstanceGenericParamOpen, + del => AssertEquals(typeof(T), del(new GenericStruct(), default)), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.InstanceGenericParam), Constants.InstanceFlags)); + AssertValid(GenericStructIl.GetInstanceDoubleGenericOpen, + del => AssertEquals((typeof(T), typeof(T)), del(new GenericStruct())), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.InstanceDoubleGeneric), Constants.InstanceFlags)?.MakeGenericMethod(typeof(T))); + + AssertValid(GenericStruct.GetStaticBasicClosed, + del => del(), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticBasic), Constants.StaticFlags)); + AssertValid(GenericStruct.GetStaticReturnClosed, + del => AssertEquals(Constants.TestInt, del()), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticReturn), Constants.StaticFlags)); + AssertValid(GenericStruct.GetStaticParamClosed, + del => AssertEquals(null, del()), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticParam), Constants.StaticFlags)); + AssertValid(GenericStruct.GetStaticParamOpen, + del => AssertEquals(Constants.TestString, del(Constants.TestString)), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticParam), Constants.StaticFlags)); + AssertValid(GenericStruct.GetStaticGenericClosed, + del => AssertEquals(typeof(T), del()), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticGeneric), Constants.StaticFlags)); + AssertValid(GenericStruct.GetStaticGenericParamOpen, + del => AssertEquals(typeof(T), del(default)), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticGenericParam), Constants.StaticFlags)); + AssertValid(GenericStruct.GetStaticDoubleGenericOpen, + del => AssertEquals((typeof(T), typeof(T)), del()), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticDoubleGeneric), Constants.StaticFlags)?.MakeGenericMethod(typeof(T))); + + AssertValid(StaticResolver>.GetInterfaceStaticAbstract, + del => AssertEquals(Constants.TestString, del()), + typeof(GenericStruct).GetMethod(nameof(IStaticInterface.InterfaceStaticAbstract), Constants.StaticFlags)); + AssertValid(StaticResolver>.GetInterfaceStaticVirtual, + del => AssertEquals(Constants.TestString, del()), + typeof(IStaticInterface).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtual), Constants.StaticFlags)); + AssertValid(StaticResolver>.GetInterfaceStaticVirtualOverriden, + del => AssertEquals(Constants.TestString, del()), + typeof(GenericStruct).GetMethod(nameof(IStaticInterface.InterfaceStaticVirtualOverriden), Constants.StaticFlags)); + + AssertValid(VirtualCache.GetInterfaceInstance, + del => AssertEquals(Constants.TestString, del(new GenericStruct())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstance), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDim, + del => AssertEquals(Constants.TestString, del(new GenericStruct())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDim), Constants.InstanceFlags)); + AssertValid(VirtualResolver.GetInterfaceInstanceDimOverriden, + del => AssertEquals(Constants.TestString, del(new GenericStruct())), + typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstanceDimOverriden), Constants.InstanceFlags)); + + if (typeof(T).IsValueType) + { + AssertThrows(() => GenericStruct.GetStaticGenericParamClosed()); + } + else + { + AssertValid(GenericStruct.GetStaticGenericParamClosed, + del => AssertEquals(typeof(T), del()), + typeof(GenericStruct).GetMethod(nameof(GenericStruct<>.StaticGenericParam), Constants.StaticFlags)); + } + + AssertThrows(() => GenericStructIl.GetInstanceBasicClosed()); + AssertThrows(() => GenericStructIl.GetInstanceReturnClosed()); + AssertThrows(() => GenericStructIl.GetInstanceParamClosed()); + AssertThrows(() => GenericStructIl.GetInstanceGenericClosed()); + AssertThrows(() => GenericStructIl.GetInstanceGenericParamClosed()); + AssertThrows(() => GenericStructIl.GetInstanceDoubleGenericClosed()); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void AssertValid(Func f, Action a, MethodInfo? info, bool recursed = false, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") where TDelegate : Delegate + { + try + { + TDelegate del = f(); + + AssertEquals(false, del is null, line: line, file: file); + AssertEquals(false, del!.Method is null, line: line, file: file); + AssertEquals(false, del.Method!.DeclaringType is null, line: line, file: file); + + AssertEquals(typeof(TDelegate), GetType(del), line: line, file: file); + + AssertEquals(false, del.Method.IsGenericMethodDefinition, line: line, file: file); + AssertEquals(false, del.Method.DeclaringType!.IsGenericTypeDefinition, line: line, file: file); + + AssertEquals(true, del.Target is null, line: line, file: file); + + a(del); + + AssertEquals(false, info is null, line: line, file: file); + + if (info is null) + return; + + AssertEquals(info, del.Method, line: line, file: file); + AssertEquals(info.DeclaringType, del.Method.DeclaringType, line: line, file: file); + + if (!recursed) + { + // verify fallback path works + // this is fine on AOT due to normal creation guaranteeing the method and stubs are present + AssertValid(() => + { + TDelegate? unused = null; + return RuntimeHelpers.GetDelegate(info!.MethodHandle.GetFunctionPointer(), ref unused); + }, a, info, true); + } + } + catch (Exception exception) + { + Console.WriteLine($"{file}:L{line} exception: {exception}"); + _errors++; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void AssertEquals(T left, T right, [CallerArgumentExpression("left")] string a = "", [CallerArgumentExpression("right")] string b = "", [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") + { + if (EqualityComparer.Default.Equals(left, right)) + return; + Console.WriteLine($"{file}:L{line} test failed ({a}: {left}, {b}: {right})."); + _errors++; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void AssertThrows(Action action, [CallerLineNumber] int line = 0, [CallerFilePath] string file = "") where T : Exception + { + try + { + action(); + Console.WriteLine($"{file}:L{line} test failed (expected {typeof(T).Name})."); + _errors++; + } + catch (T) + { + // ignore + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Type? GetType(object? o) + { + return o?.GetType(); + } +} diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateCases.cs b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateCases.cs new file mode 100644 index 00000000000000..aa6d12426af686 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateCases.cs @@ -0,0 +1,347 @@ +// 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.Reflection; +using System.Runtime.CompilerServices; + +#pragma warning disable CA2211 + +public unsafe class NonGeneric : BaseClass, IStaticInterface, IInterface +{ + public static Action? InstanceBasicClosed; + public static Action? InstanceBasicOpen; + public static Func? InstanceReturnClosed; + public static Func? InstanceReturnOpen; + public static Func? InstanceParamClosed; + public static Func? InstanceParamOpen; + + public static Func? VirtualClosed; + public static Func? VirtualOpen; + + public static Action? StaticBasicClosed; + public static Func? StaticReturnClosed; + public static Func? StaticParamClosed; + public static Func? StaticParamOpen; + + public static class Cache + { + public static Func? InstanceGenericClosed; + public static Func? InstanceGenericOpen; + public static Func? InstanceGenericParamClosed; + public static Func? InstanceGenericParamOpen; + + public static Func? StaticGenericClosed; + public static Func? StaticGenericParamClosed; + public static Func? StaticGenericParamOpen; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Action GetStaticBasicClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticBasic, ref StaticBasicClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticReturnClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticReturn, ref StaticReturnClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamOpen); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGeneric, ref Cache.StaticGenericClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref Cache.StaticGenericParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref Cache.StaticGenericParamOpen); + + public void InstanceBasic() { } + public int InstanceReturn() => Constants.TestInt; + public object InstanceParam(object obj) => obj; + public Type InstanceGeneric() => typeof(T); + public Type InstanceGenericParam(T val) => typeof(T); + + public virtual object Virtual() => Constants.TestString; + + public static void StaticBasic() { } + public static int StaticReturn() => Constants.TestInt; + public static object StaticParam(object obj) => obj; + public static Type StaticGeneric() => typeof(T); + public static Type StaticGenericParam(T val) => typeof(T); + + public object InterfaceInstance() => Constants.TestString; + public object InterfaceInstanceDimOverriden() => Constants.TestString; + + public static object InterfaceStaticAbstract() => Constants.TestString; + public static object InterfaceStaticVirtualOverriden() => Constants.TestString; + + public override object BaseAbstract() => Constants.TestString; + public override object BaseVirtualOverriden() => Constants.TestString; +} + +public unsafe class Generic : BaseClass, IStaticInterface, IInterface +{ + public static Action? InstanceBasicClosed; + public static Action>? InstanceBasicOpen; + public static Func? InstanceReturnClosed; + public static Func, int>? InstanceReturnOpen; + public static Func? InstanceParamClosed; + public static Func, object, object>? InstanceParamOpen; + + public static Func? VirtualClosed; + public static Func, object>? VirtualOpen; + + public static Action? StaticBasicClosed; + public static Func? StaticReturnClosed; + public static Func? StaticParamClosed; + public static Func? StaticParamOpen; + + public static Func? InstanceGenericClosed; + public static Func, Type>? InstanceGenericOpen; + public static Func? InstanceGenericParamClosed; + public static Func, T, Type>? InstanceGenericParamOpen; + + public static Func? StaticGenericClosed; + public static Func? StaticGenericParamClosed; + public static Func? StaticGenericParamOpen; + + public static class Cache + { + public static Func<(Type, Type)>? InstanceDoubleGenericClosed; + public static Func, (Type, Type)>? InstanceDoubleGenericOpen; + + public static Func<(Type, Type)>? StaticDoubleGenericClosed; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Action GetStaticBasicClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticBasic, ref StaticBasicClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticReturnClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticReturn, ref StaticReturnClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamOpen); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGeneric, ref StaticGenericClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref StaticGenericParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref StaticGenericParamOpen); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func<(Type, Type)> GetStaticDoubleGenericOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*<(Type, Type)>)&StaticDoubleGeneric, ref Cache.StaticDoubleGenericClosed); + + public void InstanceBasic() { } + public int InstanceReturn() => Constants.TestInt; + public object InstanceParam(object obj) => obj; + public Type InstanceGeneric() => typeof(T); + public Type InstanceGenericParam(T val) => typeof(T); + public (Type, Type) InstanceDoubleGeneric() => (typeof(T), typeof(T2)); + + public virtual object Virtual() => Constants.TestString; + + public static void StaticBasic() { } + public static int StaticReturn() => Constants.TestInt; + public static object StaticParam(object obj) => obj; + public static Type StaticGeneric() => typeof(T); + public static Type StaticGenericParam(T val) => typeof(T); + public static (Type, Type) StaticDoubleGeneric() => (typeof(T), typeof(T2)); + + public object InterfaceInstance() => Constants.TestString; + public object InterfaceInstanceDimOverriden() => Constants.TestString; + + public static object InterfaceStaticAbstract() => Constants.TestString; + public static object InterfaceStaticVirtualOverriden() => Constants.TestString; + + public override object BaseAbstract() => Constants.TestString; + public override object BaseVirtualOverriden() => Constants.TestString; +} + +public unsafe struct NonGenericStruct : IStaticInterface, IInterface +{ + public static Action? InstanceBasicClosed; + public static Action? InstanceBasicOpen; + public static Func? InstanceReturnClosed; + public static Func? InstanceReturnOpen; + public static Func? InstanceParamClosed; + public static Func? InstanceParamOpen; + + public static Action? StaticBasicClosed; + public static Func? StaticReturnClosed; + public static Func? StaticParamClosed; + public static Func? StaticParamOpen; + + public static class Cache + { + public static Func? InstanceGenericClosed; + public static Func? InstanceGenericOpen; + public static Func? InstanceGenericParamClosed; + public static Func? InstanceGenericParamOpen; + + public static Func? StaticGenericClosed; + public static Func? StaticGenericParamClosed; + public static Func? StaticGenericParamOpen; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Action GetStaticBasicClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticBasic, ref StaticBasicClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticReturnClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticReturn, ref StaticReturnClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamOpen); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGeneric, ref Cache.StaticGenericClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref Cache.StaticGenericParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref Cache.StaticGenericParamOpen); + + public void InstanceBasic() { } + public int InstanceReturn() => Constants.TestInt; + public object InstanceParam(object obj) => obj; + public Type InstanceGeneric() => typeof(T); + public Type InstanceGenericParam(T val) => typeof(T); + + public static void StaticBasic() { } + public static int StaticReturn() => Constants.TestInt; + public static object StaticParam(object obj) => obj; + public static Type StaticGeneric() => typeof(T); + public static Type StaticGenericParam(T val) => typeof(T); + + public object InterfaceInstance() => Constants.TestString; + public object InterfaceInstanceDimOverriden() => Constants.TestString; + + public static object InterfaceStaticAbstract() => Constants.TestString; + public static object InterfaceStaticVirtualOverriden() => Constants.TestString; +} + +public unsafe struct GenericStruct : IStaticInterface, IInterface +{ + public static Action? InstanceBasicClosed; + public static Action>? InstanceBasicOpen; + public static Func? InstanceReturnClosed; + public static Func, int>? InstanceReturnOpen; + public static Func? InstanceParamClosed; + public static Func, object, object>? InstanceParamOpen; + + public static Action? StaticBasicClosed; + public static Func? StaticReturnClosed; + public static Func? StaticParamClosed; + public static Func? StaticParamOpen; + + public static Func? InstanceGenericClosed; + public static Func, Type>? InstanceGenericOpen; + public static Func? InstanceGenericParamClosed; + public static Func, T, Type>? InstanceGenericParamOpen; + + public static Func? StaticGenericClosed; + public static Func? StaticGenericParamClosed; + public static Func? StaticGenericParamOpen; + + public static class Cache + { + public static Func<(Type, Type)>? InstanceDoubleGenericClosed; + public static Func, (Type, Type)>? InstanceDoubleGenericOpen; + + public static Func<(Type, Type)>? StaticDoubleGenericClosed; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Action GetStaticBasicClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticBasic, ref StaticBasicClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticReturnClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticReturn, ref StaticReturnClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticParam, ref StaticParamOpen); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGeneric, ref StaticGenericClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamClosed() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref StaticGenericParamClosed); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetStaticGenericParamOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*)&StaticGenericParam, ref StaticGenericParamOpen); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func<(Type, Type)> GetStaticDoubleGenericOpen() => RuntimeHelpers.GetDelegate((nint)(delegate*<(Type, Type)>)&StaticDoubleGeneric, ref Cache.StaticDoubleGenericClosed); + + public void InstanceBasic() { } + public int InstanceReturn() => Constants.TestInt; + public object InstanceParam(object obj) => obj; + public Type InstanceGeneric() => typeof(T); + public Type InstanceGenericParam(T val) => typeof(T); + public (Type, Type) InstanceDoubleGeneric() => (typeof(T), typeof(T2)); + + public static void StaticBasic() { } + public static int StaticReturn() => Constants.TestInt; + public static object StaticParam(object obj) => obj; + public static Type StaticGeneric() => typeof(T); + public static Type StaticGenericParam(T val) => typeof(T); + public static (Type, Type) StaticDoubleGeneric() => (typeof(T), typeof(T2)); + + public object InterfaceInstance() => Constants.TestString; + public object InterfaceInstanceDimOverriden() => Constants.TestString; + + public static object InterfaceStaticAbstract() => Constants.TestString; + public static object InterfaceStaticVirtualOverriden() => Constants.TestString; +} + +public static unsafe class StaticResolver where T : IStaticInterface +{ + public static Func? InterfaceStaticAbstract; + public static Func? InterfaceStaticVirtual; + public static Func? InterfaceStaticVirtualOverriden; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetInterfaceStaticAbstract() => RuntimeHelpers.GetDelegate((nint)(delegate*)&T.InterfaceStaticAbstract, ref InterfaceStaticAbstract); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetInterfaceStaticVirtual() => RuntimeHelpers.GetDelegate((nint)(delegate*)&T.InterfaceStaticVirtual, ref InterfaceStaticVirtual); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetInterfaceStaticVirtualOverriden() => RuntimeHelpers.GetDelegate((nint)(delegate*)&T.InterfaceStaticVirtualOverriden, ref InterfaceStaticVirtualOverriden); +} + +public interface IStaticInterface +{ + public static abstract object InterfaceStaticAbstract(); + public static virtual object InterfaceStaticVirtual() => Constants.TestString; + public static virtual object InterfaceStaticVirtualOverriden() => null!; +} + +public interface IInterface +{ + public object InterfaceInstance(); + public object InterfaceInstanceDim() => Constants.TestString; + public object InterfaceInstanceDimOverriden() => null!; +} + +public abstract class BaseClass +{ + public abstract object BaseAbstract(); + public virtual object BaseVirtual() => Constants.TestString; + public virtual object BaseVirtualOverriden() => null!; +} + +public static class VirtualCache +{ + public static Func? InterfaceInstance; + public static Func? InterfaceInstanceDim; + public static Func? InterfaceInstanceDimOverriden; + + public static Func? BaseAbstract; + public static Func? BaseVirtual; + public static Func? BaseVirtualOverriden; + + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetBaseAbstract() => RuntimeHelpers.GetDelegate(typeof(BaseClass).GetMethod(nameof(BaseClass.BaseAbstract), + Constants.InstanceFlags)!.MethodHandle.GetFunctionPointer(), ref BaseAbstract); + [MethodImpl(MethodImplOptions.NoInlining)] + public static Func GetInterfaceInstance() => RuntimeHelpers.GetDelegate(typeof(IInterface).GetMethod(nameof(IInterface.InterfaceInstance), + Constants.InstanceFlags)!.MethodHandle.GetFunctionPointer(), ref InterfaceInstance); +} + +public static class Constants +{ + public const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public; + public const BindingFlags StaticFlags = BindingFlags.Static | BindingFlags.Public; + public const int TestInt = 5; + public const string TestString = "test"; +} diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateCases.csproj b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateCases.csproj new file mode 100644 index 00000000000000..5edaa3c7826b83 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateCases.csproj @@ -0,0 +1,8 @@ + + + Library + + + + + diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateIL.il b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateIL.il new file mode 100644 index 00000000000000..eddc28893cc728 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateIL.il @@ -0,0 +1,608 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) } +.assembly extern RuntimeHelpersGetDelegateCases { } + +.assembly RuntimeHelpersGetDelegateIL { } + +.class public abstract auto ansi sealed beforefieldinit NonGenericIl + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) + .method public hidebysig static class [System.Runtime]System.Action + GetInstanceBasicClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance void [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceBasic() + ldsflda class [System.Runtime]System.Action [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceBasicClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceBasicClosed + + .method public hidebysig static class [System.Runtime]System.Action`1 + GetInstanceBasicOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance void [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceBasic() + ldsflda class [System.Runtime]System.Action`1 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceBasicOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceBasicOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceReturnClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceReturn() + ldsflda class [System.Runtime]System.Func`1 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceReturnClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceReturnClosed + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceReturnOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceReturn() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceReturnOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceReturnOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceParamClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3 + GetInstanceParamOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`3 [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceParamOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceVirtualClosed() cil managed noinlining + { + .maxstack 2 + newobj instance void [RuntimeHelpersGetDelegateCases]NonGeneric::.ctor() + ldvirtftn instance object [RuntimeHelpersGetDelegateCases]NonGeneric::Virtual() + ldsflda class [System.Runtime]System.Func`1 [RuntimeHelpersGetDelegateCases]NonGeneric::VirtualClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceVirtualClosed + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceVirtualOpen() cil managed noinlining + { + .maxstack 2 + newobj instance void [RuntimeHelpersGetDelegateCases]NonGeneric::.ctor() + ldvirtftn instance object [RuntimeHelpersGetDelegateCases]NonGeneric::Virtual() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]NonGeneric::VirtualOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceVirtualOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceGenericClosed() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`1 class [RuntimeHelpersGetDelegateCases]NonGeneric/Cache`1::InstanceGenericClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceGenericClosed + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceGenericOpen() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`2 class [RuntimeHelpersGetDelegateCases]NonGeneric/Cache`1::InstanceGenericOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceGenericOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceGenericParamClosed() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceGenericParam(!!0) + ldsflda class [System.Runtime]System.Func`2 class [RuntimeHelpersGetDelegateCases]NonGeneric/Cache`1::InstanceGenericParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceGenericParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3 + GetInstanceGenericParamOpen() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGeneric::InstanceGenericParam(!!0) + ldsflda class [System.Runtime]System.Func`3 class [RuntimeHelpersGetDelegateCases]NonGeneric/Cache`1::InstanceGenericParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericIl::GetInstanceGenericParamOpen + +} // end of class NonGenericIl + +.class public abstract auto ansi sealed beforefieldinit GenericIl`1 + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .method public hidebysig static class [System.Runtime]System.Action + GetInstanceBasicClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance void class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceBasic() + ldsflda class [System.Runtime]System.Action class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceBasicClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceBasicClosed + + .method public hidebysig static class [System.Runtime]System.Action`1> + GetInstanceBasicOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance void class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceBasic() + ldsflda class [System.Runtime]System.Action`1> class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceBasicOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceBasicOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceReturnClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceReturn() + ldsflda class [System.Runtime]System.Func`1 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceReturnClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceReturnClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,int32> + GetInstanceReturnOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceReturn() + ldsflda class [System.Runtime]System.Func`2,int32> class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceReturnOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,int32>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceReturnOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceParamClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance object class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`2 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3,object,object> + GetInstanceParamOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance object class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`3,object,object> class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,object,object>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceParamOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceVirtualClosed() cil managed noinlining + { + .maxstack 2 + newobj instance void class [RuntimeHelpersGetDelegateCases]Generic`1::.ctor() + ldvirtftn instance object class [RuntimeHelpersGetDelegateCases]Generic`1::Virtual() + ldsflda class [System.Runtime]System.Func`1 class [RuntimeHelpersGetDelegateCases]Generic`1::VirtualClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceVirtualClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,object> + GetInstanceVirtualOpen() cil managed noinlining + { + .maxstack 2 + newobj instance void class [RuntimeHelpersGetDelegateCases]Generic`1::.ctor() + ldvirtftn instance object class [RuntimeHelpersGetDelegateCases]Generic`1::Virtual() + ldsflda class [System.Runtime]System.Func`2,object> class [RuntimeHelpersGetDelegateCases]Generic`1::VirtualOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,object>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceVirtualOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceGenericClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance class [System.Runtime]System.Type class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`1 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGenericClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceGenericClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,class [System.Runtime]System.Type> + GetInstanceGenericOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance class [System.Runtime]System.Type class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`2,class [System.Runtime]System.Type> class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGenericOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,class [System.Runtime]System.Type>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceGenericOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceGenericParamClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance class [System.Runtime]System.Type class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGenericParam(!0) + ldsflda class [System.Runtime]System.Func`2 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGenericParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceGenericParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3,!T,class [System.Runtime]System.Type> + GetInstanceGenericParamOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance class [System.Runtime]System.Type class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGenericParam(!0) + ldsflda class [System.Runtime]System.Func`3,!0,class [System.Runtime]System.Type> class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceGenericParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,!T,class [System.Runtime]System.Type>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceGenericParamOpen + + .method public hidebysig static class [System.Runtime]System.Func`1> + GetInstanceDoubleGenericClosed() cil managed noinlining + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 04 00 00 00 01 00 01 01 00 00 ) + .maxstack 2 + ldftn instance valuetype [System.Runtime]System.ValueTuple`2 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceDoubleGeneric() + ldsflda class [System.Runtime]System.Func`1> class [RuntimeHelpersGetDelegateCases]Generic`1/Cache`1::InstanceDoubleGenericClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceDoubleGenericClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,valuetype [System.Runtime]System.ValueTuple`2> + GetInstanceDoubleGenericOpen() cil managed noinlining + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 06 00 00 00 01 01 01 00 01 01 00 00 ) + .maxstack 2 + ldftn instance valuetype [System.Runtime]System.ValueTuple`2 class [RuntimeHelpersGetDelegateCases]Generic`1::InstanceDoubleGeneric() + ldsflda class [System.Runtime]System.Func`2,valuetype [System.Runtime]System.ValueTuple`2> class [RuntimeHelpersGetDelegateCases]Generic`1/Cache`1::InstanceDoubleGenericOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,valuetype [System.Runtime]System.ValueTuple`2>>(native int, !!0&) + ret + } // end of method GenericIl`1::GetInstanceDoubleGenericOpen + +} // end of class GenericIl`1 + +.class public abstract auto ansi sealed beforefieldinit NonGenericStructIl + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) + .method public hidebysig static class [System.Runtime]System.Action + GetInstanceBasicClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance void [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceBasic() + ldsflda class [System.Runtime]System.Action [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceBasicClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceBasicClosed + + .method public hidebysig static class [System.Runtime]System.Action`1 + GetInstanceBasicOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance void [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceBasic() + ldsflda class [System.Runtime]System.Action`1 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceBasicOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceBasicOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceReturnClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceReturn() + ldsflda class [System.Runtime]System.Func`1 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceReturnClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceReturnClosed + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceReturnOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceReturn() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceReturnOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceReturnOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceParamClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3 + GetInstanceParamOpen() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`3 [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceParamOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceGenericClosed() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`1 class [RuntimeHelpersGetDelegateCases]NonGenericStruct/Cache`1::InstanceGenericClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceGenericClosed + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceGenericOpen() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`2 class [RuntimeHelpersGetDelegateCases]NonGenericStruct/Cache`1::InstanceGenericOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceGenericOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceGenericParamClosed() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceGenericParam(!!0) + ldsflda class [System.Runtime]System.Func`2 class [RuntimeHelpersGetDelegateCases]NonGenericStruct/Cache`1::InstanceGenericParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceGenericParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3 + GetInstanceGenericParamOpen() cil managed noinlining + { + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type [RuntimeHelpersGetDelegateCases]NonGenericStruct::InstanceGenericParam(!!0) + ldsflda class [System.Runtime]System.Func`3 class [RuntimeHelpersGetDelegateCases]NonGenericStruct/Cache`1::InstanceGenericParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method NonGenericStructIl::GetInstanceGenericParamOpen + +} // end of class NonGenericStructIl + +.class public abstract auto ansi sealed beforefieldinit GenericStructIl`1 + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) + .param type T + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .method public hidebysig static class [System.Runtime]System.Action + GetInstanceBasicClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance void valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceBasic() + ldsflda class [System.Runtime]System.Action valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceBasicClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceBasicClosed + + .method public hidebysig static class [System.Runtime]System.Action`1> + GetInstanceBasicOpen() cil managed noinlining + { + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 03 00 00 00 01 00 01 00 00 ) + .maxstack 2 + ldftn instance void valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceBasic() + ldsflda class [System.Runtime]System.Action`1> valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceBasicOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceBasicOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceReturnClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance int32 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceReturn() + ldsflda class [System.Runtime]System.Func`1 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceReturnClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceReturnClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,int32> + GetInstanceReturnOpen() cil managed noinlining + { + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 03 00 00 00 01 00 01 00 00 ) + .maxstack 2 + ldftn instance int32 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceReturn() + ldsflda class [System.Runtime]System.Func`2,int32> valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceReturnOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,int32>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceReturnOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceParamClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance object valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`2 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3,object,object> + GetInstanceParamOpen() cil managed noinlining + { + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 05 00 00 00 01 00 01 01 01 00 00 ) + .maxstack 2 + ldftn instance object valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceParam(object) + ldsflda class [System.Runtime]System.Func`3,object,object> valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,object,object>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceParamOpen + + .method public hidebysig static class [System.Runtime]System.Func`1 + GetInstanceGenericClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance class [System.Runtime]System.Type valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`1 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGenericClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceGenericClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,class [System.Runtime]System.Type> + GetInstanceGenericOpen() cil managed noinlining + { + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 04 00 00 00 01 00 01 01 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGeneric() + ldsflda class [System.Runtime]System.Func`2,class [System.Runtime]System.Type> valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGenericOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,class [System.Runtime]System.Type>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceGenericOpen + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInstanceGenericParamClosed() cil managed noinlining + { + .maxstack 2 + ldftn instance class [System.Runtime]System.Type valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGenericParam(!0) + ldsflda class [System.Runtime]System.Func`2 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGenericParamClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceGenericParamClosed + + .method public hidebysig static class [System.Runtime]System.Func`3,!T,class [System.Runtime]System.Type> + GetInstanceGenericParamOpen() cil managed noinlining + { + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 05 00 00 00 01 00 01 01 01 00 00 ) + .maxstack 2 + ldftn instance class [System.Runtime]System.Type valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGenericParam(!0) + ldsflda class [System.Runtime]System.Func`3,!0,class [System.Runtime]System.Type> valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceGenericParamOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,!T,class [System.Runtime]System.Type>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceGenericParamOpen + + .method public hidebysig static class [System.Runtime]System.Func`1> + GetInstanceDoubleGenericClosed() cil managed noinlining + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 04 00 00 00 01 00 01 01 00 00 ) + .maxstack 2 + ldftn instance valuetype [System.Runtime]System.ValueTuple`2 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceDoubleGeneric() + ldsflda class [System.Runtime]System.Func`1> class [RuntimeHelpersGetDelegateCases]GenericStruct`1/Cache`1::InstanceDoubleGenericClosed + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceDoubleGenericClosed + + .method public hidebysig static class [System.Runtime]System.Func`2,valuetype [System.Runtime]System.ValueTuple`2> + GetInstanceDoubleGenericOpen() cil managed noinlining + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) + .param [0] + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 06 00 00 00 01 00 01 00 01 01 00 00 ) + .maxstack 2 + ldftn instance valuetype [System.Runtime]System.ValueTuple`2 valuetype [RuntimeHelpersGetDelegateCases]GenericStruct`1::InstanceDoubleGeneric() + ldsflda class [System.Runtime]System.Func`2,valuetype [System.Runtime]System.ValueTuple`2> class [RuntimeHelpersGetDelegateCases]GenericStruct`1/Cache`1::InstanceDoubleGenericOpen + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate,valuetype [System.Runtime]System.ValueTuple`2>>(native int, !!0&) + ret + } // end of method GenericStructIl`1::GetInstanceDoubleGenericOpen + +} // end of class GenericStructIl`1 + +.class public abstract auto ansi sealed beforefieldinit VirtualResolver + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInterfaceInstanceDim() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]IInterface::InterfaceInstanceDim() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]VirtualCache::InterfaceInstanceDim + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method VirtualResolver::GetInterfaceInstanceDim + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetInterfaceInstanceDimOverriden() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]IInterface::InterfaceInstanceDimOverriden() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]VirtualCache::InterfaceInstanceDimOverriden + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method VirtualResolver::GetInterfaceInstanceDimOverriden + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetBaseVirtual() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]BaseClass::BaseVirtual() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]VirtualCache::BaseVirtual + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method VirtualResolver::GetBaseVirtual + + .method public hidebysig static class [System.Runtime]System.Func`2 + GetBaseVirtualOverriden() cil managed noinlining + { + .maxstack 2 + ldftn instance object [RuntimeHelpersGetDelegateCases]BaseClass::BaseVirtualOverriden() + ldsflda class [System.Runtime]System.Func`2 [RuntimeHelpersGetDelegateCases]VirtualCache::BaseVirtualOverriden + call !!0 [System.Runtime]System.Runtime.CompilerServices.RuntimeHelpers::GetDelegate>(native int, !!0&) + ret + } // end of method VirtualResolver::GetBaseVirtualOverriden + +} // end of class VirtualResolver diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateIL.ilproj b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateIL.ilproj new file mode 100644 index 00000000000000..6433788916f904 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegateIL.ilproj @@ -0,0 +1,11 @@ + + + Library + + + + + + + + diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate_r.csproj b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate_r.csproj new file mode 100644 index 00000000000000..f0f4b7954b9737 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate_r.csproj @@ -0,0 +1,16 @@ + + + None + + + + + + + + + + + + + diff --git a/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate_ro.csproj b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate_ro.csproj new file mode 100644 index 00000000000000..45705f13e7ed38 --- /dev/null +++ b/src/tests/JIT/Intrinsics/RuntimeHelpersGetDelegate_ro.csproj @@ -0,0 +1,16 @@ + + + None + True + + + + + + + + + + + +