Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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: 18 additions & 9 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2854,6 +2854,21 @@ void InterpCompiler::EmitPushLdvirtftn(int thisVar, CORINFO_RESOLVED_TOKEN* pRes
m_pLastNewIns->info.pCallInfo->pCallArgs = callArgs;
}

void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunctionPointerVar, CORINFO_SIG_INFO* callSiteSig)
{
AddIns(isTailCall ? INTOP_CALLI_TAIL : INTOP_CALLI);
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
// data[1] is set to 1 if the calli is calling a pinvoke, 0 otherwise
bool suppressGCTransition = false;
m_compHnd->getUnmanagedCallConv(nullptr, callSiteSig, &suppressGCTransition);
bool isPInvoke = (callSiteSig->callConv != CORINFO_CALLCONV_DEFAULT && callSiteSig->callConv != CORINFO_CALLCONV_VARARG);
bool isPInvokeMarshalled = isPInvoke && m_compHnd->pInvokeMarshalingRequired(NULL, callSiteSig);
m_pLastNewIns->data[1] = (suppressGCTransition ? (int32_t)CalliFlags::SuppressGCTransition : 0) |
(isPInvoke ? (int32_t)CalliFlags::PInvoke : 0) |
(isPInvokeMarshalled ? (int32_t)CalliFlags::PInvokeMarshalled : 0);
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar);
}

void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli)
{
uint32_t token = getU4LittleEndian(m_ip + 1);
Expand Down Expand Up @@ -3259,9 +3274,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
}
else if (isCalli)
{
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar);
EmitCalli(tailcall, calliCookie, callIFunctionPointerVar, &callInfo.sig);
}
else
{
Expand Down Expand Up @@ -3318,9 +3331,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re

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

AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, codePointerLookupResult);
EmitCalli(tailcall, calliCookie, codePointerLookupResult, &callInfo.sig);
break;
}
case CORINFO_VIRTUALCALL_VTABLE:
Expand Down Expand Up @@ -3353,9 +3364,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re

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

AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, synthesizedLdvirtftnPtrVar);
EmitCalli(tailcall, calliCookie, synthesizedLdvirtftnPtrVar, &callInfo.sig);
}
else
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/interpreter/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ class InterpCompiler
void EmitShiftOp(int32_t opBase);
void EmitCompareOp(int32_t opBase);
void EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli);
void EmitCalli(bool isTailCall, void* calliCookie, int callIFunctionPointerVar, CORINFO_SIG_INFO* callSiteSig);
bool EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig);
void EmitLdind(InterpType type, CORINFO_CLASS_HANDLE clsHnd, int32_t offset);
void EmitStind(InterpType type, CORINFO_CLASS_HANDLE clsHnd, int32_t offset, bool reverseSVarOrder);
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/interpreter/inc/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,12 @@ enum class PInvokeCallFlags : int32_t
SuppressGCTransition = 1 << 1, // The pinvoke is marked by the SuppressGCTransition attribute
};

enum class CalliFlags : int32_t
{
None = 0,
SuppressGCTransition = 1 << 1, // The call is marked by the SuppressGCTransition attribute
PInvoke = 1 << 2, // The call is a PInvoke call
PInvokeMarshalled = 1 << 3, // The call is a PInvoke call with marshaling
};

#endif
4 changes: 2 additions & 2 deletions src/coreclr/interpreter/inc/intops.def
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ OPDEF(INTOP_LDFLDA, "ldflda", 4, 1, 1, InterpOpInt)
// Calls
OPDEF(INTOP_CALL, "call", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALLDELEGATE, "call.delegate", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALLI, "calli", 5, 1, 2, InterpOpLdPtr)
OPDEF(INTOP_CALLI, "calli", 6, 1, 2, InterpOpLdPtr)
OPDEF(INTOP_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALL_PINVOKE, "call.pinvoke", 6, 1, 1, InterpOpMethodHandle) // inlined (no marshaling wrapper) pinvokes only
OPDEF(INTOP_NEWOBJ, "newobj", 5, 1, 1, InterpOpMethodHandle)
Expand All @@ -367,7 +367,7 @@ OPDEF(INTOP_NEWOBJ_VT, "newobj.vt", 5, 1, 1, InterpOpMethodHandle)

