From f510ee6660c5387c36ab138c2ba1c10a4e202c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 8 Mar 2024 06:48:20 +0100 Subject: [PATCH 1/2] Fix mismatch between boxed/unboxed method entrypoints Fixes #99198. --- .../CompilerServices/FunctionPointerOps.cs | 10 +++-- .../TypeLoader/NativeLayoutInfoLoadContext.cs | 10 ++--- .../Runtime/TypeLoader/TypeBuilder.cs | 8 ++-- ...ronment.ConstructedGenericMethodsLookup.cs | 8 ++-- .../TypeLoaderEnvironment.GVMResolution.cs | 4 +- ...peLoaderEnvironment.LdTokenResultLookup.cs | 4 +- .../TypeLoader/TypeLoaderEnvironment.cs | 2 +- .../Internal/TypeSystem/MethodDesc.Runtime.cs | 22 +++------- .../TypeSystem/RuntimeMethodDesc.Canon.cs | 2 +- .../Internal/TypeSystem/RuntimeMethodDesc.cs | 4 +- .../TypeSystem/TypeSystemContext.Runtime.cs | 24 +++-------- .../SmokeTests/UnitTests/Generics.cs | 43 +++++++++++++++++++ 12 files changed, 79 insertions(+), 62 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs index a0f5312c92304e..d2ebc90309e6df 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/FunctionPointerOps.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; -using Internal.Runtime.Augments; +using Debug = System.Diagnostics.Debug; namespace Internal.Runtime.CompilerServices { @@ -56,6 +56,8 @@ public override int GetHashCode() public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunctionPointer, IntPtr instantiationArgument) { + Debug.Assert(canonFunctionPointer != IntPtr.Zero); + if (instantiationArgument == IntPtr.Zero) return canonFunctionPointer; @@ -79,7 +81,7 @@ public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunction // Generate new chunk if existing chunks are insufficient if (s_genericFunctionPointerCollection.Count <= newChunkIndex) { - System.Diagnostics.Debug.Assert(newSubChunkIndex == 0); + Debug.Assert(newSubChunkIndex == 0); // New generic descriptors are allocated on the native heap and not tracked in the GC. IntPtr pNewMem = (IntPtr)NativeMemory.Alloc(c_genericDictionaryChunkSize, (nuint)sizeof(GenericMethodDescriptor)); @@ -100,8 +102,8 @@ public static unsafe IntPtr GetGenericMethodFunctionPointer(IntPtr canonFunction uint subChunkIndex = index % c_genericDictionaryChunkSize; GenericMethodDescriptor* genericFunctionPointer = &((GenericMethodDescriptor*)s_genericFunctionPointerCollection[chunkIndex])[subChunkIndex]; - System.Diagnostics.Debug.Assert(canonFunctionPointer == genericFunctionPointer->MethodFunctionPointer); - System.Diagnostics.Debug.Assert(instantiationArgument == genericFunctionPointer->InstantiationArgument); + Debug.Assert(canonFunctionPointer == genericFunctionPointer->MethodFunctionPointer); + Debug.Assert(instantiationArgument == genericFunctionPointer->InstantiationArgument); return (IntPtr)((byte*)genericFunctionPointer + FatFunctionPointerOffset); } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs index 04958f81927abf..90a2c9857c6dc1 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/NativeLayoutInfoLoadContext.cs @@ -193,18 +193,16 @@ internal MethodDesc GetMethod(ref NativeParser parser, out RuntimeSignature meth { TypeDesc[] typeArguments = GetTypeSequence(ref parser); Debug.Assert(typeArguments.Length > 0); - retVal = this._typeSystemContext.ResolveGenericMethodInstantiation(unboxingStub, containingType, nameAndSignature, new Instantiation(typeArguments), functionPointer, (flags & MethodFlags.FunctionPointerIsUSG) != 0); + retVal = this._typeSystemContext.ResolveGenericMethodInstantiation(unboxingStub, containingType, nameAndSignature, new Instantiation(typeArguments)); } else { - retVal = this._typeSystemContext.ResolveRuntimeMethod(unboxingStub, containingType, nameAndSignature, functionPointer, (flags & MethodFlags.FunctionPointerIsUSG) != 0); + retVal = this._typeSystemContext.ResolveRuntimeMethod(unboxingStub, containingType, nameAndSignature); } - if ((flags & MethodFlags.FunctionPointerIsUSG) != 0) + if ((flags & MethodFlags.HasFunctionPointer) != 0) { - // TODO, consider a change such that if a USG function pointer is passed in, but we have - // a way to get a non-usg pointer, that may be preferable - Debug.Assert(retVal.UsgFunctionPointer != IntPtr.Zero); + retVal.SetFunctionPointer(functionPointer); } return retVal; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs index 8ee004b11d42c7..43ea9b81d8bf0e 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs @@ -300,7 +300,7 @@ internal void ParseNativeLayoutInfo(InstantiatedMethod method) if (method.UnboxingStub) { // Strip unboxing stub, note the first parameter which is false - nonTemplateMethod = (InstantiatedMethod)method.Context.ResolveGenericMethodInstantiation(false, (DefType)method.OwningType, method.NameAndSignature, method.Instantiation, IntPtr.Zero, false); + nonTemplateMethod = (InstantiatedMethod)method.Context.ResolveGenericMethodInstantiation(false, (DefType)method.OwningType, method.NameAndSignature, method.Instantiation); } uint nativeLayoutInfoToken; @@ -311,9 +311,11 @@ internal void ParseNativeLayoutInfo(InstantiatedMethod method) throw new MissingTemplateException(); } - if (templateMethod.FunctionPointer != IntPtr.Zero) + // We might have a mismatch between unboxing/non-unboxing variants so only remember it for static methods + if (TypeLoaderEnvironment.IsStaticMethodSignature(templateMethod.NameAndSignature) + && templateMethod.FunctionPointer != IntPtr.Zero) { - nonTemplateMethod.SetFunctionPointer(templateMethod.FunctionPointer, isFunctionPointerUSG: false); + nonTemplateMethod.SetFunctionPointer(templateMethod.FunctionPointer); } // Ensure that if this method is non-shareable from a normal canonical perspective, then diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs index c5f5308226148d..c8437c4a4e437c 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.ConstructedGenericMethodsLookup.cs @@ -153,7 +153,7 @@ internal override bool MatchParsedEntry(ref NativeParser entryParser, ref Extern DefType parsedDeclaringType = context.ResolveRuntimeTypeHandle(parsedDeclaringTypeHandle) as DefType; Instantiation parsedArgs = context.ResolveRuntimeTypeHandles(parsedArgsHandles); - InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, nameAndSignature, parsedArgs, IntPtr.Zero, false); + InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, nameAndSignature, parsedArgs); return parsedGenericMethod == _methodToLookup; } @@ -164,7 +164,7 @@ internal override bool MatchGenericMethodEntry(GenericMethodEntry entry) DefType parsedDeclaringType = context.ResolveRuntimeTypeHandle(entry._declaringTypeHandle) as DefType; Instantiation parsedArgs = context.ResolveRuntimeTypeHandles(entry._genericMethodArgumentHandles); - InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, entry._methodNameAndSignature, parsedArgs, IntPtr.Zero, false); + InstantiatedMethod parsedGenericMethod = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, parsedDeclaringType, entry._methodNameAndSignature, parsedArgs); return parsedGenericMethod == _methodToLookup; } @@ -267,9 +267,7 @@ public bool TryGetGenericVirtualMethodPointer(InstantiatedMethod method, out Int return false; } - methodPointer = templateMethod.IsCanonicalMethod(CanonicalFormKind.Universal) ? - templateMethod.UsgFunctionPointer : - templateMethod.FunctionPointer; + methodPointer = templateMethod.FunctionPointer; if (!TryLookupGenericMethodDictionary(new MethodDescBasedGenericMethodLookup(method), out dictionaryPointer)) { diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs index d9416b32863869..c73df4af62b5d7 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs @@ -309,7 +309,7 @@ private static InstantiatedMethod FindMatchingInterfaceSlot(NativeFormatModuleIn Debug.Assert(interfaceImplType != null); } - return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, interfaceImplType, targetMethodNameAndSignature, slotMethod.Instantiation, IntPtr.Zero, false); + return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, interfaceImplType, targetMethodNameAndSignature, slotMethod.Instantiation); } } } @@ -500,7 +500,7 @@ private static InstantiatedMethod ResolveGenericVirtualMethodTarget(DefType targ Debug.Assert(targetMethodNameAndSignature != null); TypeSystemContext context = slotMethod.Context; - return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, targetType, targetMethodNameAndSignature, slotMethod.Instantiation, IntPtr.Zero, false); + return (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, targetType, targetMethodNameAndSignature, slotMethod.Instantiation); } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs index 9ddec8a39d7aa3..dd2bc75e3d61d4 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.LdTokenResultLookup.cs @@ -388,10 +388,10 @@ public MethodDesc GetMethodDescForDynamicRuntimeMethodHandle(TypeSystemContext c if (genericMethodArgs != null) { Instantiation methodInst = context.ResolveRuntimeTypeHandles(genericMethodArgs); - return context.ResolveGenericMethodInstantiation(unboxingStub: false, type, nameAndSignature, methodInst, default, default); + return context.ResolveGenericMethodInstantiation(unboxingStub: false, type, nameAndSignature, methodInst); } - return context.ResolveRuntimeMethod(unboxingStub: false, type, nameAndSignature, default, default); + return context.ResolveRuntimeMethod(unboxingStub: false, type, nameAndSignature); } private unsafe bool TryGetStaticRuntimeMethodHandleComponents(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out MethodNameAndSignature nameAndSignature, out RuntimeTypeHandle[] genericMethodArgs) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs index 42864c10f2ebc7..22c07b2e837bc6 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs @@ -485,7 +485,7 @@ public bool TryGetGenericMethodDictionaryForComponents(RuntimeTypeHandle declari TypeSystemContext context = TypeSystemContextFactory.Create(); DefType declaringType = (DefType)context.ResolveRuntimeTypeHandle(declaringTypeHandle); - InstantiatedMethod methodBeingLoaded = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, declaringType, nameAndSignature, context.ResolveRuntimeTypeHandles(genericMethodArgHandles), IntPtr.Zero, false); + InstantiatedMethod methodBeingLoaded = (InstantiatedMethod)context.ResolveGenericMethodInstantiation(false, declaringType, nameAndSignature, context.ResolveRuntimeTypeHandles(genericMethodArgHandles)); if (TryLookupGenericMethodDictionary(new MethodDescBasedGenericMethodLookup(methodBeingLoaded), out methodDictionary)) { diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs index 89161ce5309d72..24dceff6d0f05f 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/MethodDesc.Runtime.cs @@ -6,19 +6,18 @@ using Internal.Runtime.CompilerServices; +using Debug = System.Diagnostics.Debug; + namespace Internal.TypeSystem { public partial class MethodDesc { private IntPtr _functionPointer; - private IntPtr _usgFunctionPointer; - public void SetFunctionPointer(IntPtr functionPointer, bool isFunctionPointerUSG) + public void SetFunctionPointer(IntPtr functionPointer) { - if (isFunctionPointerUSG) - _usgFunctionPointer = functionPointer; - else - _functionPointer = functionPointer; + Debug.Assert(_functionPointer == IntPtr.Zero || _functionPointer == functionPointer); + _functionPointer = functionPointer; } /// @@ -32,17 +31,6 @@ public IntPtr FunctionPointer } } - /// - /// Pointer to function's universal shared generics code. May be IntPtr.Zero - /// - public IntPtr UsgFunctionPointer - { - get - { - return _usgFunctionPointer; - } - } - public abstract MethodNameAndSignature NameAndSignature { get; } private bool? _isNonSharableCache; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs index 956dcdcafb9761..ad12ea96f00817 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.Canon.cs @@ -23,7 +23,7 @@ public override MethodDesc GetCanonMethodTarget(CanonicalFormKind kind) if (canonicalizedTypeOfTargetMethod == OwningType) return this; - return Context.ResolveRuntimeMethod(this.UnboxingStub, canonicalizedTypeOfTargetMethod, this.NameAndSignature, IntPtr.Zero, false); + return Context.ResolveRuntimeMethod(this.UnboxingStub, canonicalizedTypeOfTargetMethod, this.NameAndSignature); } } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs index f95b8561e3a9dc..042b1957e22b65 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs @@ -117,7 +117,7 @@ public override MethodDesc GetTypicalMethodDefinition() } // Otherwise, find its equivalent on the type definition of the owning type - return Context.ResolveRuntimeMethod(UnboxingStub, (DefType)owningTypeDefinition, _nameAndSignature, IntPtr.Zero, false); + return Context.ResolveRuntimeMethod(UnboxingStub, (DefType)owningTypeDefinition, _nameAndSignature); } public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) @@ -127,7 +127,7 @@ public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, TypeDesc owningType = method.OwningType; TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); if (owningType != instantiatedOwningType) - method = instantiatedOwningType.Context.ResolveRuntimeMethod(UnboxingStub, (DefType)instantiatedOwningType, _nameAndSignature, IntPtr.Zero, false); + method = instantiatedOwningType.Context.ResolveRuntimeMethod(UnboxingStub, (DefType)instantiatedOwningType, _nameAndSignature); Instantiation instantiation = method.Instantiation; TypeDesc[] clone = null; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs index 464a370a5f7be3..1e4b888552220a 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs @@ -417,7 +417,7 @@ protected override MethodDesc CreateValueFromKey(RuntimeMethodKey key) // Instantiated Types always get their methods through GetMethodForInstantiatedType if (key._owningType is InstantiatedType) { - MethodDesc typicalMethod = key._owningType.Context.ResolveRuntimeMethod(key._unboxingStub, (DefType)key._owningType.GetTypeDefinition(), key._methodNameAndSignature, IntPtr.Zero, false); + MethodDesc typicalMethod = key._owningType.Context.ResolveRuntimeMethod(key._unboxingStub, (DefType)key._owningType.GetTypeDefinition(), key._methodNameAndSignature); return typicalMethod.Context.GetMethodForInstantiatedType(typicalMethod, (InstantiatedType)key._owningType); } } @@ -434,18 +434,10 @@ protected override MethodDesc CreateValueFromKey(RuntimeMethodKey key) private RuntimeMethodKey.RuntimeMethodKeyHashtable _runtimeMethods; - internal MethodDesc ResolveRuntimeMethod(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature, IntPtr functionPointer, bool usgFunctionPointer) + internal MethodDesc ResolveRuntimeMethod(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature) { _runtimeMethods ??= new RuntimeMethodKey.RuntimeMethodKeyHashtable(); - - MethodDesc retVal = _runtimeMethods.GetOrCreateValue(new RuntimeMethodKey(unboxingStub, owningType, nameAndSignature)); - - if (functionPointer != IntPtr.Zero) - { - retVal.SetFunctionPointer(functionPointer, usgFunctionPointer); - } - - return retVal; + return _runtimeMethods.GetOrCreateValue(new RuntimeMethodKey(unboxingStub, owningType, nameAndSignature)); } private LowLevelDictionary _genericTypeInstances; @@ -479,9 +471,9 @@ public DefType ResolveGenericInstantiation(DefType typeDef, Instantiation argume /// /// Find a method based on owner type and nativelayout name, method instantiation, and signature. /// - public MethodDesc ResolveGenericMethodInstantiation(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature, Instantiation methodInstantiation, IntPtr functionPointer, bool usgFunctionPointer) + public MethodDesc ResolveGenericMethodInstantiation(bool unboxingStub, DefType owningType, MethodNameAndSignature nameAndSignature, Instantiation methodInstantiation) { - var uninstantiatedMethod = ResolveRuntimeMethod(unboxingStub, owningType, nameAndSignature, IntPtr.Zero, false); + var uninstantiatedMethod = ResolveRuntimeMethod(unboxingStub, owningType, nameAndSignature); MethodDesc returnedMethod; if (methodInstantiation.IsNull || (methodInstantiation.Length == 0)) @@ -492,12 +484,6 @@ public MethodDesc ResolveGenericMethodInstantiation(bool unboxingStub, DefType o { returnedMethod = GetInstantiatedMethod(uninstantiatedMethod, methodInstantiation); } - - if (functionPointer != IntPtr.Zero) - { - returnedMethod.SetFunctionPointer(functionPointer, usgFunctionPointer); - } - return returnedMethod; } diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs index a9d3d44c758dde..5fc713f313da37 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs @@ -55,6 +55,7 @@ internal static int Run() TestRecursionThroughGenericLookups.Run(); TestRecursionInFields.Run(); TestGvmLookupDependency.Run(); + Test99198Regression.Run(); TestInvokeMemberCornerCaseInGenerics.Run(); TestRefAny.Run(); TestNullableCasting.Run(); @@ -3480,6 +3481,48 @@ public static void Run() } } + class Test99198Regression + { + delegate void Set(ref T t); + + interface IFoo + { + void Do(); + } + + struct Foo : IFoo + { + public nint Cookie1; + public nint Cookie2; + + public void Do() + { + Cookie1 = 42; + } + } + + class C where T : IFoo + { + public static void Set(ref T t) + { + t.Do(); + } + } + + public static void Run() + { + new C>().ToString(); + + static Type GetObject() => typeof(Foo); + var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate>>(); + + Foo ob = default; + s(ref ob); + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + } + } + class TestInvokeMemberCornerCaseInGenerics { class Generic From 4bd3cb57cece6f2df9afed267a93adc51bd35b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 18 Apr 2024 23:00:15 +0200 Subject: [PATCH 2/2] Extend the test --- .../SmokeTests/UnitTests/Generics.cs | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs index 5fc713f313da37..f362c08d424649 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs @@ -3483,13 +3483,15 @@ public static void Run() class Test99198Regression { - delegate void Set(ref T t); + delegate void Set(ref T t, IFoo ifoo); interface IFoo { void Do(); } + class Atom { } + struct Foo : IFoo { public nint Cookie1; @@ -3503,12 +3505,32 @@ public void Do() class C where T : IFoo { - public static void Set(ref T t) + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Set(ref T t, IFoo ifoo) { t.Do(); + ifoo.Do(); } } + public static void RunDynamic() + { + static Type GetObject() => typeof(Foo); + var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate>>(); + + Foo ob = default; + IFoo boxed = ob; + + s(ref ob, boxed); + + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + + ob = (Foo)boxed; + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + } + public static void Run() { new C>().ToString(); @@ -3517,9 +3539,19 @@ public static void Run() var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate>>(); Foo ob = default; - s(ref ob); + IFoo boxed = ob; + + s(ref ob, boxed); + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) throw new Exception(); + + ob = (Foo)boxed; + if (ob.Cookie1 != 42 || ob.Cookie2 != 0) + throw new Exception(); + + static Type GetAtom() => typeof(Atom); + typeof(Test99198Regression).GetMethod(nameof(RunDynamic)).MakeGenericMethod(GetAtom()).Invoke(null, []); } }