Skip to content

Commit 617f882

Browse files
committed
Implement interpreter PInvoke Calli
The Calli implementation was missing support for the case when the targer is a pinvoke. That resulted in errors due to incorrect GC mode. This change fixes that.
1 parent 44a6dd2 commit 617f882

File tree

5 files changed

+66
-13
lines changed

5 files changed

+66
-13
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,6 +2810,16 @@ void InterpCompiler::EmitPushLdvirtftn(int thisVar, CORINFO_RESOLVED_TOKEN* pRes
28102810
m_pLastNewIns->info.pCallInfo->pCallArgs = callArgs;
28112811
}
28122812

2813+
void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunctionPointerVar, CorInfoCallConv callConv)
2814+
{
2815+
AddIns(isTailCall ? INTOP_CALLI_TAIL : INTOP_CALLI);
2816+
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
2817+
// data[1] is set to 1 if the calli is calling a pinvoke, 0 otherwise
2818+
m_pLastNewIns->data[1] = (callConv == CORINFO_CALLCONV_DEFAULT || callConv == CORINFO_CALLCONV_VARARG) ? 0 : 1;
2819+
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar);
2820+
2821+
}
2822+
28132823
void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli)
28142824
{
28152825
uint32_t token = getU4LittleEndian(m_ip + 1);
@@ -3215,9 +3225,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
32153225
}
32163226
else if (isCalli)
32173227
{
3218-
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
3219-
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
3220-
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar);
3228+
EmitCalli(tailcall, calliCookie, callIFunctionPointerVar, callInfo.sig.getCallConv());
32213229
}
32223230
else
32233231
{
@@ -3274,9 +3282,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
32743282

32753283
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
32763284

3277-
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
3278-
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
3279-
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, codePointerLookupResult);
3285+
EmitCalli(tailcall, calliCookie, codePointerLookupResult, callInfo.sig.getCallConv());
32803286
break;
32813287
}
32823288
case CORINFO_VIRTUALCALL_VTABLE:
@@ -3309,9 +3315,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
33093315

33103316
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
33113317

3312-
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
3313-
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
3314-
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, synthesizedLdvirtftnPtrVar);
3318+
EmitCalli(tailcall, calliCookie, synthesizedLdvirtftnPtrVar, callInfo.sig.getCallConv());
33153319
}
33163320
else
33173321
{

src/coreclr/interpreter/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ class InterpCompiler
711711
void EmitShiftOp(int32_t opBase);
712712
void EmitCompareOp(int32_t opBase);
713713
void EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli);
714+
void EmitCalli(bool isTailCall, void* calliCookie, int callIFunctionPointerVar, CorInfoCallConv callConv);
714715
bool EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig);
715716
void EmitLdind(InterpType type, CORINFO_CLASS_HANDLE clsHnd, int32_t offset);
716717
void EmitStind(InterpType type, CORINFO_CLASS_HANDLE clsHnd, int32_t offset, bool reverseSVarOrder);

src/coreclr/interpreter/intops.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ OPDEF(INTOP_LDFLDA, "ldflda", 4, 1, 1, InterpOpInt)
358358
// Calls
359359
OPDEF(INTOP_CALL, "call", 4, 1, 1, InterpOpMethodHandle)
360360
OPDEF(INTOP_CALLDELEGATE, "call.delegate", 4, 1, 1, InterpOpMethodHandle)
361-
OPDEF(INTOP_CALLI, "calli", 5, 1, 2, InterpOpLdPtr)
361+
OPDEF(INTOP_CALLI, "calli", 6, 1, 2, InterpOpLdPtr)
362362
OPDEF(INTOP_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodHandle)
363363
OPDEF(INTOP_CALL_PINVOKE, "call.pinvoke", 6, 1, 1, InterpOpMethodHandle) // inlined (no marshaling wrapper) pinvokes only
364364
OPDEF(INTOP_NEWOBJ, "newobj", 5, 1, 1, InterpOpMethodHandle)
@@ -367,7 +367,7 @@ OPDEF(INTOP_NEWOBJ_VT, "newobj.vt", 5, 1, 1, InterpOpMethodHandle)
367367

