Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;

Expand All @@ -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));
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/// <summary>
Expand All @@ -32,17 +31,6 @@ public IntPtr FunctionPointer
}
}

/// <summary>
/// Pointer to function's universal shared generics code. May be IntPtr.Zero
/// </summary>
public IntPtr UsgFunctionPointer
{
get
{
return _usgFunctionPointer;
}
}

public abstract MethodNameAndSignature NameAndSignature { get; }

private bool? _isNonSharableCache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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<GenericTypeInstanceKey, DefType> _genericTypeInstances;
Expand Down Expand Up @@ -479,9 +471,9 @@ public DefType ResolveGenericInstantiation(DefType typeDef, Instantiation argume
/// <summary>
/// Find a method based on owner type and nativelayout name, method instantiation, and signature.
/// </summary>
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))
Expand All @@ -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;
}

Expand Down
75 changes: 75 additions & 0 deletions src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ internal static int Run()
TestRecursionThroughGenericLookups.Run();
TestRecursionInFields.Run();
TestGvmLookupDependency.Run();
Test99198Regression.Run();
TestInvokeMemberCornerCaseInGenerics.Run();
TestRefAny.Run();
TestNullableCasting.Run();
Expand Down Expand Up @@ -3480,6 +3481,80 @@ public static void Run()
}
}

class Test99198Regression
{
delegate void Set<T>(ref T t, IFoo ifoo);

interface IFoo
{
void Do<T>();
}

class Atom { }

struct Foo<T> : IFoo
{
public nint Cookie1;
public nint Cookie2;

public void Do<T1>()
{
Cookie1 = 42;
}
}

class C<T> where T : IFoo
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Set(ref T t, IFoo ifoo)
{
t.Do<T>();
ifoo.Do<T>();
}
}

public static void RunDynamic<T>()
{
static Type GetObject() => typeof(Foo<T>);
var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate<Set<Foo<T>>>();

Foo<T> ob = default;
IFoo boxed = ob;

s(ref ob, boxed);

if (ob.Cookie1 != 42 || ob.Cookie2 != 0)
throw new Exception();

ob = (Foo<T>)boxed;
if (ob.Cookie1 != 42 || ob.Cookie2 != 0)
throw new Exception();
}

public static void Run()
{
new C<Foo<string>>().ToString();

static Type GetObject() => typeof(Foo<object>);
var s = typeof(C<>).MakeGenericType(GetObject()).GetMethod("Set").CreateDelegate<Set<Foo<object>>>();

Foo<object> ob = default;
IFoo boxed = ob;

s(ref ob, boxed);

if (ob.Cookie1 != 42 || ob.Cookie2 != 0)
throw new Exception();

ob = (Foo<object>)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, []);
}
}

class TestInvokeMemberCornerCaseInGenerics
{
class Generic<T>
Expand Down