Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 24 additions & 9 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2854,6 +2854,27 @@ 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;
CorInfoCallConv callConv = (CorInfoCallConv)(callSiteSig->callConv & IMAGE_CEE_CS_CALLCONV_MASK);
bool isPInvoke = (callConv != CORINFO_CALLCONV_DEFAULT && callConv != CORINFO_CALLCONV_VARARG);
if (isPInvoke)
{
if (m_compHnd->pInvokeMarshalingRequired(NULL, callSiteSig))
{
BADCODE("PInvoke marshalling for calli is not supported in interpreted code");
}
m_compHnd->getUnmanagedCallConv(nullptr, callSiteSig, &suppressGCTransition);
}
m_pLastNewIns->data[1] = (suppressGCTransition ? (int32_t)CalliFlags::SuppressGCTransition : 0) |
(isPInvoke ? (int32_t)CalliFlags::PInvoke : 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 +3280,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 +3337,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 +3370,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
7 changes: 7 additions & 0 deletions src/coreclr/interpreter/inc/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,11 @@ 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
};

#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
86 changes: 76 additions & 10 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@

// 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 InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *pArgs, int8_t *pRet, PCODE callTarget);
void InvokeCalliStub(PCODE ftn, void* cookie, int8_t *pArgs, int8_t *pRet);
void InvokeUnmanagedCalli(PCODE ftn, void *cookie, 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.
NOINLINE
void InvokeUnmanagedMethodWithTransition(MethodDesc *targetMethod, int8_t *stack, InterpMethodContextFrame *pFrame, int32_t callArgsOffset, int32_t returnOffset, PCODE callTarget)
void InvokeUnmanagedMethodWithTransition(MethodDesc *targetMethod, int8_t *stack, InterpMethodContextFrame *pFrame, int8_t *pArgs, int8_t *pRet, PCODE callTarget)
{
InlinedCallFrame inlinedCallFrame;
inlinedCallFrame.m_pCallerReturnAddress = (TADDR)pFrame->ip;
Expand All @@ -32,12 +33,38 @@ void InvokeUnmanagedMethodWithTransition(MethodDesc *targetMethod, int8_t *stack
{
GCX_PREEMP();
// WASM-TODO: Handle unmanaged calling conventions
InvokeManagedMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, callTarget);
InvokeManagedMethod(targetMethod, pArgs, pRet, callTarget);
}

inlinedCallFrame.Pop();
}

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

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();
InvokeUnmanagedCalli(ftn, cookie, pArgs, pRet);
}
inlinedCallFrame.Pop();
}

#ifndef TARGET_WASM
#include "callstubgenerator.h"

Expand Down Expand Up @@ -96,9 +123,9 @@ void InvokeManagedMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE tar
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *stack, InterpMethodContextFrame *pFrame, int32_t callArgsOffset, int32_t returnOffset, PCODE callTarget)
void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *pArgs, int8_t *pRet, PCODE callTarget)
{
InvokeManagedMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, callTarget);
InvokeManagedMethod(targetMethod, pArgs, pRet, callTarget);
}

void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target)
Expand Down Expand Up @@ -129,6 +156,29 @@ void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, in
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

void InvokeUnmanagedCalli(PCODE ftn, void *cookie, 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

pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

void InvokeCalliStub(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet)
{
CONTRACTL
Expand Down Expand Up @@ -2117,15 +2167,31 @@ 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)
{
if (flags & (int32_t)CalliFlags::SuppressGCTransition)
{
InvokeUnmanagedCalli(LOCAL_VAR(calliFunctionPointerVar, PCODE), cookie, stack + callArgsOffset, stack + returnOffset);
}
else
{
InvokeUnmanagedCalliWithTransition(LOCAL_VAR(calliFunctionPointerVar, PCODE), cookie, stack, pFrame, stack + callArgsOffset, stack + returnOffset);
}
}
else
{
InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), cookie, stack + callArgsOffset, stack + returnOffset);
}

break;
}

Expand All @@ -2152,11 +2218,11 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr

if (flags & (int32_t)PInvokeCallFlags::SuppressGCTransition)
{
InvokeUnmanagedMethod(targetMethod, stack, pFrame, callArgsOffset, returnOffset, callTarget);
InvokeUnmanagedMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, callTarget);
}
else
{
InvokeUnmanagedMethodWithTransition(targetMethod, stack, pFrame, callArgsOffset, returnOffset, callTarget);
InvokeUnmanagedMethodWithTransition(targetMethod, stack, pFrame, stack + callArgsOffset, stack + returnOffset, callTarget);
}

break;
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/vm/wasm/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ void InvokeManagedMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE tar
PORTABILITY_ASSERT("Attempted to execute non-interpreter code from interpreter on wasm, this is not yet implemented");
}

void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *stack, InterpMethodContextFrame *pFrame, int32_t callArgsOffset, int32_t returnOffset, PCODE callTarget)
void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *pArgs, int8_t *pRet, PCODE callTarget)
{
PORTABILITY_ASSERT("Attempted to execute unmanaged code from interpreter on wasm, this is not yet implemented");
}
Expand All @@ -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 InvokeUnmanagedCalli(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet)
{
PORTABILITY_ASSERT("Attempted to execute unmanaged calli from interpreter on wasm, this is not yet implemented");
}

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