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
16 changes: 15 additions & 1 deletion src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
{
uint32_t token = getU4LittleEndian(m_ip + 1);
bool isVirtual = (*m_ip == CEE_CALLVIRT);
bool isDelegateInvoke = false;

CORINFO_RESOLVED_TOKEN resolvedCallToken;
CORINFO_CALL_INFO callInfo;
Expand Down Expand Up @@ -2758,6 +2759,11 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
}
}

if (callInfo.methodFlags & CORINFO_FLG_DELEGATE_INVOKE)
{
isDelegateInvoke = true;
}

if (callInfo.thisTransform != CORINFO_NO_THIS_TRANSFORM)
{
assert(pConstrainedToken != NULL);
Expand Down Expand Up @@ -3031,7 +3037,15 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
// before the call.
// TODO: Add null checking behavior somewhere here!
}
AddIns((isPInvoke && !isMarshaledPInvoke) ? INTOP_CALL_PINVOKE : INTOP_CALL);
if (isDelegateInvoke)
{
assert(!isPInvoke && !isMarshaledPInvoke);
AddIns(INTOP_CALLDELEGATE);
}
else
{
AddIns((isPInvoke && !isMarshaledPInvoke) ? INTOP_CALL_PINVOKE : INTOP_CALL);
}
m_pLastNewIns->data[0] = GetMethodDataItemIndex(callInfo.hMethod);
if (isPInvoke && !isMarshaledPInvoke)
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/interpreter/intops.def
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,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_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALL_PINVOKE, "call.pinvoke", 6, 1, 1, InterpOpMethodHandle) // inlined (no marshaling wrapper) pinvokes only
Expand Down
102 changes: 85 additions & 17 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,41 @@
#ifdef TARGET_WASM
void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target);
void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target);
#else
#include "callstubgenerator.h"

CallStubHeader *UpdateCallStubForMethod(MethodDesc *pMD)
{
CONTRACTL
{
THROWS;
MODE_ANY;
PRECONDITION(CheckPointer(pMD));
}
CONTRACTL_END

GCX_PREEMP();

CallStubGenerator callStubGenerator;

AllocMemTracker amTracker;
CallStubHeader *header = callStubGenerator.GenerateCallStub(pMD, &amTracker, true /* interpreterToNative */);

if (pMD->SetCallStub(header))
{
amTracker.SuppressRelease();
}
else
{
// We have lost the race for generating the header, use the one that was generated by another thread
// and let the amTracker release the memory of the one we generated.
header = pMD->GetCallStub();
}

return header;
}

void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target)
{
CONTRACTL
Expand All @@ -32,22 +64,7 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE ta
CallStubHeader *pHeader = pMD->GetCallStub();
if (pHeader == NULL)
{
CallStubGenerator callStubGenerator;
GCX_PREEMP();

AllocMemTracker amTracker;
pHeader = callStubGenerator.GenerateCallStub(pMD, &amTracker, true /* interpreterToNative */);

if (pMD->SetCallStub(pHeader))
{
amTracker.SuppressRelease();
}
else
{
// We have lost the race for generating the header, use the one that was generated by another thread
// and let the amTracker release the memory of the one we generated.
pHeader = pMD->GetCallStub();
}
pHeader = UpdateCallStubForMethod(pMD);
}

// Interpreter-FIXME: Potential race condition if a single CallStubHeader is reused for multiple targets.
Expand All @@ -56,6 +73,34 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE ta
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

void InvokeDelegateInvokeMethod(MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target)
{
CONTRACTL
{
THROWS;
MODE_ANY;
PRECONDITION(CheckPointer(pMDDelegateInvoke));
PRECONDITION(CheckPointer(pArgs));
PRECONDITION(CheckPointer(pRet));
}
CONTRACTL_END

CallStubHeader *stubHeaderTemplate = pMDDelegateInvoke->GetCallStub();
if (stubHeaderTemplate == NULL)
{
stubHeaderTemplate = UpdateCallStubForMethod(pMDDelegateInvoke);
}

// 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.
size_t templateSize = stubHeaderTemplate->GetSize();
uint8_t* actualCallStub = (uint8_t*)alloca(templateSize);
memcpy(actualCallStub, stubHeaderTemplate, templateSize);
CallStubHeader *pHeader = (CallStubHeader*)actualCallStub;
pHeader->SetTarget(target); // The method to call
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

void InvokeCalliStub(PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet)
{
CONTRACTL
Expand Down Expand Up @@ -84,7 +129,6 @@ CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod)
CallStubHeader *pHeader = VolatileLoadWithoutBarrier(&pInterpMethod->pCallStub);
GCX_PREEMP();

AllocMemTracker amTracker;
if (pHeader == NULL)
{
// Ensure that there is an interpreter thread context instance and thus an interpreter stack
Expand Down Expand Up @@ -1881,6 +1925,30 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
break;
}

case INTOP_CALLDELEGATE:
{
returnOffset = ip[1];
callArgsOffset = ip[2];
methodSlot = ip[3];

// targetMethod holds a pointer to the Invoke method of the delegate, not the final actual target.
targetMethod = (MethodDesc*)pMethod->pDataItems[methodSlot];

ip += 4;

DELEGATEREF delegateObj = LOCAL_VAR(callArgsOffset, DELEGATEREF);
NULL_CHECK(delegateObj);
PCODE targetAddress = delegateObj->GetMethodPtr();
OBJECTREF targetMethodObj = delegateObj->GetTarget();
LOCAL_VAR(callArgsOffset, OBJECTREF) = targetMethodObj;

// TODO! Once we are investigating performance here, we may want to optimize this so that
// delegate calls to interpeted methods don't have to go through the native invoke here, but for
// now this should work well.
InvokeDelegateInvokeMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, targetAddress);
break;
}

case INTOP_CALL:
{
returnOffset = ip[1];
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 @@ -487,3 +487,8 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE ta
{
PORTABILITY_ASSERT("Attempted to execute non-interpreter code 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");
}
Loading