Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ enum CorInfoHelpFunc
CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, // Transition to preemptive mode in reverse P/Invoke epilog, frame is the first argument
CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS, // Transition to preemptive mode and track transitions in reverse P/Invoke prolog.

CORINFO_HELP_GVMLOOKUP_FOR_SLOT, // Resolve a generic virtual method target from this pointer and runtime method handle
CORINFO_HELP_GVMLOOKUP_FOR_SLOT, // Resolve a generic virtual method target from this pointer and dispatch cell
CORINFO_HELP_INTERFACEDISPATCH_FOR_SLOT, // Dispatch a non-generic interface method from this pointer and dispatch cell
CORINFO_HELP_INTERFACELOOKUP_FOR_SLOT, // Resolve a non-generic interface method from this pointer and dispatch cell

Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2723,10 +2723,10 @@ GenTree* Compiler::impImportLdvirtftn(GenTree* thisPtr,
// NativeAOT generic virtual method
if ((pCallInfo->sig.sigInst.methInstCount != 0) && IsTargetAbi(CORINFO_NATIVEAOT_ABI))
{
GenTree* runtimeMethodHandle =
impLookupToTree(&pCallInfo->codePointerLookup, GTF_ICON_METHOD_HDL, pCallInfo->hMethod);
GenTree* dispatchCell =
impLookupToTree(&pCallInfo->codePointerLookup, GTF_ICON_FTN_ADDR, pCallInfo->hMethod);
call = gtNewVirtualFunctionLookupHelperCallNode(CORINFO_HELP_GVMLOOKUP_FOR_SLOT, TYP_I_IMPL, thisPtr,
runtimeMethodHandle);
dispatchCell);
}