368368
// Tail calls
369369
OPDEF(INTOP_CALL_TAIL, "call.tail", 4, 1, 1, InterpOpMethodHandle)
370-
OPDEF(INTOP_CALLI_TAIL, "calli", 5, 1, 2, InterpOpLdPtr)
370+
OPDEF(INTOP_CALLI_TAIL, "calli.tail", 6, 1, 2, InterpOpLdPtr)
371371
OPDEF(INTOP_CALLVIRT_TAIL, "callvirt.tail", 4, 1, 1, InterpOpMethodHandle)
372372

373373
// The following helper call instructions exist in 2 variants, one for normal methods, and one for cases where a shared generic lookup is needed.

src/coreclr/vm/interpexec.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#ifdef TARGET_WASM
1515
void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
16+
void InvokePInvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet);
1617
void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target);
1718
void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target);
1819
#else
@@ -101,6 +102,39 @@ void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, in
101102
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
102103
}
103104

105+
void InvokePInvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet)
106+
{
107+
CONTRACTL
108+
{
109+
THROWS;
110+
MODE_ANY;
111+
PRECONDITION(CheckPointer((void*)ftn));
112+
PRECONDITION(CheckPointer(stubHeaderTemplate));
113+
}
114+
CONTRACTL_END
115+
116+
// CallStubHeaders encode their destination addresses in the Routines array, so they need to be
117+
// copied to a local buffer before we can actually set their target address.
118+
size_t templateSize = stubHeaderTemplate->GetSize();
119+
uint8_t* actualCallStub = (uint8_t*)alloca(templateSize);
120+
memcpy(actualCallStub, stubHeaderTemplate, templateSize);
121+
CallStubHeader *pHeader = (CallStubHeader*)actualCallStub;
122+
pHeader->SetTarget(ftn); // The method to call
123+
124+
InlinedCallFrame inlinedCallFrame;
125+
inlinedCallFrame.m_pCallerReturnAddress = (TADDR)pFrame->ip;
126+
inlinedCallFrame.m_pCallSiteSP = pFrame;
127+
inlinedCallFrame.m_pCalleeSavedFP = (TADDR)stack;
128+
inlinedCallFrame.m_pThread = GetThread();
129+
inlinedCallFrame.m_Datum = NULL;
130+
inlinedCallFrame.Push();
131+
{
132+
GCX_PREEMP();
133+
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
134+
}
135+
inlinedCallFrame.Pop();
136+
}
137+
104138
void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet)
105139
{
106140
CONTRACTL
@@ -1975,15 +2009,24 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
19752009
callArgsOffset = ip[2];
19762010
int32_t calliFunctionPointerVar = ip[3];
19772011
int32_t calliCookie = ip[4];
2012+
bool isPInvoke = ip[5] != 0;
19782013

19792014
CallStubHeader *pCallStub = (CallStubHeader*)pMethod->pDataItems[calliCookie];
1980-
ip += 5;
2015+
ip += 6;
19812016

19822017
// Save current execution state for when we return from called method
19832018
pFrame->ip = ip;
19842019

19852020
// Interpreter-FIXME: isTailcall
1986-
InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack + callArgsOffset, stack + returnOffset);
2021+
if (isPInvoke)
2022+
{
2023+
InvokePInvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack, pFrame, stack + callArgsOffset, stack + returnOffset);
2024+
}
2025+
else
2026+
{
2027+
InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack + callArgsOffset, stack + returnOffset);
2028+
}
2029+
19872030
break;
19882031
}
19892032

src/coreclr/vm/wasm/helpers.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,11 @@ void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArg
483483
PORTABILITY_ASSERT("InvokeCalliStub is not implemented on wasm");
484484
}
485485

486+
void InvokePInvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet)
487+
{
488+
PORTABILITY_ASSERT("InvokePInvokeCalliStub is not implemented on wasm");
489+
}
490+
486491
void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target)
487492
{
488493
PORTABILITY_ASSERT("Attempted to execute non-interpreter code from interpreter on wasm, this is not yet implemented");

0 commit comments

Comments
 (0)