diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
index 6a56d48790efc9..348f0878a4bb87 100644
--- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
@@ -68,9 +68,18 @@ internal unsafe struct DispatchMapEntry
internal ushort _usInterfaceMethodSlot;
internal ushort _usImplMethodSlot;
}
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct StaticDispatchMapEntry
+ {
+ // Do not put any other fields before this one. We need StaticDispatchMapEntry* be castable to DispatchMapEntry*.
+ internal DispatchMapEntry _entry;
+ internal ushort _usContextMapSource;
+ }
private ushort _standardEntryCount; // Implementations on the class
private ushort _defaultEntryCount; // Default implementations
+ private ushort _standardStaticEntryCount; // Implementations on the class (static virtuals)
+ private ushort _defaultStaticEntryCount; // Default implementations (static virtuals)
private DispatchMapEntry _dispatchMap; // at least one entry if any interfaces defined
public uint NumStandardEntries
@@ -101,20 +110,54 @@ public uint NumDefaultEntries
#endif
}
- public int Size
+ public uint NumStandardStaticEntries
{
get
{
- return sizeof(ushort) + sizeof(ushort) + sizeof(DispatchMapEntry) * ((int)_standardEntryCount + (int)_defaultEntryCount);
+ return _standardStaticEntryCount;
+ }
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _standardStaticEntryCount = checked((ushort)value);
}
+#endif
}
- public DispatchMapEntry* this[int index]
+ public uint NumDefaultStaticEntries
{
get
{
- return (DispatchMapEntry*)Unsafe.AsPointer(ref Unsafe.Add(ref _dispatchMap, index));
+ return _defaultStaticEntryCount;
}
+#if TYPE_LOADER_IMPLEMENTATION
+ set
+ {
+ _defaultStaticEntryCount = checked((ushort)value);
+ }
+#endif
+ }
+
+ public int Size
+ {
+ get
+ {
+ return sizeof(ushort) + sizeof(ushort) + sizeof(ushort) + sizeof(ushort)
+ + sizeof(DispatchMapEntry) * ((int)_standardEntryCount + (int)_defaultEntryCount)
+ + sizeof(StaticDispatchMapEntry) * ((int)_standardStaticEntryCount + (int)_defaultStaticEntryCount);
+ }
+ }
+
+ public DispatchMapEntry* GetEntry(int index)
+ {
+ Debug.Assert(index <= _defaultEntryCount + _standardEntryCount);
+ return (DispatchMapEntry*)Unsafe.AsPointer(ref Unsafe.Add(ref _dispatchMap, index));
+ }
+
+ public DispatchMapEntry* GetStaticEntry(int index)
+ {
+ Debug.Assert(index <= _defaultStaticEntryCount + _standardStaticEntryCount);
+ return (DispatchMapEntry*)(((StaticDispatchMapEntry*)Unsafe.AsPointer(ref Unsafe.Add(ref _dispatchMap, _standardEntryCount + _defaultEntryCount))) + index);
}
}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
index 8c36e8312e4856..841f0cd145643b 100644
--- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
@@ -82,7 +82,7 @@ private static IntPtr RhResolveDispatch(object pObject, EETypePtr interfaceType,
}
[RuntimeExport("RhResolveDispatchOnType")]
- private static IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr interfaceType, ushort slot)
+ private static IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr interfaceType, ushort slot, EETypePtr* pGenericContext)
{
// Type of object we're dispatching on.
MethodTable* pInstanceType = instanceType.ToPointer();
@@ -92,7 +92,8 @@ private static IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr
return DispatchResolve.FindInterfaceMethodImplementationTarget(pInstanceType,
pInterfaceType,
- slot);
+ slot,
+ (MethodTable**)pGenericContext);
}
private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void* cell, ref DispatchCellInfo cellInfo)
@@ -108,7 +109,8 @@ private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void* cell,
IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
cellInfo.InterfaceType.ToPointer(),
- cellInfo.InterfaceSlot);
+ cellInfo.InterfaceSlot,
+ ppGenericContext: null);
if (pTargetCode == IntPtr.Zero && pInstanceType->IsIDynamicInterfaceCastable)
{
// Dispatch not resolved through normal dispatch map, try using the IDynamicInterfaceCastable
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs
index aa661feaf6cd1b..d46aaa96e3a017 100644
--- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs
@@ -12,7 +12,8 @@ internal static unsafe class DispatchResolve
{
public static IntPtr FindInterfaceMethodImplementationTarget(MethodTable* pTgtType,
MethodTable* pItfType,
- ushort itfSlotNumber)
+ ushort itfSlotNumber,
+ /* out */ MethodTable** ppGenericContext)
{
DynamicModule* dynamicModule = pTgtType->DynamicModule;
@@ -39,7 +40,7 @@ public static IntPtr FindInterfaceMethodImplementationTarget(MethodTable* pTgtTy
{
ushort implSlotNumber;
if (FindImplSlotForCurrentType(
- pCur, pItfType, itfSlotNumber, fDoDefaultImplementationLookup, &implSlotNumber))
+ pCur, pItfType, itfSlotNumber, fDoDefaultImplementationLookup, &implSlotNumber, ppGenericContext))
{
IntPtr targetMethod;
if (implSlotNumber < pCur->NumVtableSlots)
@@ -85,7 +86,8 @@ private static bool FindImplSlotForCurrentType(MethodTable* pTgtType,
MethodTable* pItfType,
ushort itfSlotNumber,
bool fDoDefaultImplementationLookup,
- ushort* pImplSlotNumber)
+ ushort* pImplSlotNumber,
+ MethodTable** ppGenericContext)
{
bool fRes = false;
@@ -110,13 +112,13 @@ private static bool FindImplSlotForCurrentType(MethodTable* pTgtType,
bool fDoVariantLookup = false; // do not check variance for first scan of dispatch map
fRes = FindImplSlotInSimpleMap(
- pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup, fDoDefaultImplementationLookup);
+ pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, ppGenericContext, fDoVariantLookup, fDoDefaultImplementationLookup);
if (!fRes)
{
fDoVariantLookup = true; // check variance for second scan of dispatch map
fRes = FindImplSlotInSimpleMap(
- pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup, fDoDefaultImplementationLookup);
+ pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, ppGenericContext, fDoVariantLookup, fDoDefaultImplementationLookup);
}
}
@@ -127,6 +129,7 @@ private static bool FindImplSlotInSimpleMap(MethodTable* pTgtType,
MethodTable* pItfType,
uint itfSlotNumber,
ushort* pImplSlotNumber,
+ MethodTable** ppGenericContext,
bool actuallyCheckVariance,
bool checkDefaultImplementations)
{
@@ -176,10 +179,18 @@ private static bool FindImplSlotInSimpleMap(MethodTable* pTgtType,
}
}
+ // It only makes sense to ask for generic context if we're asking about a static method
+ bool fStaticDispatch = ppGenericContext != null;
+
+ // We either scan the instance or static portion of the dispatch map. Depends on what the caller wants.
DispatchMap* pMap = pTgtType->DispatchMap;
- DispatchMap.DispatchMapEntry* i = (*pMap)[checkDefaultImplementations ? (int)pMap->NumStandardEntries : 0];
- DispatchMap.DispatchMapEntry* iEnd = (*pMap)[checkDefaultImplementations ? (int)(pMap->NumStandardEntries + pMap->NumDefaultEntries) : (int)pMap->NumStandardEntries];
- for (; i != iEnd; ++i)
+ DispatchMap.DispatchMapEntry* i = fStaticDispatch ?
+ pMap->GetStaticEntry(checkDefaultImplementations ? (int)pMap->NumStandardStaticEntries : 0) :
+ pMap->GetEntry(checkDefaultImplementations ? (int)pMap->NumStandardEntries : 0);
+ DispatchMap.DispatchMapEntry* iEnd = fStaticDispatch ?
+ pMap->GetStaticEntry(checkDefaultImplementations ? (int)(pMap->NumStandardStaticEntries + pMap->NumDefaultStaticEntries) : (int)pMap->NumStandardStaticEntries) :
+ pMap->GetEntry(checkDefaultImplementations ? (int)(pMap->NumStandardEntries + pMap->NumDefaultEntries) : (int)pMap->NumStandardEntries);
+ for (; i != iEnd; i = fStaticDispatch ? (DispatchMap.DispatchMapEntry*)(((DispatchMap.StaticDispatchMapEntry*)i) + 1) : i + 1)
{
if (i->_usInterfaceMethodSlot == itfSlotNumber)
{
@@ -192,6 +203,12 @@ private static bool FindImplSlotInSimpleMap(MethodTable* pTgtType,
if (pCurEntryType == pItfType)
{
*pImplSlotNumber = i->_usImplMethodSlot;
+
+ // If this is a static method, the entry point is not usable without generic context.
+ // (Instance methods acquire the generic context from their `this`.)
+ if (fStaticDispatch)
+ *ppGenericContext = GetGenericContextSource(pTgtType, i);
+
return true;
}
else if (fCheckVariance && ((fArrayCovariance && pCurEntryType->IsGeneric) || pCurEntryType->HasGenericVariance))
@@ -227,6 +244,12 @@ private static bool FindImplSlotInSimpleMap(MethodTable* pTgtType,
if (TypeCast.TypeParametersAreCompatible(itfArity, pCurEntryInstantiation, pItfInstantiation, pItfVarianceInfo, fArrayCovariance, null))
{
*pImplSlotNumber = i->_usImplMethodSlot;
+
+ // If this is a static method, the entry point is not usable without generic context.
+ // (Instance methods acquire the generic context from their `this`.)
+ if (fStaticDispatch)
+ *ppGenericContext = GetGenericContextSource(pTgtType, i);
+
return true;
}
}
@@ -235,5 +258,16 @@ private static bool FindImplSlotInSimpleMap(MethodTable* pTgtType,
return false;
}
+
+ private static unsafe MethodTable* GetGenericContextSource(MethodTable* pTgtType, DispatchMap.DispatchMapEntry* pEntry)
+ {
+ ushort usEncodedValue = ((DispatchMap.StaticDispatchMapEntry*)pEntry)->_usContextMapSource;
+ return usEncodedValue switch
+ {
+ StaticVirtualMethodContextSource.None => null,
+ StaticVirtualMethodContextSource.ContextFromThisClass => pTgtType,
+ _ => pTgtType->InterfaceMap[usEncodedValue - StaticVirtualMethodContextSource.ContextFromFirstInterface].InterfaceType
+ };
+ }
}
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
index 03e4fffed6a990..09ee25f38db8ef 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
@@ -641,6 +641,17 @@ public static IntPtr ResolveDispatchOnType(RuntimeTypeHandle instanceType, Runti
return RuntimeImports.RhResolveDispatchOnType(CreateEETypePtr(instanceType), CreateEETypePtr(interfaceType), checked((ushort)slot));
}
+ public static unsafe IntPtr ResolveStaticDispatchOnType(RuntimeTypeHandle instanceType, RuntimeTypeHandle interfaceType, int slot, out RuntimeTypeHandle genericContext)
+ {
+ EETypePtr genericContextPtr = default;
+ IntPtr result = RuntimeImports.RhResolveDispatchOnType(CreateEETypePtr(instanceType), CreateEETypePtr(interfaceType), checked((ushort)slot), &genericContextPtr);
+ if (result != IntPtr.Zero)
+ genericContext = new RuntimeTypeHandle(genericContextPtr);
+ else
+ genericContext = default;
+ return result;
+ }
+
public static IntPtr ResolveDispatch(object instance, RuntimeTypeHandle interfaceType, int slot)
{
return RuntimeImports.RhResolveDispatch(instance, CreateEETypePtr(interfaceType), checked((ushort)slot));
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
index aedbe429fd00fb..ff23d238e10eb7 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
@@ -454,7 +454,14 @@ internal static unsafe int RhCompatibleReentrantWaitAny(bool alertable, int time
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhResolveDispatchOnType")]
- internal static extern IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr interfaceType, ushort slot);
+ // For my life cannot figure out the ordering of modifiers this is expecting.
+#pragma warning disable IDE0036
+ internal static extern unsafe IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr interfaceType, ushort slot, EETypePtr* pGenericContext);
+
+ internal static unsafe IntPtr RhResolveDispatchOnType(EETypePtr instanceType, EETypePtr interfaceType, ushort slot)
+ {
+ return RhResolveDispatchOnType(instanceType, interfaceType, slot, null);
+ }
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetRuntimeHelperForType")]
diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs
index c16a125c3474e4..b31abb9f70d49b 100644
--- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs
+++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs
@@ -583,14 +583,25 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo
DispatchMap* pDynamicDispatchMap = (DispatchMap*)dynamicDispatchMapPtr;
pDynamicDispatchMap->NumStandardEntries = pTemplateDispatchMap->NumStandardEntries;
pDynamicDispatchMap->NumDefaultEntries = pTemplateDispatchMap->NumDefaultEntries;
+ pDynamicDispatchMap->NumStandardStaticEntries = pTemplateDispatchMap->NumStandardStaticEntries;
+ pDynamicDispatchMap->NumDefaultStaticEntries = pTemplateDispatchMap->NumDefaultStaticEntries;
- for (int i = 0; i < pTemplateDispatchMap->NumStandardEntries + pTemplateDispatchMap->NumDefaultEntries; i++)
+ uint numInstanceEntries = pTemplateDispatchMap->NumStandardEntries + pTemplateDispatchMap->NumDefaultEntries;
+ for (uint i = 0; i < numInstanceEntries + pTemplateDispatchMap->NumStandardStaticEntries + pTemplateDispatchMap->NumDefaultStaticEntries; i++)
{
- DispatchMap.DispatchMapEntry* pTemplateEntry = (*pTemplateDispatchMap)[i];
- DispatchMap.DispatchMapEntry* pDynamicEntry = (*pDynamicDispatchMap)[i];
+ DispatchMap.DispatchMapEntry* pTemplateEntry = i < numInstanceEntries ?
+ pTemplateDispatchMap->GetEntry((int)i) :
+ pTemplateDispatchMap->GetStaticEntry((int)(i - numInstanceEntries));
+ DispatchMap.DispatchMapEntry* pDynamicEntry = i < numInstanceEntries ?
+ pDynamicDispatchMap->GetEntry((int)i) :
+ pDynamicDispatchMap->GetStaticEntry((int)(i - numInstanceEntries));
pDynamicEntry->_usInterfaceIndex = pTemplateEntry->_usInterfaceIndex;
pDynamicEntry->_usInterfaceMethodSlot = pTemplateEntry->_usInterfaceMethodSlot;
+ if (i >= numInstanceEntries)
+ {
+ ((DispatchMap.StaticDispatchMapEntry*)pDynamicEntry)->_usContextMapSource = ((DispatchMap.StaticDispatchMapEntry*)pTemplateEntry)->_usContextMapSource;
+ }
if (pTemplateEntry->_usImplMethodSlot < pTemplateEEType->NumVtableSlots)
{
pDynamicEntry->_usImplMethodSlot = (ushort)state.VTableSlotsMapping.GetVTableSlotInTargetType(pTemplateEntry->_usImplMethodSlot);
diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs
index 69df4c61d68df1..3aa25ab4816abd 100644
--- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs
+++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/GenericDictionaryCell.cs
@@ -239,6 +239,43 @@ internal override IntPtr Create(TypeBuilder builder)
}
#endif
+ ///
+ /// Used for non-generic static constrained Methods
+ ///
+ private class NonGenericStaticConstrainedMethodCell : GenericDictionaryCell
+ {
+ internal TypeDesc ConstraintType;
+ internal TypeDesc ConstrainedMethodType;
+ internal int ConstrainedMethodSlot;
+
+ internal override void Prepare(TypeBuilder builder)
+ {
+ if (ConstraintType.IsCanonicalSubtype(CanonicalFormKind.Any) || ConstrainedMethodType.IsCanonicalSubtype(CanonicalFormKind.Any))
+ Environment.FailFast("Unable to compute call information for a canonical type/method.");
+
+ builder.RegisterForPreparation(ConstraintType);
+ builder.RegisterForPreparation(ConstrainedMethodType);
+ }
+
+ internal override IntPtr Create(TypeBuilder builder)
+ {
+ IntPtr result = RuntimeAugments.ResolveStaticDispatchOnType(
+ builder.GetRuntimeTypeHandle(ConstraintType),
+ builder.GetRuntimeTypeHandle(ConstrainedMethodType),
+ ConstrainedMethodSlot,
+ out RuntimeTypeHandle genericContext);
+
+ Debug.Assert(result != IntPtr.Zero);
+
+ if (!genericContext.IsNull())
+ {
+ result = FunctionPointerOps.GetGenericMethodFunctionPointer(result, genericContext.ToIntPtr());
+ }
+
+ return result;
+ }
+ }
+
private class StaticDataCell : GenericDictionaryCell
{
internal StaticDataKind DataKind;
@@ -1749,6 +1786,21 @@ internal static GenericDictionaryCell ParseAndCreateCell(NativeLayoutInfoLoadCon
}
break;
#endif
+ case FixupSignatureKind.NonGenericStaticConstrainedMethod:
+ {
+ var constraintType = nativeLayoutInfoLoadContext.GetType(ref parser);
+ var constrainedMethodType = nativeLayoutInfoLoadContext.GetType(ref parser);
+ var constrainedMethodSlot = parser.GetUnsigned();
+ TypeLoaderLogger.WriteLine("NonGenericStaticConstrainedMethod: " + constraintType.ToString() + " Method " + constrainedMethodType.ToString() + ", slot #" + constrainedMethodSlot.LowLevelToString());
+
+ cell = new NonGenericStaticConstrainedMethodCell()
+ {
+ ConstraintType = constraintType,
+ ConstrainedMethodType = constrainedMethodType,
+ ConstrainedMethodSlot = (int)constrainedMethodSlot
+ };
+ }
+ break;
case FixupSignatureKind.IsInst:
case FixupSignatureKind.CastClass:
@@ -1793,6 +1845,7 @@ internal static GenericDictionaryCell ParseAndCreateCell(NativeLayoutInfoLoadCon
case FixupSignatureKind.NotYetSupported:
case FixupSignatureKind.ThreadStaticIndex:
+ case FixupSignatureKind.GenericStaticConstrainedMethod:
TypeLoaderLogger.WriteLine("Valid dictionary entry, but not yet supported by the TypeLoader!");
throw new TypeBuilder.MissingTemplateException();
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 ab1bbfba737a46..a0c7bc7324639c 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
@@ -1152,8 +1152,10 @@ private void FinishInterfaces(TypeDesc type, TypeBuilderState state)
}
}
- private unsafe void FinishTypeDictionary(TypeDesc type, TypeBuilderState state)
+ private unsafe void FinishTypeDictionary(TypeDesc type)
{
+ TypeBuilderState state = type.GetTypeBuilderState();
+
if (state.Dictionary != null)
{
// First, update the dictionary slot in the type's vtable to point to the created dictionary when applicable
@@ -1348,8 +1350,6 @@ private void FinishRuntimeType(TypeDesc type)
FinishInterfaces(type, state);
- FinishTypeDictionary(type, state);
-
FinishClassConstructor(type, state);
#if FEATURE_UNIVERSAL_GENERICS
@@ -1371,8 +1371,6 @@ private void FinishRuntimeType(TypeDesc type)
if (typeAsSzArrayType.IsSzArray && !typeAsSzArrayType.ElementType.IsPointer)
{
- FinishTypeDictionary(type, state);
-
#if FEATURE_UNIVERSAL_GENERICS
// For types that were allocated from universal canonical templates, patch their vtables with
// pointers to calling convention conversion thunks
@@ -1522,6 +1520,11 @@ private void FinishTypeAndMethodBuilding()
FinishRuntimeType(_typesThatNeedTypeHandles[i]);
}
+ for (int i = 0; i < _typesThatNeedTypeHandles.Count; i++)
+ {
+ FinishTypeDictionary(_typesThatNeedTypeHandles[i]);
+ }
+
for (int i = 0; i < _methodsThatNeedDictionaries.Count; i++)
{
FinishMethodDictionary(_methodsThatNeedDictionaries[i]);
diff --git a/src/coreclr/tools/Common/Compiler/MethodExtensions.cs b/src/coreclr/tools/Common/Compiler/MethodExtensions.cs
index af23ea53fb8110..b8a92a276f859f 100644
--- a/src/coreclr/tools/Common/Compiler/MethodExtensions.cs
+++ b/src/coreclr/tools/Common/Compiler/MethodExtensions.cs
@@ -87,11 +87,22 @@ public static string GetUnmanagedCallersOnlyExportName(this EcmaMethod This)
///
public static bool CanMethodBeInSealedVTable(this MethodDesc method)
{
+ bool isInterfaceMethod = method.OwningType.IsInterface;
+
// Methods on interfaces never go into sealed vtable
// We would hit this code path for default implementations of interface methods (they are newslot+final).
// Inteface types don't get physical slots, but they have logical slot numbers and that logic shouldn't
// attempt to place final+newslot methods differently.
- return method.IsFinal && method.IsNewSlot && !method.OwningType.IsInterface;
+ if (method.IsFinal && method.IsNewSlot && !isInterfaceMethod)
+ return true;
+
+ // Implementations of static virtual method also go into the sealed vtable.
+ // Again, we don't let that happen for interface methods because the slot numbers are only logical,
+ // not physical.
+ if (method.Signature.IsStatic && !isInterfaceMethod)
+ return true;
+
+ return false;
}
public static bool NotCallableWithoutOwningEEType(this MethodDesc method)
diff --git a/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs b/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs
index 785c7a97ca8350..5fd89c6d66b8e8 100644
--- a/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs
+++ b/src/coreclr/tools/Common/Internal/NativeFormat/NativeFormat.cs
@@ -100,6 +100,8 @@ enum FixupSignatureKind : uint
NonGenericDirectConstrainedMethod = 0x18,
PointerToOtherSlot = 0x19,
IntValue = 0x20,
+ NonGenericStaticConstrainedMethod = 0x21,
+ GenericStaticConstrainedMethod = 0x22,
NotYetSupported = 0xee,
}
diff --git a/src/coreclr/tools/Common/Internal/Runtime/RuntimeConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/RuntimeConstants.cs
index fc05a42e6435eb..f01bd3f30fe0b0 100644
--- a/src/coreclr/tools/Common/Internal/Runtime/RuntimeConstants.cs
+++ b/src/coreclr/tools/Common/Internal/Runtime/RuntimeConstants.cs
@@ -64,6 +64,13 @@ internal static class SpecialGVMInterfaceEntry
public const uint Reabstraction = 0xFFFFFFFE;
}
+ internal static class StaticVirtualMethodContextSource
+ {
+ public const ushort None = 0;
+ public const ushort ContextFromThisClass = 1;
+ public const ushort ContextFromFirstInterface = 2;
+ }
+
internal enum RuntimeHelperKind
{
AllocateObject,
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs
index 54b6424032c5b2..07e9d4b972f887 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs
@@ -371,14 +371,25 @@ public sealed override IEnumerable GetConditionalSt
if (interfaceMethod.HasInstantiation)
continue;
- // Static virtual methods are resolved at compile time
- if (interfaceMethod.Signature.IsStatic)
- continue;
+ bool isStaticInterfaceMethod = interfaceMethod.Signature.IsStatic;
- MethodDesc implMethod = defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
+ MethodDesc implMethod = isStaticInterfaceMethod ?
+ defType.ResolveInterfaceMethodToStaticVirtualMethodOnType(interfaceMethod) :
+ defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
if (implMethod != null)
{
- result.Add(new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method"));
+ if (isStaticInterfaceMethod)
+ {
+ Debug.Assert(!implMethod.IsVirtual);
+
+ // If the interface method is used virtually, the implementation body is used
+ result.Add(new CombinedDependencyListEntry(factory.CanonicalEntrypoint(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method"));
+ }
+ else
+ {
+ // If the interface method is used virtually, the slot is used virtually
+ result.Add(new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.VirtualMethodUse(interfaceMethod), "Interface method"));
+ }
// If any of the implemented interfaces have variance, calls against compatible interface methods
// could result in interface methods of this type being used (e.g. IEnumerable