Skip to content

Commit 7018450

Browse files
radekdoulikCopilotjkotasCopilot
authored
[wasm][coreclr] Cache calli cookies (#127016)
Avoid repeated expensive calls to get calli cookie by caching it Checked in HelloWorld ``` CalliCookie cache: 18 hits, 17 misses, 35 total (51.4% hit rate) ``` --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 004c358 commit 7018450

10 files changed

Lines changed: 172 additions & 135 deletions

File tree

src/coreclr/vm/interpexec.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,9 @@ static size_t CreateDispatchTokenForMethod(MethodDesc* pMD)
206206
void InvokeManagedMethod(ManagedMethodParam *pParam);
207207
void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *pArgs, int8_t *pRet, PCODE callTarget);
208208
void InvokeCalliStub(CalliStubParam* pParam);
209-
void InvokeUnmanagedCalli(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet);
209+
void InvokeUnmanagedCalli(PCODE ftn, InterpreterCalliCookie cookie, int8_t *pArgs, int8_t *pRet);
210210
void InvokeDelegateInvokeMethod(DelegateInvokeMethodParam* pParam);
211-
void* GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD);
211+
InterpreterCalliCookie GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD);
212212
extern "C" PCODE CID_VirtualOpenDelegateDispatch(TransitionBlock * pTransitionBlock);
213213

214214
// Filter to ignore SEH exceptions representing C++ exceptions.
@@ -287,7 +287,7 @@ void InvokeUnmanagedMethodWithTransition(UnmanagedMethodWithTransitionParam *pPa
287287
}
288288

289289
NOINLINE
290-
void InvokeUnmanagedCalliWithTransition(PCODE ftn, void *cookie, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet)
290+
void InvokeUnmanagedCalliWithTransition(PCODE ftn, InterpreterCalliCookie cookie, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet)
291291
{
292292
CONTRACTL
293293
{
@@ -349,15 +349,15 @@ static CallStubHeader *UpdateCallStubForMethod(MethodDesc *pMD, PCODE target)
349349
header->SetTarget(target);
350350
}
351351

352-
if (pMD->SetCallStub(header))
352+
if (pMD->SetCalliCookie(header))
353353
{
354354
amTracker.SuppressRelease();
355355
}
356356
else
357357
{
358358
// We have lost the race for generating the header, use the one that was generated by another thread
359359
// and let the amTracker release the memory of the one we generated.
360-
header = pMD->GetCallStub();
360+
header = pMD->GetCalliCookie();
361361
}
362362

363363
return header;
@@ -408,7 +408,7 @@ void InvokeManagedMethod(ManagedMethodParam* pParam)
408408
PCODE target = pParam->target;
409409
Object** pContinuationRet = pParam->pContinuationRet;
410410

411-
CallStubHeader *pHeader = pParam->pMD->GetCallStub();
411+
CallStubHeader *pHeader = pParam->pMD->GetCalliCookie();
412412
if (pHeader == NULL)
413413
{
414414
pHeader = UpdateCallStubForMethod(pMD, target == (PCODE)NULL ? pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY) : target);
@@ -467,7 +467,7 @@ void InvokeDelegateInvokeMethod(DelegateInvokeMethodParam* pParam)
467467
PCODE target = pParam->target;
468468
Object** pContinuationRet = pParam->pContinuationRet;
469469

470-
CallStubHeader *stubHeaderTemplate = pMDDelegateInvoke->GetCallStub();
470+
CallStubHeader *stubHeaderTemplate = pMDDelegateInvoke->GetCalliCookie();
471471
if (stubHeaderTemplate == NULL)
472472
{
473473
stubHeaderTemplate = UpdateCallStubForMethod(pMDDelegateInvoke, (PCODE)pMDDelegateInvoke->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY));
@@ -490,7 +490,7 @@ void InvokeDelegateInvokeMethod(DelegateInvokeMethodParam* pParam)
490490
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize, pContinuationRet);
491491
}
492492

493-
void InvokeUnmanagedCalli(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet)
493+
void InvokeUnmanagedCalli(PCODE ftn, InterpreterCalliCookie cookie, int8_t *pArgs, int8_t *pRet)
494494
{
495495
CONTRACTL
496496
{
@@ -549,7 +549,7 @@ void InvokeCalliStub(CalliStubParam* pParam)
549549
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize, pContinuationRet);
550550
}
551551