// Wasm R2R cannot use the CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR fast path because it
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/nativeaot/Bootstrap/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void* PalGetModuleHandleFromPointer(void* pointer);
MANAGED_RUNTIME_EXPORT(GetRuntimeException)
MANAGED_RUNTIME_EXPORT(RuntimeFailFast)
MANAGED_RUNTIME_EXPORT(AppendExceptionStackFrame)
MANAGED_RUNTIME_EXPORT(ResolveDispatch)
MANAGED_RUNTIME_EXPORT(GetSystemArrayEEType)
MANAGED_RUNTIME_EXPORT(OnFirstChanceException)
MANAGED_RUNTIME_EXPORT(OnUnhandledException)
Expand All @@ -151,7 +152,7 @@ static const pfn c_classlibFunctions[] = {
&MANAGED_RUNTIME_EXPORT_NAME(RuntimeFailFast),
(pfn)&ThreadEntryPoint,
&MANAGED_RUNTIME_EXPORT_NAME(AppendExceptionStackFrame),
nullptr, // &CheckStaticClassConstruction,
&MANAGED_RUNTIME_EXPORT_NAME(ResolveDispatch),
&MANAGED_RUNTIME_EXPORT_NAME(GetSystemArrayEEType),
&MANAGED_RUNTIME_EXPORT_NAME(OnFirstChanceException),
&MANAGED_RUNTIME_EXPORT_NAME(OnUnhandledException),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// 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.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;

using Internal.Runtime;
using Internal.Runtime.CompilerHelpers;

namespace System.Runtime
{
Expand Down Expand Up @@ -65,31 +62,20 @@ public override bool Equals(object obj)
}
#endif

[StructLayout(LayoutKind.Sequential)]
private struct DispatchCell
{
public nint MethodTable;
public nint Code;
}

[RuntimeExport("RhpCidResolve")]
private static unsafe IntPtr RhpCidResolve(IntPtr callerTransitionBlockParam, IntPtr pCell)
private static IntPtr RhpCidResolve(IntPtr callerTransitionBlockParam, IntPtr pCell)
{
IntPtr locationOfThisPointer = callerTransitionBlockParam + TransitionBlock.GetThisOffset();
object pObject = *(object*)locationOfThisPointer;
IntPtr dispatchResolveTarget = RhpCidResolve_Worker(pObject, pCell);
return dispatchResolveTarget;
}

[RuntimeExport("RhpCidResolve_Worker")]
private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
{
DispatchCellInfo cellInfo;
// We're passing the type manager of the object, but we need a type manager associated with
// the dispatch cell region. This is fine for now since we don't worry about multifile scenarios much.
// We'll need an API to find the right containing section in multimodule.
GetDispatchCellInfo(pObject.GetMethodTable()->TypeManager, pCell, out cellInfo);

IntPtr pTargetCode = RhResolveDispatchWorker(pObject, (void*)pCell, ref cellInfo);
var resolver = (delegate*<object, nint, nint>)InternalCalls.RhpGetClasslibFunctionFromEEType(pObject.GetMethodTable(), ClassLibFunctionId.ResolveDispatch);
IntPtr pTargetCode = resolver(pObject, pCell);
if (pTargetCode != IntPtr.Zero)
{
return UpdateDispatchCellCache(pCell, pTargetCode, pObject.GetMethodTable());
Expand All @@ -100,52 +86,6 @@ private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
return IntPtr.Zero;
}

private static void GetDispatchCellInfo(TypeManagerHandle typeManager, IntPtr pCell, out DispatchCellInfo info)
{
IntPtr dispatchCellRegion = RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.InterfaceDispatchCellRegion, out int length);
if (pCell >= dispatchCellRegion && pCell < dispatchCellRegion + length)
{
// Static dispatch cell: find the info in the associated info region
nint cellIndex = (pCell - dispatchCellRegion) / sizeof(DispatchCell);

IntPtr dispatchCellInfoRegion = RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.InterfaceDispatchCellInfoRegion, out _);
if (MethodTable.SupportsRelativePointers)
{
var dispatchCellInfo = (int*)dispatchCellInfoRegion;
info = new DispatchCellInfo
{
CellType = DispatchCellType.InterfaceAndSlot,
InterfaceType = (MethodTable*)ReadRelPtr32(dispatchCellInfo + (cellIndex * 2)),
InterfaceSlot = (ushort)*(dispatchCellInfo + (cellIndex * 2 + 1))
};

static void* ReadRelPtr32(void* address)
=> (byte*)address + *(int*)address;
}
else
{
var dispatchCellInfo = (nint*)dispatchCellInfoRegion;
info = new DispatchCellInfo
{
CellType = DispatchCellType.InterfaceAndSlot,
InterfaceType = (MethodTable*)(*(dispatchCellInfo + (cellIndex * 2))),
InterfaceSlot = (ushort)*(dispatchCellInfo + (cellIndex * 2 + 1))
};
}

}
else
{
// Dynamically allocated dispatch cell: info is next to the dispatch cell
info = new DispatchCellInfo
{
CellType = DispatchCellType.InterfaceAndSlot,
InterfaceType = *(MethodTable**)(pCell + sizeof(DispatchCell)),
InterfaceSlot = (ushort)*(nint*)(pCell + sizeof(DispatchCell) + sizeof(MethodTable*))
};
}
}

