Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change some delegate FCalls to managed #70000

Merged
merged 8 commits into from
May 31, 2022
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
27 changes: 22 additions & 5 deletions src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,28 @@ internal static Delegate CreateDelegateNoSecurityCheck(Type type, object? target
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern MulticastDelegate InternalAllocLike(Delegate d);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool InternalEqualTypes(object a, object b);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe bool InternalEqualTypes(object a, object b)
{
if (a.GetType() == b.GetType())
return true;

MethodTable* pMTa = RuntimeHelpers.GetMethodTable(a);
MethodTable* pMTb = RuntimeHelpers.GetMethodTable(b);

bool ret;

// only use QCall to check the type equivalence scenario
if (pMTa->HasTypeEquivalence && pMTb->HasTypeEquivalence)
ret = RuntimeHelpers.AreTypesEquivalent(pMTa, pMTb);
else
ret = false;

GC.KeepAlive(a);
GC.KeepAlive(b);

return ret;
}

// Used by the ctor. Do not call directly.
// The name of this function will appear in managed stacktraces as delegate constructor.
Expand Down Expand Up @@ -441,9 +461,6 @@ internal static Delegate CreateDelegateNoSecurityCheck(Type type, object? target
{
return (_methodPtrAux == IntPtr.Zero) ? _target : null;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool CompareUnmanagedFunctionPtrs(Delegate d1, Delegate d2);
}

// These flags effect the way BindToMethodInfo and BindToMethodName are allowed to bind a delegate to a target method. Their
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj)
if (!d.IsUnmanagedFunctionPtr())
return false;

return CompareUnmanagedFunctionPtrs(this, d);
return _methodPtr == d._methodPtr
&& _methodPtrAux == d._methodPtrAux;
}

// now we know 'this' is not a special one, so we can work out what the other is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ internal static unsafe bool ObjectHasComponentSize(object obj)
return (MethodTable *)Unsafe.Add(ref Unsafe.As<byte, IntPtr>(ref obj.GetRawData()), -1);
}


[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MethodTable_AreTypesEquivalent")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static unsafe partial bool AreTypesEquivalent(MethodTable* pMTa, MethodTable* pMTb);

/// <summary>
/// Allocate memory that is associated with the <paramref name="type"/> and
/// will be freed if and when the <see cref="System.Type"/> is unloaded.
Expand Down
52 changes: 0 additions & 52 deletions src/coreclr/vm/comdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1488,34 +1488,6 @@ MethodDesc* COMDelegate::GetILStubMethodDesc(EEImplMethodDesc* pDelegateMD, DWOR
return NDirect::CreateCLRToNativeILStub(&sigInfo, dwStubFlags, pDelegateMD);
}



FCIMPL2(FC_BOOL_RET, COMDelegate::CompareUnmanagedFunctionPtrs, Object *refDelegate1UNSAFE, Object *refDelegate2UNSAFE)
{
CONTRACTL
{
FCALL_CHECK;
PRECONDITION(refDelegate1UNSAFE != NULL);
PRECONDITION(refDelegate2UNSAFE != NULL);
}
CONTRACTL_END;

DELEGATEREF refD1 = (DELEGATEREF) ObjectToOBJECTREF(refDelegate1UNSAFE);
DELEGATEREF refD2 = (DELEGATEREF) ObjectToOBJECTREF(refDelegate2UNSAFE);
BOOL ret = FALSE;

// Make sure this is an unmanaged function pointer wrapped in a delegate.
CONSISTENCY_CHECK(DELEGATE_MARKER_UNMANAGEDFPTR == refD1->GetInvocationCount());
CONSISTENCY_CHECK(DELEGATE_MARKER_UNMANAGEDFPTR == refD2->GetInvocationCount());

ret = (refD1->GetMethodPtr() == refD2->GetMethodPtr() &&
refD1->GetMethodPtrAux() == refD2->GetMethodPtrAux());

FC_RETURN_BOOL(ret);
}
FCIMPLEND


void COMDelegate::RemoveEntryFromFPtrHash(UPTR key)
{
WRAPPER_NO_CONTRACT;
Expand Down Expand Up @@ -2029,30 +2001,6 @@ FCIMPL1(Object*, COMDelegate::InternalAllocLike, Object* pThis)
}
FCIMPLEND

FCIMPL2(FC_BOOL_RET, COMDelegate::InternalEqualTypes, Object* pThis, Object *pThat)
{
FCALL_CONTRACT;

MethodTable *pThisMT = pThis->GetMethodTable();
MethodTable *pThatMT = pThat->GetMethodTable();

_ASSERTE(pThisMT != NULL && pThisMT->IsDelegate());
_ASSERTE(pThatMT != NULL);

BOOL bResult = (pThisMT == pThatMT);

if (!bResult)
{
HELPER_METHOD_FRAME_BEGIN_RET_0();
bResult = pThisMT->IsEquivalentTo(pThatMT);
HELPER_METHOD_FRAME_END();
}

FC_RETURN_BOOL(bResult);
}
FCIMPLEND


void COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD)
{
CONTRACTL
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/vm/comdelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class COMDelegate

static FCDECL1(Object*, InternalAlloc, ReflectClassBaseObject* target);
static FCDECL1(Object*, InternalAllocLike, Object* pThis);
static FCDECL2(FC_BOOL_RET, InternalEqualTypes, Object* pThis, Object *pThat);

static FCDECL3(PCODE, AdjustTarget, Object* refThis, Object* target, PCODE method);
static FCDECL2(PCODE, GetCallStub, Object* refThis, PCODE method);
Expand Down Expand Up @@ -90,9 +89,6 @@ class COMDelegate
static ComPlusCallInfo * PopulateComPlusCallInfo(MethodTable * pDelMT);
#endif // FEATURE_COMINTEROP

// Checks whether two delegates wrapping function pointers have the same unmanaged target
static FCDECL2(FC_BOOL_RET, CompareUnmanagedFunctionPtrs, Object *refDelegate1UNSAFE, Object *refDelegate2UNSAFE);

static PCODE GetStubForILStub(EEImplMethodDesc* pDelegateMD, MethodDesc** ppStubMD, DWORD dwStubFlags);
static MethodDesc* GetILStubMethodDesc(EEImplMethodDesc* pDelegateMD, DWORD dwStubFlags);

Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/vm/comutilnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2036,6 +2036,21 @@ FCIMPL1(UINT32, MethodTableNative::GetNumInstanceFieldBytes, MethodTable* mt)
}
FCIMPLEND

extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb)
{
QCALL_CONTRACT;

BOOL bResult = FALSE;

BEGIN_QCALL;

bResult = mta->IsEquivalentTo(mtb);

END_QCALL;

return bResult;
}

static MethodTable * g_pStreamMT;
static WORD g_slotBeginRead, g_slotEndRead;
static WORD g_slotBeginWrite, g_slotEndWrite;
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/comutilnative.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ class MethodTableNative {
static FCDECL1(UINT32, GetNumInstanceFieldBytes, MethodTable* mt);
};

extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb);

class StreamNative {
public:
static FCDECL1(FC_BOOL_RET, HasOverriddenBeginEndRead, Object *stream);
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,10 @@ FCFuncStart(gDelegateFuncs)
FCFuncElement("GetInvokeMethod", COMDelegate::GetInvokeMethod)
FCFuncElement("InternalAlloc", COMDelegate::InternalAlloc)
FCFuncElement("InternalAllocLike", COMDelegate::InternalAllocLike)
FCFuncElement("InternalEqualTypes", COMDelegate::InternalEqualTypes)
FCFuncElement("InternalEqualMethodHandles", COMDelegate::InternalEqualMethodHandles)
FCFuncElement("FindMethodHandle", COMDelegate::FindMethodHandle)
FCFuncElement("AdjustTarget", COMDelegate::AdjustTarget)
FCFuncElement("GetCallStub", COMDelegate::GetCallStub)
FCFuncElement("CompareUnmanagedFunctionPtrs", COMDelegate::CompareUnmanagedFunctionPtrs)

// The FCall mechanism knows how to wire multiple different constructor calls into a
// single entrypoint, without the following entry. But we need this entry to satisfy
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ static const Entry s_QCall[] =
DllImportEntry(RuntimeTypeHandle_CreateInstanceForAnotherGenericParameter)
DllImportEntry(QCall_GetGCHandleForTypeHandle)
DllImportEntry(QCall_FreeGCHandleForTypeHandle)
DllImportEntry(MethodTable_AreTypesEquivalent)
DllImportEntry(RuntimeTypeHandle_MakePointer)
DllImportEntry(RuntimeTypeHandle_MakeByRef)
DllImportEntry(RuntimeTypeHandle_MakeSZArray)
Expand Down