552-
void* GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD)
552+
InterpreterCalliCookie GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD)
553553
{
554554
STANDARD_VM_CONTRACT;
555555

@@ -3162,7 +3162,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
31623162
int32_t calliCookie = ip[4];
31633163
int32_t flags = ip[5];
31643164

3165-
void* cookie = pMethod->pDataItems[calliCookie];
3165+
InterpreterCalliCookie cookie = (InterpreterCalliCookie)pMethod->pDataItems[calliCookie];
31663166
ip += 6;
31673167

31683168
// Save current execution state for when we return from called method
@@ -3206,8 +3206,15 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
32063206
if (PortableEntryPoint::PrefersInterpreterEntryPoint(calliFunctionPointer) || !PortableEntryPoint::HasNativeEntryPoint(calliFunctionPointer))
32073207
goto CALL_INTERP_METHOD;
32083208

3209-
MetaSig sig(targetMethod);
3210-
cookie = GetCookieForCalliSig(sig, NULL);
3209+
cookie = targetMethod->GetCalliCookie();
3210+
if (cookie == NULL)
3211+
{
3212+
MetaSig sig(targetMethod);
3213+
cookie = GetCookieForCalliSig(sig, NULL);
3214+
_ASSERTE(cookie != NULL);
3215+
targetMethod->SetCalliCookie(cookie);
3216+
cookie = targetMethod->GetCalliCookie();
3217+
}
32113218
#endif // FEATURE_PORTABLE_ENTRYPOINTS
32123219
frameNeedsTailcallUpdate = false;
32133220
CalliStubParam param = { calliFunctionPointer, cookie, callArgsAddress, returnValueAddress, pInterpreterFrame->GetContinuationPtr() };

src/coreclr/vm/interpexec.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,16 @@ struct ManagedMethodParam
132132

133133
void InvokeManagedMethod(ManagedMethodParam *pParam);
134134

135+
#ifdef FEATURE_INTERPRETER
135136
struct CalliStubParam
136137
{
137138
PCODE ftn;
138-
void* cookie;
139+
InterpreterCalliCookie cookie;
139140
int8_t *pArgs;
140141
int8_t *pRet;
141142
Object** pContinuationRet;
142143
};
144+
#endif // FEATURE_INTERPRETER
143145

144146
struct DelegateInvokeMethodParam
145147
{

src/coreclr/vm/jitinterface.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11491,25 +11491,13 @@ LPVOID CEEInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig)
1149111491
#ifdef FEATURE_INTERPRETER
1149211492

1149311493
// Forward declare the function for mapping MetaSig to a cookie.
11494-
void* GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD);
11494+
InterpreterCalliCookie GetCookieForCalliSig(MetaSig metaSig, MethodDesc *pContextMD);
1149511495

1149611496
LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig)
1149711497
{
11498-
void* result = NULL;
11498+
InterpreterCalliCookie result = NULL;
1149911499
JIT_TO_EE_TRANSITION();
1150011500

11501-
Instantiation classInst = Instantiation((TypeHandle*) szMetaSig->sigInst.classInst, szMetaSig->sigInst.classInstCount);
11502-
Instantiation methodInst = Instantiation((TypeHandle*) szMetaSig->sigInst.methInst, szMetaSig->sigInst.methInstCount);
11503-
SigTypeContext typeContext = SigTypeContext(classInst, methodInst);
11504-
Module* mod = GetModule(szMetaSig->scope);
11505-
11506-
MetaSig sig(szMetaSig->pSig, szMetaSig->cbSig, mod, &typeContext);
11507-
11508-
if (szMetaSig->isAsyncCall())
11509-
sig.SetIsAsyncCall();
11510-
11511-
_ASSERTE(szMetaSig->isAsyncCall() == sig.IsAsyncCall());
11512-
1151311501
// When compiling a calli inside an IL stub for a P/Invoke, pass the target
1151411502
// P/Invoke MethodDesc so ComputeCallStub can detect the Swift calling convention.
1151511503
MethodDesc* pContextMD = nullptr;
@@ -11519,12 +11507,35 @@ LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* sz
1151911507
if (pTargetMD != nullptr)
1152011508
{
1152111509
pContextMD = pTargetMD;
11510+
result = pTargetMD->GetCalliCookie();
11511+
}
11512+
}
11513+
11514+
if (result == NULL)
11515+
{
11516+
Instantiation classInst = Instantiation((TypeHandle*) szMetaSig->sigInst.classInst, szMetaSig->sigInst.classInstCount);
11517+
Instantiation methodInst = Instantiation((TypeHandle*) szMetaSig->sigInst.methInst, szMetaSig->sigInst.methInstCount);
11518+
SigTypeContext typeContext = SigTypeContext(classInst, methodInst);
11519+
Module* mod = GetModule(szMetaSig->scope);
11520+
11521+
MetaSig sig(szMetaSig->pSig, szMetaSig->cbSig, mod, &typeContext);
11522+
11523+
if (szMetaSig->isAsyncCall())
11524+
sig.SetIsAsyncCall();
11525+
11526+
_ASSERTE(szMetaSig->isAsyncCall() == sig.IsAsyncCall());
11527+
11528+
result = GetCookieForCalliSig(sig, pContextMD);
11529+
11530+
if (pContextMD != nullptr)
11531+
{
11532+
pContextMD->SetCalliCookie(result);
11533+
result = pContextMD->GetCalliCookie();
1152211534
}
1152311535
}
11524-
result = GetCookieForCalliSig(sig, pContextMD);
1152511536

