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

Code before:
    else if (callerSig->retType == CORINFO_TYPE_VALUECLASS && callerSig->retTypeClass != calleeSig->retTypeClass)
    {
        return true;
    }
    if (callerSig->isAsyncCall())
    {
        // Disallow tail calls from async methods for now
        return true;
    }
    return false;
}

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))
        {
            // If we remove this restriction, we should handle the track transitions scenario by forcing a 
            // p/invoke marshaling calli stub even when needed.
            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::EmitCanAccessCallout(CORINFO_RESOLVED_TOKEN *pResolvedToken)
{
    CORINFO_HELPER_DESC calloutHelper;
    CorInfoIsAccessAllowedResult accessAllowed =
        m_compHnd->canAccessClass(pResolvedToken, m_methodHnd, &calloutHelper);

    // Inject call to callsite callout helper
    EmitCallsiteCallout(accessAllowed, &calloutHelper);
}

void InterpCompiler::EmitCallsiteCallout(CorInfoIsAccessAllowedResult accessAllowed, CORINFO_HELPER_DESC* calloutDesc)
{
    if (accessAllowed == CORINFO_ACCESS_ILLEGAL)
    {
        int32_t svars[CORINFO_ACCESS_ALLOWED_MAX_ARGS];


Review comment (suggestion):
There is a grammatical issue in the comment. The phrase "even when needed" should be clarified. Did you mean "even when not needed" or should this say something else? The logic seems inverted.
```suggestion
            // p/invoke marshaling calli stub even when not needed.
```

Code after:
    else if (callerSig->retType == CORINFO_TYPE_VALUECLASS && callerSig->retTypeClass != calleeSig->retTypeClass)
    {
        return true;
    }
    if (callerSig->isAsyncCall())
    {
        // Disallow tail calls from async methods for now
        return true;
    }
    return false;
}

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))
        {
            // If we remove this restriction, we should handle the track transitions scenario by forcing a 
            // p/invoke marshaling calli stub even when not needed.
            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::EmitCanAccessCallout(CORINFO_RESOLVED_TOKEN *pResolvedToken)
{
    CORINFO_HELPER_DESC calloutHelper;
    CorInfoIsAccessAllowedResult accessAllowed =
        m_compHnd->canAccessClass(pResolvedToken, m_methodHnd, &calloutHelper);

    // Inject call to callsite callout helper
    EmitCallsiteCallout(accessAllowed, &calloutHelper);
}

void InterpCompiler::EmitCallsiteCallout(CorInfoIsAccessAllowedResult accessAllowed, CORINFO_HELPER_DESC* calloutDesc)
{
    if (accessAllowed == CORINFO_ACCESS_ILLEGAL)
    {
        int32_t svars[CORINFO_ACCESS_ALLOWED_MAX_ARGS];