private static IntPtr UpdateDispatchCellCache(IntPtr pCell, IntPtr pTargetCode, MethodTable* pInstanceType)
{
DispatchCell* pDispatchCell = (DispatchCell*)pCell;
Expand Down Expand Up @@ -213,12 +153,7 @@ private static IntPtr RhpResolveInterfaceMethod(object pObject, IntPtr pCell)
[RuntimeExport("RhResolveDispatch")]
private static IntPtr RhResolveDispatch(object pObject, MethodTable* interfaceType, ushort slot)
{
DispatchCellInfo cellInfo = default;
cellInfo.CellType = DispatchCellType.InterfaceAndSlot;
cellInfo.InterfaceType = interfaceType;
cellInfo.InterfaceSlot = slot;

return RhResolveDispatchWorker(pObject, null, ref cellInfo);
return RhResolveDispatchWorker(pObject, interfaceType, slot);
}

[RuntimeExport("RhResolveDispatchOnType")]
Expand Down Expand Up @@ -266,52 +201,23 @@ private static IntPtr RhResolveDynamicInterfaceCastableDispatchOnType(MethodTabl
[AnalysisCharacteristic]
private static extern bool DynamicInterfaceCastablePresent();

private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void* cell, ref DispatchCellInfo cellInfo)
internal static IntPtr RhResolveDispatchWorker(object pObject, MethodTable* pItfType, ushort itfSlotNumber)
{
// Type of object we're dispatching on.
MethodTable* pInstanceType = pObject.GetMethodTable();

if (cellInfo.CellType == DispatchCellType.InterfaceAndSlot)
{
IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pInstanceType,
cellInfo.InterfaceType,
cellInfo.InterfaceSlot,
flags: default,
ppGenericContext: null);
if (DynamicInterfaceCastablePresent() && pTargetCode == IntPtr.Zero && pInstanceType->IsIDynamicInterfaceCastable)
{
// Dispatch not resolved through normal dispatch map, try using the IDynamicInterfaceCastable
// This will either give us the appropriate result, or throw.
pTargetCode = IDynamicInterfaceCastable.GetDynamicInterfaceImplementation((IDynamicInterfaceCastable)pObject, cellInfo.InterfaceType, cellInfo.InterfaceSlot);
Diagnostics.Debug.Assert(pTargetCode != IntPtr.Zero);
}
return pTargetCode;
}
else if (cellInfo.CellType == DispatchCellType.VTableOffset)
{
// Dereference VTable
return *(IntPtr*)(((byte*)pInstanceType) + cellInfo.VTableOffset);
}
else
{
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING_AND_SUPPORTS_TOKEN_BASED_DISPATCH_CELLS
// Attempt to convert dispatch cell to non-metadata form if we haven't acquired a cache for this cell yet
if (cellInfo.HasCache == 0)
{
cellInfo = InternalTypeLoaderCalls.ConvertMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), cellInfo);
if (cellInfo.CellType != DispatchCellType.MetadataToken)
{
return RhResolveDispatchWorker(pObject, cell, ref cellInfo);
}
}

// If that failed, go down the metadata resolution path
return InternalTypeLoaderCalls.ResolveMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), (int)cellInfo.MetadataToken, new IntPtr(pInstanceType));
#else
EH.FallbackFailFast(RhFailFastReason.InternalError, null);
return IntPtr.Zero;
#endif
IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pInstanceType,
pItfType,
itfSlotNumber,
flags: default,
ppGenericContext: null);
if (DynamicInterfaceCastablePresent() && pTargetCode == IntPtr.Zero && pInstanceType->IsIDynamicInterfaceCastable)
{
// Dispatch not resolved through normal dispatch map, try using the IDynamicInterfaceCastable
// This will either give us the appropriate result, or throw.
pTargetCode = IDynamicInterfaceCastable.GetDynamicInterfaceImplementation((IDynamicInterfaceCastable)pObject, pItfType, itfSlotNumber);
Diagnostics.Debug.Assert(pTargetCode != IntPtr.Zero);
}
return pTargetCode;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,6 @@

namespace System.Runtime
{
internal enum DispatchCellType
{
InterfaceAndSlot = 0x0,
MetadataToken = 0x1,
VTableOffset = 0x2,
}

internal unsafe struct DispatchCellInfo
{
public DispatchCellType CellType;
public MethodTable* InterfaceType;
public ushort InterfaceSlot;
public byte HasCache;
public uint MetadataToken;
public uint VTableOffset;
}

// Constants used with RhpGetClasslibFunction, to indicate which classlib function
// we are interested in.
// Note: make sure you change the def in ICodeManager.h if you change this!
Expand All @@ -40,7 +23,7 @@ internal enum ClassLibFunctionId
FailFast = 1,
ThreadEntryPoint = 2,
AppendExceptionStackFrame = 3,
// unused = 4,
ResolveDispatch = 4,
GetSystemArrayEEType = 5,
OnFirstChance = 6,
OnUnhandledException = 7,
Expand Down
34 changes: 31 additions & 3 deletions src/coreclr/nativeaot/Runtime/EHHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,12 @@ static bool InWriteBarrierHelper(uintptr_t faultingIP)
}