1152611537
EE_TO_JIT_TRANSITION();
11527-
return result;
11538+
return (void*)result;
1152811539
}
1152911540

1153011541
void CInterpreterJitInfo::allocMem(AllocMemArgs *pArgs)

src/coreclr/vm/method.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,26 +300,26 @@ PatchpointInfo* MethodDesc::GetMethodDescAltJitPatchpointInfo()
300300
#endif // FEATURE_CODE_VERSIONING
301301

302302
#ifdef FEATURE_INTERPRETER
303-
// Set the call stub for the interpreter to JIT/AOT calls
304-
// Returns true if the current call set the stub, false if it was already set
305-
bool MethodDesc::SetCallStub(CallStubHeader *pHeader)
303+
// Cache the calli cookie on the MethodDesc
304+
// Returns true if the current call set the cookie, false if it was already set
305+
bool MethodDesc::SetCalliCookie(InterpreterCalliCookie cookie)
306306
{
307307
STANDARD_VM_CONTRACT;
308308

309309
IfFailThrow(EnsureCodeDataExists(NULL));
310310

311311
_ASSERTE(m_codeData != NULL);
312-
return InterlockedCompareExchangeT(&m_codeData->CallStub, pHeader, NULL) == NULL;
312+
return InterlockedCompareExchangeT((void**)&m_codeData->CalliCookie, (void*)cookie, (void*)NULL) == NULL;
313313
}
314314

315-
CallStubHeader *MethodDesc::GetCallStub()
315+
InterpreterCalliCookie MethodDesc::GetCalliCookie()
316316
{
317317
LIMITED_METHOD_CONTRACT;
318318

319319
PTR_MethodDescCodeData codeData = VolatileLoadWithoutBarrier(&m_codeData);
320320
if (codeData == NULL)
321321
return NULL;
322-
return VolatileLoadWithoutBarrier(&codeData->CallStub);
322+
return (InterpreterCalliCookie)VolatileLoadWithoutBarrier(&codeData->CalliCookie);
323323
}
324324
#endif // FEATURE_INTERPRETER
325325

src/coreclr/vm/method.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,14 @@ enum MethodDescFlags
249249
};
250250

251251
// Used for storing additional items related to native code
252+
#ifdef FEATURE_INTERPRETER
253+
#ifdef FEATURE_PORTABLE_ENTRYPOINTS
254+
typedef void(*InterpreterCalliCookie)(PCODE, int8_t*, int8_t*);
255+
#else
256+
typedef CallStubHeader* InterpreterCalliCookie;
257+
#endif // FEATURE_PORTABLE_ENTRYPOINTS
258+
#endif // FEATURE_INTERPRETER
259+
252260
struct MethodDescCodeData final
253261
{
254262
#ifdef FEATURE_CODE_VERSIONING
@@ -257,7 +265,7 @@ struct MethodDescCodeData final
257265
#endif // FEATURE_CODE_VERSIONING
258266
PCODE TemporaryEntryPoint;
259267
#ifdef FEATURE_INTERPRETER
260-
CallStubHeader *CallStub;
268+
InterpreterCalliCookie CalliCookie;
261269
#endif // FEATURE_INTERPRETER
262270
#if defined(_DEBUG) && defined(ALLOW_SXS_JIT)
263271
PatchpointInfo *AltJitPatchpointInfo;
@@ -1976,8 +1984,8 @@ class MethodDesc
19761984
#endif //!DACCESS_COMPILE
19771985

19781986
#if defined(FEATURE_INTERPRETER) && !defined(DACCESS_COMPILE)
1979-
bool SetCallStub(CallStubHeader *pHeader);
1980-
CallStubHeader *GetCallStub();
1987+
bool SetCalliCookie(InterpreterCalliCookie cookie);
1988+
InterpreterCalliCookie GetCalliCookie();
19811989
#endif // FEATURE_INTERPRETER && !DACCESS_COMPILE
19821990

19831991
#ifdef FEATURE_CODE_VERSIONING

src/coreclr/vm/precode_portable.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,14 @@ class PortableEntryPoint final
116116

117117
friend struct ::cdac_data<PortableEntryPoint>;
118118
};
119+
119120
template<>
120121
struct cdac_data<PortableEntryPoint>
121122
{
122123
static constexpr size_t MethodDesc = offsetof(PortableEntryPoint, _pMD);
123-
};
124124

125+
static_assert(offsetof(PortableEntryPoint, _pActualCode) == 0, "CLR ABI requires _pActualCode to be at offset 0 of PortableEntryPoint");
126+
};
125127

126128
extern InterleavedLoaderHeapConfig s_stubPrecodeHeapConfig;
127129

0 commit comments

Comments
 (0)