Skip to content

Commit

Permalink
Add support for creating delegates to static virtual methods (dotnet#…
Browse files Browse the repository at this point in the history
…66936)

Requires a JitInterface change because we need to be able to pass information about constraints to `getReadyToRunDelegateCtorHelper`
  • Loading branch information
MichalStrehovsky authored Mar 29, 2022
1 parent 71ad9f5 commit 370f160
Show file tree
Hide file tree
Showing 27 changed files with 325 additions and 203 deletions.
1 change: 1 addition & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -2441,6 +2441,7 @@ class ICorStaticInfo

virtual void getReadyToRunDelegateCtorHelper(
CORINFO_RESOLVED_TOKEN * pTargetMethod,
mdToken targetConstraint,
CORINFO_CLASS_HANDLE delegateType,
CORINFO_LOOKUP * pLookup
) = 0;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/icorjitinfoimpl_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ bool getReadyToRunHelper(

void getReadyToRunDelegateCtorHelper(
CORINFO_RESOLVED_TOKEN* pTargetMethod,
mdToken targetConstraint,
CORINFO_CLASS_HANDLE delegateType,
CORINFO_LOOKUP* pLookup) override;

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED

constexpr GUID JITEEVersionIdentifier = { /* bcc99ca6-5291-4cc0-a5d9-2758456053f3 */
0xbcc99ca6,
0x5291,
0x4cc0,
{ 0xa5, 0xd9, 0x27, 0x58, 0x45, 0x60, 0x53, 0xf3 }
constexpr GUID JITEEVersionIdentifier = { /* 398270b8-d474-428f-8113-3834281853cf */
0x398270b8,
0xd474,
0x428f,
{0x81, 0x13, 0x38, 0x34, 0x28, 0x18, 0x53, 0xcf}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/ICorJitInfo_API_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,11 +656,12 @@ bool WrapICorJitInfo::getReadyToRunHelper(

void WrapICorJitInfo::getReadyToRunDelegateCtorHelper(
CORINFO_RESOLVED_TOKEN* pTargetMethod,
mdToken targetConstraint,
CORINFO_CLASS_HANDLE delegateType,
CORINFO_LOOKUP* pLookup)
{
API_ENTER(getReadyToRunDelegateCtorHelper);
wrapHnd->getReadyToRunDelegateCtorHelper(pTargetMethod, delegateType, pLookup);
wrapHnd->getReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, pLookup);
API_LEAVE(getReadyToRunDelegateCtorHelper);
}

Expand Down
71 changes: 29 additions & 42 deletions src/coreclr/jit/_typeinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ inline ti_types JITtype2tiType(CorInfoType type)
return g_ti_types_map[type];
};

/*****************************************************************************
* Captures information about a method pointer
*
* m_token is the CORINFO_RESOLVED_TOKEN from the IL, potentially with a more
* precise method handle from getCallInfo
* m_tokenConstraint is the constraint if this was a constrained ldftn.
*
*/
class methodPointerInfo
{
public:
CORINFO_RESOLVED_TOKEN m_token;
mdToken m_tokenConstraint;
};

/*****************************************************************************
* Declares the typeInfo class, which represents the type of an entity on the
* stack, in a local variable or an argument.
Expand Down Expand Up @@ -221,9 +236,6 @@ inline ti_types JITtype2tiType(CorInfoType type)
// since conversions between them are not verifiable.
#define TI_FLAG_NATIVE_INT 0x00000200

// This item contains resolved token. It is used for ctor delegate optimization.
#define TI_FLAG_TOKEN 0x00000400

// This item contains the 'this' pointer (used for tracking)

#define TI_FLAG_THIS_PTR 0x00001000
Expand Down Expand Up @@ -270,7 +282,7 @@ inline ti_types JITtype2tiType(CorInfoType type)
* - A type (ref, array, value type) (m_cls describes the type)
* - An array (m_cls describes the array type)
* - A byref (byref flag set, otherwise the same as the above),
* - A Function Pointer (m_method)
* - A Function Pointer (m_methodPointerInfo)
* - A byref local variable (byref and byref local flags set), can be
* uninitialized
*
Expand All @@ -291,7 +303,7 @@ class typeInfo
unsigned byref : 1; // used
unsigned byref_readonly : 1; // used
unsigned nativeInt : 1; // used
unsigned token : 1; // used
unsigned : 1; // unused
unsigned : 1; // unused
unsigned thisPtr : 1; // used
unsigned thisPermHome : 1; // used
Expand All @@ -303,10 +315,8 @@ class typeInfo

union {
CORINFO_CLASS_HANDLE m_cls;
// Valid only for type TI_METHOD without IsToken
CORINFO_METHOD_HANDLE m_method;
// Valid only for TI_TOKEN with IsToken
CORINFO_RESOLVED_TOKEN* m_token;
// Valid only for type TI_METHOD
methodPointerInfo* m_methodPointerInfo;
};

template <typename T>
Expand Down Expand Up @@ -362,21 +372,13 @@ class typeInfo
m_cls = cls;
}

typeInfo(CORINFO_METHOD_HANDLE method)
{
assert(method != nullptr && !isInvalidHandle(method));
m_flags = TI_METHOD;
m_method = method;
}

typeInfo(CORINFO_RESOLVED_TOKEN* token)
typeInfo(methodPointerInfo* methodPointerInfo)
{
assert(token != nullptr);
assert(token->hMethod != nullptr);
assert(!isInvalidHandle(token->hMethod));
m_flags = TI_METHOD;
SetIsToken();
m_token = token;
assert(methodPointerInfo != nullptr);
assert(methodPointerInfo->m_token.hMethod != nullptr);
assert(!isInvalidHandle(methodPointerInfo->m_token.hMethod));
m_flags = TI_METHOD;
m_methodPointerInfo = methodPointerInfo;
}

#ifdef DEBUG
Expand Down Expand Up @@ -458,12 +460,6 @@ class typeInfo
// Operations
/////////////////////////////////////////////////////////////////////////

void SetIsToken()
{
m_flags |= TI_FLAG_TOKEN;
assert(m_bits.token);
}

void SetIsThisPtr()
{
m_flags |= TI_FLAG_THIS_PTR;
Expand Down Expand Up @@ -573,17 +569,13 @@ class typeInfo
CORINFO_METHOD_HANDLE GetMethod() const
{
assert(GetType() == TI_METHOD);
if (IsToken())
{
return m_token->hMethod;
}
return m_method;
return m_methodPointerInfo->m_token.hMethod;
}

CORINFO_RESOLVED_TOKEN* GetToken() const
methodPointerInfo* GetMethodPointerInfo() const
{
assert(IsToken());
return m_token;
assert(GetType() == TI_METHOD);
return m_methodPointerInfo;
}

// Get this item's type
Expand Down Expand Up @@ -750,11 +742,6 @@ class typeInfo
return (m_flags & TI_FLAG_UNINIT_OBJREF);
}

bool IsToken() const
{
return IsMethod() && ((m_flags & TI_FLAG_TOKEN) != 0);
}

private:
// used to make functions that return typeinfo efficient.
typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls)
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4988,7 +4988,7 @@ class Compiler
bool impIsClassExact(CORINFO_CLASS_HANDLE classHnd);
bool impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array);

CORINFO_RESOLVED_TOKEN* impAllocateToken(const CORINFO_RESOLVED_TOKEN& token);
methodPointerInfo* impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained);

/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down Expand Up @@ -6487,7 +6487,7 @@ class Compiler
#endif
GenTree* fgOptimizeDelegateConstructor(GenTreeCall* call,
CORINFO_CONTEXT_HANDLE* ExactContextHnd,
CORINFO_RESOLVED_TOKEN* ldftnToken);
methodPointerInfo* ldftnToken);
GenTree* fgMorphLeaf(GenTree* tree);
void fgAssignSetVarDef(GenTree* tree);
GenTree* fgMorphOneAsgBlockOp(GenTree* tree);
Expand Down
16 changes: 9 additions & 7 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ bool Compiler::fgAddrCouldBeNull(GenTree* addr)

GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
CORINFO_CONTEXT_HANDLE* ExactContextHnd,
CORINFO_RESOLVED_TOKEN* ldftnToken)
methodPointerInfo* ldftnToken)
{
JITDUMP("\nfgOptimizeDelegateConstructor: ");
noway_assert(call->gtCallType == CT_USER_FUNC);
Expand Down Expand Up @@ -1115,14 +1115,14 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
// via the above pattern match, and more...
if (ldftnToken != nullptr)
{
assert(ldftnToken->hMethod != nullptr);
assert(ldftnToken->m_token.hMethod != nullptr);

if (targetMethodHnd != nullptr)
{
assert(targetMethodHnd == ldftnToken->hMethod);
assert(targetMethodHnd == ldftnToken->m_token.hMethod);
}

targetMethodHnd = ldftnToken->hMethod;
targetMethodHnd = ldftnToken->m_token.hMethod;
}
else
{
Expand All @@ -1143,7 +1143,8 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
GenTreeCall::Use* helperArgs = nullptr;
CORINFO_LOOKUP pLookup;
CORINFO_CONST_LOOKUP entryPoint;
info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &pLookup);
info.compCompHnd->getReadyToRunDelegateCtorHelper(&ldftnToken->m_token, ldftnToken->m_tokenConstraint,
clsHnd, &pLookup);
if (!pLookup.lookupKind.needsRuntimeLookup)
{
helperArgs = gtNewCallArgs(thisPointer, targetObjPointers);
Expand All @@ -1153,7 +1154,7 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
{
assert(oper != GT_FTN_ADDR);
CORINFO_CONST_LOOKUP genericLookup;
info.compCompHnd->getReadyToRunHelper(ldftnToken, &pLookup.lookupKind,
info.compCompHnd->getReadyToRunHelper(&ldftnToken->m_token, &pLookup.lookupKind,
CORINFO_HELP_READYTORUN_GENERIC_HANDLE, &genericLookup);
GenTree* ctxTree = getRuntimeContextTree(pLookup.lookupKind.runtimeLookupKind);
helperArgs = gtNewCallArgs(thisPointer, targetObjPointers, ctxTree);
Expand All @@ -1179,7 +1180,8 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);

CORINFO_LOOKUP entryPoint;
info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &entryPoint);
info.compCompHnd->getReadyToRunDelegateCtorHelper(&ldftnToken->m_token, ldftnToken->m_tokenConstraint,
clsHnd, &entryPoint);
assert(!entryPoint.lookupKind.needsRuntimeLookup);
call->setEntryPoint(entryPoint.constLookup);
}
Expand Down
33 changes: 18 additions & 15 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8716,7 +8716,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
const int tailCallFlags = (prefixFlags & PREFIX_TAILCALL);
const bool isReadonlyCall = (prefixFlags & PREFIX_READONLY) != 0;

CORINFO_RESOLVED_TOKEN* ldftnToken = nullptr;
methodPointerInfo* ldftnInfo = nullptr;

// Synchronized methods need to call CORINFO_HELP_MON_EXIT at the end. We could
// do that before tailcalls, but that is probably not the intended
Expand Down Expand Up @@ -9530,9 +9530,9 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (impStackHeight() > 0)
{
typeInfo delegateTypeInfo = impStackTop().seTypeInfo;
if (delegateTypeInfo.IsToken())
if (delegateTypeInfo.IsMethod())
{
ldftnToken = delegateTypeInfo.GetToken();
ldftnInfo = delegateTypeInfo.GetMethodPointerInfo();
}
}
}
Expand Down Expand Up @@ -9626,7 +9626,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
{
// New inliner morph it in impImportCall.
// This will allow us to inline the call to the delegate constructor.
call = fgOptimizeDelegateConstructor(call->AsCall(), &exactContextHnd, ldftnToken);
call = fgOptimizeDelegateConstructor(call->AsCall(), &exactContextHnd, ldftnInfo);
}

if (!bIntrinsicImported)
Expand Down Expand Up @@ -12156,7 +12156,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
bool usingReadyToRunHelper = false;
#endif
CORINFO_RESOLVED_TOKEN resolvedToken;
CORINFO_RESOLVED_TOKEN constrainedResolvedToken;
CORINFO_RESOLVED_TOKEN constrainedResolvedToken = {};
CORINFO_CALL_INFO callInfo;
CORINFO_FIELD_INFO fieldInfo;

Expand Down Expand Up @@ -14558,9 +14558,10 @@ void Compiler::impImportBlockCode(BasicBlock* block)

// Call info may have more precise information about the function than
// the resolved token.
CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken);
mdToken constrainedToken = prefixFlags & PREFIX_CONSTRAINED ? constrainedResolvedToken.token : 0;
methodPointerInfo* heapToken = impAllocateMethodPointerInfo(resolvedToken, constrainedToken);
assert(callInfo.hMethod != nullptr);
heapToken->hMethod = callInfo.hMethod;
heapToken->m_token.hMethod = callInfo.hMethod;
impPushOnStack(op1, typeInfo(heapToken));

break;
Expand Down Expand Up @@ -14632,13 +14633,13 @@ void Compiler::impImportBlockCode(BasicBlock* block)
return;
}

CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken);
methodPointerInfo* heapToken = impAllocateMethodPointerInfo(resolvedToken, 0);

assert(heapToken->tokenType == CORINFO_TOKENKIND_Method);
assert(heapToken->m_token.tokenType == CORINFO_TOKENKIND_Method);
assert(callInfo.hMethod != nullptr);

heapToken->tokenType = CORINFO_TOKENKIND_Ldvirtftn;
heapToken->hMethod = callInfo.hMethod;
heapToken->m_token.tokenType = CORINFO_TOKENKIND_Ldvirtftn;
heapToken->m_token.hMethod = callInfo.hMethod;
impPushOnStack(fptr, typeInfo(heapToken));

break;
Expand Down Expand Up @@ -21662,17 +21663,19 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(CORINFO_MET
}

//------------------------------------------------------------------------
// impAllocateToken: create CORINFO_RESOLVED_TOKEN into jit-allocated memory and init it.
// impAllocateMethodPointerInfo: create methodPointerInfo into jit-allocated memory and init it.
//
// Arguments:
// token - init value for the allocated token.
// tokenConstrained - init value for the constraint associated with the token
//
// Return Value:
// pointer to token into jit-allocated memory.
CORINFO_RESOLVED_TOKEN* Compiler::impAllocateToken(const CORINFO_RESOLVED_TOKEN& token)
methodPointerInfo* Compiler::impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained)
{
CORINFO_RESOLVED_TOKEN* memory = getAllocator(CMK_Unknown).allocate<CORINFO_RESOLVED_TOKEN>(1);
*memory = token;
methodPointerInfo* memory = getAllocator(CMK_Unknown).allocate<methodPointerInfo>(1);
memory->m_token = token;
memory->m_tokenConstraint = tokenConstrained;
return memory;
}

Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/tools/Common/JitInterface/CorInfoBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -989,12 +989,12 @@ static byte _getReadyToRunHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO
}

[UnmanagedCallersOnly]
static void _getReadyToRunDelegateCtorHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_RESOLVED_TOKEN* pTargetMethod, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_LOOKUP* pLookup)
static void _getReadyToRunDelegateCtorHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_RESOLVED_TOKEN* pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_LOOKUP* pLookup)
{
var _this = GetThis(thisHandle);
try
{
_this.getReadyToRunDelegateCtorHelper(ref *pTargetMethod, delegateType, ref *pLookup);
_this.getReadyToRunDelegateCtorHelper(ref *pTargetMethod, targetConstraint, delegateType, ref *pLookup);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -2635,7 +2635,7 @@ static IntPtr GetUnmanagedCallbacks()
callbacks[63] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getBoxHelper;
callbacks[64] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getUnBoxHelper;
callbacks[65] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
callbacks[67] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, byte*>)&_getHelperName;
callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
Expand Down
Loading

0 comments on commit 370f160

Please sign in to comment.