// Tail calls
OPDEF(INTOP_CALL_TAIL, "call.tail", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALLI_TAIL, "calli", 5, 1, 2, InterpOpLdPtr)
OPDEF(INTOP_CALLI_TAIL, "calli.tail", 6, 1, 2, InterpOpLdPtr)
OPDEF(INTOP_CALLVIRT_TAIL, "callvirt.tail", 4, 1, 1, InterpOpMethodHandle)

// The following helper call instructions exist in 2 variants, one for normal methods, and one for cases where a shared generic lookup is needed.
Expand Down
50 changes: 47 additions & 3 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
// Call invoker helpers provided by platform.
void InvokeManagedMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target);
void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *stack, InterpMethodContextFrame *pFrame, int32_t callArgsOffset, int32_t returnOffset, PCODE callTarget);
void InvokeCalliStub(PCODE ftn, void* stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
void InvokeCalliStub(PCODE ftn, void* cookie, int8_t *pArgs, int8_t *pRet);
void InvokePInvokeCalliStub(PCODE ftn, void *cookie, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet);
void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target);

// Use the NOINLINE to ensure that the InlinedCallFrame in this method is a lower stack address than any InterpMethodContextFrame values.
Expand Down Expand Up @@ -129,6 +130,40 @@ void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, in
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

void InvokePInvokeCalliStub(PCODE ftn, void *cookie, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet)
{
CONTRACTL
{
THROWS;
MODE_ANY;
PRECONDITION(CheckPointer((void*)ftn));
PRECONDITION(CheckPointer(cookie));
}
CONTRACTL_END

// CallStubHeaders encode their destination addresses in the Routines array, so they need to be
// copied to a local buffer before we can actually set their target address.
CallStubHeader* stubHeaderTemplate = (CallStubHeader*)cookie;
size_t templateSize = stubHeaderTemplate->GetSize();
uint8_t* actualCallStub = (uint8_t*)alloca(templateSize);
memcpy(actualCallStub, stubHeaderTemplate, templateSize);
CallStubHeader *pHeader = (CallStubHeader*)actualCallStub;
pHeader->SetTarget(ftn); // The method to call

InlinedCallFrame inlinedCallFrame;
inlinedCallFrame.m_pCallerReturnAddress = (TADDR)pFrame->ip;
inlinedCallFrame.m_pCallSiteSP = pFrame;
inlinedCallFrame.m_pCalleeSavedFP = (TADDR)stack;
inlinedCallFrame.m_pThread = GetThread();
inlinedCallFrame.m_Datum = NULL;
inlinedCallFrame.Push();
{
GCX_PREEMP();
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}
inlinedCallFrame.Pop();
}

void InvokeCalliStub(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet)
{
CONTRACTL
Expand Down Expand Up @@ -2117,15 +2152,24 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
callArgsOffset = ip[2];
int32_t calliFunctionPointerVar = ip[3];
int32_t calliCookie = ip[4];
int32_t flags = ip[5];

void* cookie = pMethod->pDataItems[calliCookie];
ip += 5;
ip += 6;

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

// Interpreter-FIXME: isTailcall
InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), cookie, stack + callArgsOffset, stack + returnOffset);
if ((flags & (int32_t)CalliFlags::PInvoke) && !(flags & (int32_t)CalliFlags::SuppressGCTransition) && !(flags & (int32_t)CalliFlags::PInvokeMarshalled))
{
InvokePInvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), cookie, stack, pFrame, stack + callArgsOffset, stack + returnOffset);
}
else
{
InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), cookie, stack + callArgsOffset, stack + returnOffset);
}

break;
}

Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/wasm/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,11 @@ void InvokeCalliStub(PCODE ftn, void* cookie, int8_t *pArgs, int8_t *pRet)
((void(*)(PCODE, int8_t*, int8_t*))cookie)(ftn, pArgs, pRet);
}

void InvokePInvokeCalliStub(PCODE ftn, void *cookie, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet)
{
PORTABILITY_ASSERT("InvokePInvokeCalliStub is not implemented on wasm");
}

void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target)
{
PORTABILITY_ASSERT("Attempted to execute non-interpreter code from interpreter on wasm, this is not yet implemented");
Expand Down
Loading