Skip to content

Commit 7fe76b1

Browse files
MichalStrehovskyradekdoulik
authored andcommitted
Add support for creating delegates to static virtual methods (dotnet#66936)
Requires a JitInterface change because we need to be able to pass information about constraints to `getReadyToRunDelegateCtorHelper`
1 parent 844bea7 commit 7fe76b1

File tree

27 files changed

+325
-203
lines changed

27 files changed

+325
-203
lines changed

src/coreclr/inc/corinfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,6 +2441,7 @@ class ICorStaticInfo
24412441

24422442
virtual void getReadyToRunDelegateCtorHelper(
24432443
CORINFO_RESOLVED_TOKEN * pTargetMethod,
2444+
mdToken targetConstraint,
24442445
CORINFO_CLASS_HANDLE delegateType,
24452446
CORINFO_LOOKUP * pLookup
24462447
) = 0;

src/coreclr/inc/icorjitinfoimpl_generated.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ bool getReadyToRunHelper(
283283

284284
void getReadyToRunDelegateCtorHelper(
285285
CORINFO_RESOLVED_TOKEN* pTargetMethod,
286+
mdToken targetConstraint,
286287
CORINFO_CLASS_HANDLE delegateType,
287288
CORINFO_LOOKUP* pLookup) override;
288289

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

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

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/jit/ICorJitInfo_API_wrapper.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,11 +656,12 @@ bool WrapICorJitInfo::getReadyToRunHelper(
656656

657657
void WrapICorJitInfo::getReadyToRunDelegateCtorHelper(
658658
CORINFO_RESOLVED_TOKEN* pTargetMethod,
659+
mdToken targetConstraint,
659660
CORINFO_CLASS_HANDLE delegateType,
660661
CORINFO_LOOKUP* pLookup)
661662
{
662663
API_ENTER(getReadyToRunDelegateCtorHelper);
663-
wrapHnd->getReadyToRunDelegateCtorHelper(pTargetMethod, delegateType, pLookup);
664+
wrapHnd->getReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, pLookup);
664665
API_LEAVE(getReadyToRunDelegateCtorHelper);
665666
}
666667

src/coreclr/jit/_typeinfo.h

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,21 @@ inline ti_types JITtype2tiType(CorInfoType type)
142142
return g_ti_types_map[type];
143143
};
144144

145+
/*****************************************************************************
146+
* Captures information about a method pointer
147+
*
148+
* m_token is the CORINFO_RESOLVED_TOKEN from the IL, potentially with a more
149+
* precise method handle from getCallInfo
150+
* m_tokenConstraint is the constraint if this was a constrained ldftn.
151+
*
152+
*/
153+
class methodPointerInfo
154+
{
155+
public:
156+
CORINFO_RESOLVED_TOKEN m_token;
157+
mdToken m_tokenConstraint;
158+
};
159+
145160
/*****************************************************************************
146161
* Declares the typeInfo class, which represents the type of an entity on the
147162
* stack, in a local variable or an argument.
@@ -221,9 +236,6 @@ inline ti_types JITtype2tiType(CorInfoType type)
221236
// since conversions between them are not verifiable.
222237
#define TI_FLAG_NATIVE_INT 0x00000200
223238

224-
// This item contains resolved token. It is used for ctor delegate optimization.
225-
#define TI_FLAG_TOKEN 0x00000400
226-
227239
// This item contains the 'this' pointer (used for tracking)
228240

229241
#define TI_FLAG_THIS_PTR 0x00001000
@@ -270,7 +282,7 @@ inline ti_types JITtype2tiType(CorInfoType type)
270282
* - A type (ref, array, value type) (m_cls describes the type)
271283
* - An array (m_cls describes the array type)
272284
* - A byref (byref flag set, otherwise the same as the above),
273-
* - A Function Pointer (m_method)
285+
* - A Function Pointer (m_methodPointerInfo)
274286
* - A byref local variable (byref and byref local flags set), can be
275287
* uninitialized
276288
*
@@ -291,7 +303,7 @@ class typeInfo
291303
unsigned byref : 1; // used
292304
unsigned byref_readonly : 1; // used
293305
unsigned nativeInt : 1; // used
294-
unsigned token : 1; // used
306+
unsigned : 1; // unused
295307
unsigned : 1; // unused
296308
unsigned thisPtr : 1; // used
297309
unsigned thisPermHome : 1; // used
@@ -303,10 +315,8 @@ class typeInfo
303315

304316
union {
305317
CORINFO_CLASS_HANDLE m_cls;
306-
// Valid only for type TI_METHOD without IsToken
307-
CORINFO_METHOD_HANDLE m_method;
308-
// Valid only for TI_TOKEN with IsToken
309-
CORINFO_RESOLVED_TOKEN* m_token;
318+
// Valid only for type TI_METHOD
319+
methodPointerInfo* m_methodPointerInfo;
310320
};
311321

312322
template <typename T>
@@ -362,21 +372,13 @@ class typeInfo
362372
m_cls = cls;
363373
}
364374

365-
typeInfo(CORINFO_METHOD_HANDLE method)
366-
{
367-
assert(method != nullptr && !isInvalidHandle(method));
368-
m_flags = TI_METHOD;
369-
m_method = method;
370-
}
371-
372-
typeInfo(CORINFO_RESOLVED_TOKEN* token)
375+
typeInfo(methodPointerInfo* methodPointerInfo)
373376
{
374-
assert(token != nullptr);
375-
assert(token->hMethod != nullptr);
376-
assert(!isInvalidHandle(token->hMethod));
377-
m_flags = TI_METHOD;
378-
SetIsToken();
379-
m_token = token;
377+
assert(methodPointerInfo != nullptr);
378+
assert(methodPointerInfo->m_token.hMethod != nullptr);
379+
assert(!isInvalidHandle(methodPointerInfo->m_token.hMethod));
380+
m_flags = TI_METHOD;
381+
m_methodPointerInfo = methodPointerInfo;
380382
}
381383

382384
#ifdef DEBUG
@@ -458,12 +460,6 @@ class typeInfo
458460
// Operations
459461
/////////////////////////////////////////////////////////////////////////
460462

461-
void SetIsToken()
462-
{
463-
m_flags |= TI_FLAG_TOKEN;
464-
assert(m_bits.token);
465-
}
466-
467463
void SetIsThisPtr()
468464
{
469465
m_flags |= TI_FLAG_THIS_PTR;
@@ -573,17 +569,13 @@ class typeInfo
573569
CORINFO_METHOD_HANDLE GetMethod() const
574570
{
575571
assert(GetType() == TI_METHOD);
576-
if (IsToken())
577-
{
578-
return m_token->hMethod;
579-
}
580-
return m_method;
572+
return m_methodPointerInfo->m_token.hMethod;
581573
}
582574

583-
CORINFO_RESOLVED_TOKEN* GetToken() const
575+
methodPointerInfo* GetMethodPointerInfo() const
584576
{
585-
assert(IsToken());
586-
return m_token;
577+
assert(GetType() == TI_METHOD);
578+
return m_methodPointerInfo;
587579
}
588580

589581
// Get this item's type
@@ -750,11 +742,6 @@ class typeInfo
750742
return (m_flags & TI_FLAG_UNINIT_OBJREF);
751743
}
752744

753-
bool IsToken() const
754-
{
755-
return IsMethod() && ((m_flags & TI_FLAG_TOKEN) != 0);
756-
}
757-
758745
private:
759746
// used to make functions that return typeinfo efficient.
760747
typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls)

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4988,7 +4988,7 @@ class Compiler
49884988
bool impIsClassExact(CORINFO_CLASS_HANDLE classHnd);
49894989
bool impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array);
49904990

4991-
CORINFO_RESOLVED_TOKEN* impAllocateToken(const CORINFO_RESOLVED_TOKEN& token);
4991+
methodPointerInfo* impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained);
49924992

49934993
/*
49944994
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -6487,7 +6487,7 @@ class Compiler
64876487
#endif
64886488
GenTree* fgOptimizeDelegateConstructor(GenTreeCall* call,
64896489
CORINFO_CONTEXT_HANDLE* ExactContextHnd,
6490-
CORINFO_RESOLVED_TOKEN* ldftnToken);
6490+
methodPointerInfo* ldftnToken);
64916491
GenTree* fgMorphLeaf(GenTree* tree);
64926492
void fgAssignSetVarDef(GenTree* tree);
64936493
GenTree* fgMorphOneAsgBlockOp(GenTree* tree);

src/coreclr/jit/flowgraph.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ bool Compiler::fgAddrCouldBeNull(GenTree* addr)
10471047

10481048
GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
10491049
CORINFO_CONTEXT_HANDLE* ExactContextHnd,
1050-
CORINFO_RESOLVED_TOKEN* ldftnToken)
1050+
methodPointerInfo* ldftnToken)
10511051
{
10521052
JITDUMP("\nfgOptimizeDelegateConstructor: ");
10531053
noway_assert(call->gtCallType == CT_USER_FUNC);
@@ -1115,14 +1115,14 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
11151115
// via the above pattern match, and more...
11161116
if (ldftnToken != nullptr)
11171117
{
1118-
assert(ldftnToken->hMethod != nullptr);
1118+
assert(ldftnToken->m_token.hMethod != nullptr);
11191119

11201120
if (targetMethodHnd != nullptr)
11211121
{
1122-
assert(targetMethodHnd == ldftnToken->hMethod);
1122+
assert(targetMethodHnd == ldftnToken->m_token.hMethod);
11231123
}
11241124

1125-
targetMethodHnd = ldftnToken->hMethod;
1125+
targetMethodHnd = ldftnToken->m_token.hMethod;
11261126
}
11271127
else
11281128
{
@@ -1143,7 +1143,8 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
11431143
GenTreeCall::Use* helperArgs = nullptr;
11441144
CORINFO_LOOKUP pLookup;
11451145
CORINFO_CONST_LOOKUP entryPoint;
1146-
info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &pLookup);
1146+
info.compCompHnd->getReadyToRunDelegateCtorHelper(&ldftnToken->m_token, ldftnToken->m_tokenConstraint,
1147+
clsHnd, &pLookup);
11471148
if (!pLookup.lookupKind.needsRuntimeLookup)
11481149
{
11491150
helperArgs = gtNewCallArgs(thisPointer, targetObjPointers);
@@ -1153,7 +1154,7 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
11531154
{
11541155
assert(oper != GT_FTN_ADDR);
11551156
CORINFO_CONST_LOOKUP genericLookup;
1156-
info.compCompHnd->getReadyToRunHelper(ldftnToken, &pLookup.lookupKind,
1157+
info.compCompHnd->getReadyToRunHelper(&ldftnToken->m_token, &pLookup.lookupKind,
11571158
CORINFO_HELP_READYTORUN_GENERIC_HANDLE, &genericLookup);
11581159
GenTree* ctxTree = getRuntimeContextTree(pLookup.lookupKind.runtimeLookupKind);
11591160
helperArgs = gtNewCallArgs(thisPointer, targetObjPointers, ctxTree);
@@ -1179,7 +1180,8 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call,
11791180
call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);
11801181

11811182
CORINFO_LOOKUP entryPoint;
1182-
info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &entryPoint);
1183+
info.compCompHnd->getReadyToRunDelegateCtorHelper(&ldftnToken->m_token, ldftnToken->m_tokenConstraint,
1184+
clsHnd, &entryPoint);
11831185
assert(!entryPoint.lookupKind.needsRuntimeLookup);
11841186
call->setEntryPoint(entryPoint.constLookup);
11851187
}

src/coreclr/jit/importer.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8716,7 +8716,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
87168716
const int tailCallFlags = (prefixFlags & PREFIX_TAILCALL);
87178717
const bool isReadonlyCall = (prefixFlags & PREFIX_READONLY) != 0;
87188718

8719-
CORINFO_RESOLVED_TOKEN* ldftnToken = nullptr;
8719+
methodPointerInfo* ldftnInfo = nullptr;
87208720

87218721
// Synchronized methods need to call CORINFO_HELP_MON_EXIT at the end. We could
87228722
// do that before tailcalls, but that is probably not the intended
@@ -9530,9 +9530,9 @@ var_types Compiler::impImportCall(OPCODE opcode,
95309530
if (impStackHeight() > 0)
95319531
{
95329532
typeInfo delegateTypeInfo = impStackTop().seTypeInfo;
9533-
if (delegateTypeInfo.IsToken())
9533+
if (delegateTypeInfo.IsMethod())
95349534
{
9535-
ldftnToken = delegateTypeInfo.GetToken();
9535+
ldftnInfo = delegateTypeInfo.GetMethodPointerInfo();
95369536
}
95379537
}
95389538
}
@@ -9626,7 +9626,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
96269626
{
96279627
// New inliner morph it in impImportCall.
96289628
// This will allow us to inline the call to the delegate constructor.
9629-
call = fgOptimizeDelegateConstructor(call->AsCall(), &exactContextHnd, ldftnToken);
9629+
call = fgOptimizeDelegateConstructor(call->AsCall(), &exactContextHnd, ldftnInfo);
96309630
}
96319631

96329632
if (!bIntrinsicImported)
@@ -12156,7 +12156,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
1215612156
bool usingReadyToRunHelper = false;
1215712157
#endif
1215812158
CORINFO_RESOLVED_TOKEN resolvedToken;
12159-
CORINFO_RESOLVED_TOKEN constrainedResolvedToken;
12159+
CORINFO_RESOLVED_TOKEN constrainedResolvedToken = {};
1216012160
CORINFO_CALL_INFO callInfo;
1216112161
CORINFO_FIELD_INFO fieldInfo;
1216212162

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

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

1456614567
break;
@@ -14632,13 +14633,13 @@ void Compiler::impImportBlockCode(BasicBlock* block)
1463214633
return;
1463314634
}
1463414635

14635-
CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken);
14636+
methodPointerInfo* heapToken = impAllocateMethodPointerInfo(resolvedToken, 0);
1463614637

14637-
assert(heapToken->tokenType == CORINFO_TOKENKIND_Method);
14638+
assert(heapToken->m_token.tokenType == CORINFO_TOKENKIND_Method);
1463814639
assert(callInfo.hMethod != nullptr);
1463914640

14640-
heapToken->tokenType = CORINFO_TOKENKIND_Ldvirtftn;
14641-
heapToken->hMethod = callInfo.hMethod;
14641+
heapToken->m_token.tokenType = CORINFO_TOKENKIND_Ldvirtftn;
14642+
heapToken->m_token.hMethod = callInfo.hMethod;
1464214643
impPushOnStack(fptr, typeInfo(heapToken));
1464314644

1464414645
break;
@@ -21662,17 +21663,19 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(CORINFO_MET
2166221663
}
2166321664

2166421665
//------------------------------------------------------------------------
21665-
// impAllocateToken: create CORINFO_RESOLVED_TOKEN into jit-allocated memory and init it.
21666+
// impAllocateMethodPointerInfo: create methodPointerInfo into jit-allocated memory and init it.
2166621667
//
2166721668
// Arguments:
2166821669
// token - init value for the allocated token.
21670+
// tokenConstrained - init value for the constraint associated with the token
2166921671
//
2167021672
// Return Value:
2167121673
// pointer to token into jit-allocated memory.
21672-
CORINFO_RESOLVED_TOKEN* Compiler::impAllocateToken(const CORINFO_RESOLVED_TOKEN& token)
21674+
methodPointerInfo* Compiler::impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained)
2167321675
{
21674-
CORINFO_RESOLVED_TOKEN* memory = getAllocator(CMK_Unknown).allocate<CORINFO_RESOLVED_TOKEN>(1);
21675-
*memory = token;
21676+
methodPointerInfo* memory = getAllocator(CMK_Unknown).allocate<methodPointerInfo>(1);
21677+
memory->m_token = token;
21678+
memory->m_tokenConstraint = tokenConstrained;
2167621679
return memory;
2167721680
}
2167821681

src/coreclr/tools/Common/JitInterface/CorInfoBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -989,12 +989,12 @@ static byte _getReadyToRunHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO
989989
}
990990

991991
[UnmanagedCallersOnly]
992-
static void _getReadyToRunDelegateCtorHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_RESOLVED_TOKEN* pTargetMethod, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_LOOKUP* pLookup)
992+
static void _getReadyToRunDelegateCtorHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_RESOLVED_TOKEN* pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_LOOKUP* pLookup)
993993
{
994994
var _this = GetThis(thisHandle);
995995
try
996996
{
997-
_this.getReadyToRunDelegateCtorHelper(ref *pTargetMethod, delegateType, ref *pLookup);
997+
_this.getReadyToRunDelegateCtorHelper(ref *pTargetMethod, targetConstraint, delegateType, ref *pLookup);
998998
}
999999
catch (Exception ex)
10001000
{
@@ -2635,7 +2635,7 @@ static IntPtr GetUnmanagedCallbacks()
26352635
callbacks[63] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getBoxHelper;
26362636
callbacks[64] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getUnBoxHelper;
26372637
callbacks[65] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
2638-
callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
2638+
callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
26392639
callbacks[67] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, byte*>)&_getHelperName;
26402640
callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
26412641
callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;

0 commit comments

Comments
 (0)