Repository: dotnet/runtime
File: src/coreclr/vm/interpexec.cpp (C++)

Code before:
                    // slots containing the interpreter IR pointer
                    targetMethod = pMD->GetMethodDescOfVirtualizedCode(pThisArg, pMD->GetMethodTable());
                    ip += 4;
                    goto CALL_INTERP_METHOD;
                }

                case INTOP_CALLI_TAIL:
                case INTOP_CALLI:
                {
                    isTailcall = (*ip == INTOP_CALLI_TAIL);
                    returnOffset = ip[1];
                    callArgsOffset = ip[2];
                    int32_t calliFunctionPointerVar = ip[3];
                    int32_t calliCookie = ip[4];
                    bool isPInvoke = ip[5] != 0;

                    CallStubHeader *pCallStub = (CallStubHeader*)pMethod->pDataItems[calliCookie];
                    ip += 6;

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

                    // Interpreter-FIXME: isTailcall
                    if (isPInvoke)
                    {
                        InvokePInvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack, pFrame, stack + callArgsOffset, stack + returnOffset);
                    }
                    else
                    {
                        InvokeCalliStub(LOCAL_VAR(calliFunctionPointerVar, PCODE), pCallStub, stack + callArgsOffset, stack + returnOffset);
                    }

                    break;
                }

                case INTOP_CALL_PINVOKE:
                {
                    // This opcode handles p/invokes that don't use a managed wrapper for marshaling. These
                    //  calls are special in that they need an InlinedCallFrame in order for proper EH to happen

                    isTailcall = false;
                    returnOffset = ip[1];
                    callArgsOffset = ip[2];
                    methodSlot = ip[3];
                    int32_t targetAddrSlot = ip[4];
                    int32_t flags = ip[5];

                    ip += 6;
                    targetMethod = (MethodDesc*)pMethod->pDataItems[methodSlot];
                    PCODE callTarget = (flags & (int32_t)PInvokeCallFlags::Indirect)
                        ? *(PCODE *)pMethod->pDataItems[targetAddrSlot]

Review comment (suggestion):
This is still leaving number of holes behind:

- When any of the arguments need marshalling (pInvokeMarshalingRequired returns true). unmanaged calli needs to go through marshalling stub.
- It needs to respect the unmanaged calling convention returned by `getUnmanagedCallConv`. I expect that we will want to support SwiftCalling convention.
- If the calling convention includes SuppressGCTransition, InlineMethodFrame and GCX_PREEMP should be skipped.

Code after:
                        returnOffset = ip[1];
                        int stackOffset = pMethod->allocaSize;
                        callArgsOffset = stackOffset;

                        // Pass arguments to the target method
                        LOCAL_VAR(stackOffset, void*) = helperArg1;
                        LOCAL_VAR(stackOffset + INTERP_STACK_SLOT_SIZE, void*) = helperArg2;

                        targetMethod = pILTargetMethod;
                        ip += 5;
                        goto CALL_INTERP_METHOD;
                    }

                    _ASSERTE(helperFtn != NULL);
                    LOCAL_VAR(ip[1], void*) = helperFtn(helperArg1, helperArg2);
                    ip += 5;
                    break;
                }

                case INTOP_CALL_HELPER_P_SP:
                {
                    HELPER_FTN_P_PP helperFtn = GetPossiblyIndirectHelper<HELPER_FTN_P_PP>(pMethod, ip[3]);
                    void* helperArg = pMethod->pDataItems[ip[4]];

                    LOCAL_VAR(ip[1], void*) = helperFtn(LOCAL_VAR(ip[2], void*), helperArg);
                    ip += 5;
                    break;
                }

                case INTOP_CALL_HELPER_P_G:
                {
                    InterpGenericLookup *pLookup = (InterpGenericLookup*)&pMethod->pDataItems[ip[4]];
                    void* helperArg = DoGenericLookup(LOCAL_VAR(ip[2], void*), pLookup);

                    MethodDesc *pILTargetMethod = NULL;
                    HELPER_FTN_P_P helperFtn = GetPossiblyIndirectHelper<HELPER_FTN_P_P>(pMethod, ip[3], &pILTargetMethod);
                    if (pILTargetMethod != NULL)
                    {
                        returnOffset = ip[1];
                        int stackOffset = pMethod->allocaSize;
                        callArgsOffset = stackOffset;

                        // Pass argument to the target method
                        LOCAL_VAR(stackOffset, void*) = helperArg;

                        targetMethod = pILTargetMethod;
                        ip += 5;
                        goto CALL_INTERP_METHOD;
                    }

                    _ASSERTE(helperFtn != NULL);