Repository: dotnet/runtime
File: src/coreclr/interpreter/compiler.cpp (C++)

Code before:
    assert(getVirtualFunctionPtrHelper != NULL);

    PushInterpType(InterpTypeI, NULL);
    int32_t dVar = m_pStackPointer[-1].var;

    int *callArgs = (int*) AllocMemPool((3 + 1) * sizeof(int));
    callArgs[0] = thisVar;
    callArgs[1] = typeVar;
    callArgs[2] = methodVar;
    callArgs[3] = CALL_ARGS_TERMINATOR;

    AddIns(INTOP_CALL);
    m_pLastNewIns->data[0] = GetMethodDataItemIndex(getVirtualFunctionPtrHelper);
    m_pLastNewIns->SetDVar(dVar);
    m_pLastNewIns->SetSVar(CALL_ARGS_SVAR);
    m_pLastNewIns->flags |= INTERP_INST_FLAG_CALL;
    m_pLastNewIns->info.pCallInfo = (InterpCallInfo*)AllocMemPool0(sizeof (InterpCallInfo));
    m_pLastNewIns->info.pCallInfo->pCallArgs = callArgs;
}

void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunctionPointerVar, CorInfoCallConv callConv)
{
    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
    m_pLastNewIns->data[1] = (callConv == CORINFO_CALLCONV_DEFAULT || callConv == CORINFO_CALLCONV_VARARG) ? 0 : 1;
    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);
    bool isVirtual = (*m_ip == CEE_CALLVIRT);
    bool isDelegateInvoke = false;

    CORINFO_RESOLVED_TOKEN resolvedCallToken;
    CORINFO_CALL_INFO callInfo;
    bool doCallInsteadOfNew = false;

    int callIFunctionPointerVar = -1;
    void* calliCookie = NULL;

    if (isCalli)
    {
        // Suppress uninitialized use warning.
        memset(&resolvedCallToken, 0, sizeof(resolvedCallToken));
        memset(&callInfo, 0, sizeof(callInfo));

        resolvedCallToken.token        = token;
        resolvedCallToken.tokenContext = METHOD_BEING_COMPILED_CONTEXT();

Review comment (suggestion):
The logic for determining if a call is a PInvoke based on calling convention uses a hardcoded condition that may not cover all managed calling conventions. Consider using a more explicit check or adding a comment explaining why these specific conventions indicate managed calls.
```suggestion
// Returns true if the calling convention is managed (.NET), false if it is unmanaged (PInvoke).
static bool IsManagedCallConv(CorInfoCallConv callConv)
{
    // Managed calling conventions in .NET are typically DEFAULT and VARARG.
    // If new managed conventions are added, update this function accordingly.
    // See: https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/corinfo.h
    return (callConv == CORINFO_CALLCONV_DEFAULT || callConv == CORINFO_CALLCONV_VARARG);
}

void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunctionPointerVar, CorInfoCallConv callConv)
{
    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 (unmanaged), 0 otherwise (managed)
    m_pLastNewIns->data[1] = IsManagedCallConv(callConv) ? 0 : 1;
```

Code after:
    m_pStackPointer--;

    GenericHandleData handleData = GenericHandleToGenericHandleData(embedInfo);

    if (handleData.argType == HelperArgType::GenericResolution)
    {
        AddIns(INTOP_GENERICLOOKUP);
        m_pLastNewIns->data[0] = handleData.dataItemIndex;

        m_pLastNewIns->SetSVar(handleData.genericVar);
        m_pLastNewIns->SetDVar(resultVar);
    }
    else
    {
        AddIns(INTOP_LDPTR);
        m_pLastNewIns->data[0] = handleData.dataItemIndex;

        m_pLastNewIns->SetDVar(resultVar);
    }

    return resultVar;
}

void InterpCompiler::EmitPushLdvirtftn(int thisVar, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo)
{
    const bool isInterface = (pCallInfo->classFlags & CORINFO_FLG_INTERFACE) == CORINFO_FLG_INTERFACE;

    if ((pCallInfo->methodFlags & CORINFO_FLG_EnC) && !isInterface)
    {
        NO_WAY("Virtual call to a function added via EnC is not supported");
    }

    // Get the exact descriptor for the static callsite
    CORINFO_GENERICHANDLE_RESULT embedInfo;
    m_compHnd->embedGenericHandle(pResolvedToken, true, m_methodInfo->ftn, &embedInfo);
    assert(embedInfo.compileTimeHandle != NULL);
    int typeVar = EmitGenericHandleAsVar(embedInfo);

    m_compHnd->embedGenericHandle(pResolvedToken, false, m_methodInfo->ftn, &embedInfo);
    assert(embedInfo.compileTimeHandle != NULL);
    int methodVar = EmitGenericHandleAsVar(embedInfo);

    CORINFO_METHOD_HANDLE getVirtualFunctionPtrHelper;
    m_compHnd->getHelperFtn(CORINFO_HELP_VIRTUAL_FUNC_PTR, NULL, &getVirtualFunctionPtrHelper);
    assert(getVirtualFunctionPtrHelper != NULL);

    PushInterpType(InterpTypeI, NULL);
    int32_t dVar = m_pStackPointer[-1].var;

    int *callArgs = (int*) AllocMemPool((3 + 1) * sizeof(int));
    callArgs[0] = thisVar;