EXTERN_C CODE_LOCATION RhpInterfaceDispatch;
#if !defined(TARGET_ARM)
EXTERN_C CODE_LOCATION RhpDispatchResolve;
#endif
#if defined(TARGET_ARM)
EXTERN_C CODE_LOCATION RhpInterfaceDispatchAVLocation;
EXTERN_C CODE_LOCATION RhpDispatchResolveAVLocation;
#endif
#if defined(TARGET_WINDOWS) && (defined(TARGET_AMD64) || defined(TARGET_ARM64))
EXTERN_C CODE_LOCATION RhpInterfaceDispatchGuarded;
Expand Down Expand Up @@ -307,6 +311,26 @@ static bool InInterfaceDispatchHelper(uintptr_t faultingIP)
return false;
}

static bool InInterfaceResolveHelper(uintptr_t faultingIP)
{
#ifndef FEATURE_PORTABLE_HELPERS
#if defined(TARGET_ARM)
return faultingIP == (uintptr_t)&RhpDispatchResolveAVLocation;
#else
uintptr_t interfaceResolveAVLocation = (uintptr_t)&RhpDispatchResolve;
#if defined(HOST_AMD64) || defined(HOST_X86)
// Verify that the runtime is not linked with incremental linking enabled. Incremental linking
// wraps every method symbol with a jump stub that breaks the following check.
ASSERT(*(uint8_t*)interfaceResolveAVLocation != 0xE9); // jmp XXXXXXXX
#endif

return interfaceResolveAVLocation == faultingIP;
#endif
#else
return false;
#endif // FEATURE_PORTABLE_HELPERS
}

static uintptr_t UnwindSimpleHelperToCaller(
#ifdef TARGET_UNIX
PAL_LIMITED_CONTEXT * pContext
Expand All @@ -317,7 +341,9 @@ static uintptr_t UnwindSimpleHelperToCaller(
{
#if defined(_DEBUG)
uintptr_t faultingIP = pContext->GetIp();
ASSERT(InWriteBarrierHelper(faultingIP) || InInterfaceDispatchHelper(faultingIP));
ASSERT(InWriteBarrierHelper(faultingIP) ||
InInterfaceDispatchHelper(faultingIP) ||
InInterfaceResolveHelper(faultingIP));
#endif
#if defined(HOST_AMD64) || defined(HOST_X86)
// simulate a ret instruction
Expand Down Expand Up @@ -378,8 +404,9 @@ int32_t RhpHardwareExceptionHandler(uintptr_t faultCode, uintptr_t faultAddress,
// Could still be an AV in one of our assembly helpers that we know how to handle.
bool inWriteBarrierHelper = InWriteBarrierHelper(faultingIP);
bool inInterfaceDispatchHelper = InInterfaceDispatchHelper(faultingIP);
bool inInterfaceResolveHelper = InInterfaceResolveHelper(faultingIP);

if (inWriteBarrierHelper || inInterfaceDispatchHelper)
if (inWriteBarrierHelper || inInterfaceDispatchHelper || inInterfaceResolveHelper)
{
if (faultAddress < NULL_AREA_SIZE)
{
Expand Down Expand Up @@ -516,8 +543,9 @@ LONG WINAPI RhpVectoredExceptionHandler(PEXCEPTION_POINTERS pExPtrs)
// Could still be an AV in one of our assembly helpers that we know how to handle.
bool inWriteBarrierHelper = InWriteBarrierHelper(faultingIP);
bool inInterfaceDispatchHelper = InInterfaceDispatchHelper(faultingIP);
bool inInterfaceResolveHelper = InInterfaceResolveHelper(faultingIP);

if (inWriteBarrierHelper || inInterfaceDispatchHelper)
if (inWriteBarrierHelper || inInterfaceDispatchHelper || inInterfaceResolveHelper)
{
if (pExPtrs->ExceptionRecord->ExceptionInformation[1] < NULL_AREA_SIZE)
{
Expand Down
Loading
Loading