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 @@ -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
Expand Down Expand Up @@ -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);
}
}

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

Expand All @@ -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)
Expand Down Expand Up @@ -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;

Expand All @@ -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);
}
}

Expand All @@ -127,6 +129,7 @@ private static bool FindImplSlotInSimpleMap(MethodTable* pTgtType,
MethodTable* pItfType,
uint itfSlotNumber,
ushort* pImplSlotNumber,
MethodTable** ppGenericContext,
bool actuallyCheckVariance,
bool checkDefaultImplementations)
{
Expand Down Expand Up @@ -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)
{
Expand All @@ -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))
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading