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

Code before:
            EmitPushCORINFO_LOOKUP(callInfo.codePointerLookup);
            m_pStackPointer--;
            int codePointerLookupResult = m_pStackPointer[0].var;

            calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);

            EmitCalli(tailcall, calliCookie, codePointerLookupResult, &callInfo.sig);

            // These calli calls cannot be pinvoke calls. (If we want to add that, we need to set the noCallArgs flag)
            assert(!((m_pLastNewIns->data[1] & (int32_t)CalliFlags::PInvoke) != 0));
            break;
        }
        case CORINFO_VIRTUALCALL_VTABLE:
        {
            // Traditional virtual call. In theory we could optimize this to using the vtable
            AddIns(tailcall ? INTOP_CALLVIRT_TAIL : INTOP_CALLVIRT);
            m_pLastNewIns->data[0] = GetDataItemIndex(callInfo.hMethod);
            // Reserved slots for caching DispatchToken and its hash
            m_pLastNewIns->data[1] = GetNewDataItemIndex(nullptr);
            int32_t secondCache = GetNewDataItemIndex(nullptr);
#ifdef DEBUG
            assert(secondCache == (m_pLastNewIns->data[1] + 1));
#endif
            break;
        }
        case CORINFO_VIRTUALCALL_LDVIRTFTN:
            if ((callInfo.sig.sigInst.methInstCount != 0) || (m_compHnd->getClassAttribs(m_compHnd->getMethodClass(callInfo.hMethod)) & CORINFO_FLG_SHAREDINST))
            {
                assert(extraParamArgLocation == INT_MAX);
                // We should not have a type argument for the ldvirtftn path since we don't know
                // the exact method to call until the ldvirtftn is resolved, and that only
                // produces a function pointer.

                // We need to copy the this argument to the target function to another var,
                // since var's which are passed to call instructions are destroyed (unless
                // they are global, and there is no reason to promote the this arg to a global)
                AddIns(INTOP_MOV_P);
                m_pLastNewIns->SetSVar(callArgs[0]);
                PushInterpType(InterpTypeO, NULL);
                m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
                int thisVarForLdvirtftn = m_pStackPointer[-1].var;
                m_pStackPointer--;

                EmitPushLdvirtftn(thisVarForLdvirtftn, &resolvedCallToken, &callInfo);
                m_pStackPointer--;
                int synthesizedLdvirtftnPtrVar = m_pStackPointer[0].var;

                calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);

                EmitCalli(tailcall, calliCookie, synthesizedLdvirtftnPtrVar, &callInfo.sig);
            }

Review comment (bug):
The variable 'secondCache' is assigned but never used. It appears to exist solely for the DEBUG assertion on line 5190 to verify that consecutive GetNewDataItemIndex calls return sequential indices. Consider using (void)secondCache; or UNUSED(secondCache); to explicitly indicate this is intentional, or remove the variable and directly assert on a second call if the assertion is important.

Code after:
                m_pLastNewIns->SetSVar(callArgs[0]);
            }

            EmitPushCORINFO_LOOKUP(callInfo.codePointerLookup);
            m_pStackPointer--;
            int codePointerLookupResult = m_pStackPointer[0].var;

            calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);

            EmitCalli(tailcall, calliCookie, codePointerLookupResult, &callInfo.sig);

            // These calli calls cannot be pinvoke calls. (If we want to add that, we need to set the noCallArgs flag)
            assert(!((m_pLastNewIns->data[1] & (int32_t)CalliFlags::PInvoke) != 0));
            break;
        }
        case CORINFO_VIRTUALCALL_VTABLE:
        {
            // Traditional virtual call. In theory we could optimize this to using the vtable
            AddIns(tailcall ? INTOP_CALLVIRT_TAIL : INTOP_CALLVIRT);
            m_pLastNewIns->data[0] = GetDataItemIndex(callInfo.hMethod);
            // Reserved slots for caching DispatchToken and its hash
            m_pLastNewIns->data[1] = GetNewDataItemIndex(nullptr);
            int32_t secondCache = GetNewDataItemIndex(nullptr);
#ifdef DEBUG
            assert(secondCache == (m_pLastNewIns->data[1] + 1));
#endif
            break;
        }
        case CORINFO_VIRTUALCALL_LDVIRTFTN:
            if ((callInfo.sig.sigInst.methInstCount != 0) || (m_compHnd->getClassAttribs(m_compHnd->getMethodClass(callInfo.hMethod)) & CORINFO_FLG_SHAREDINST))
            {
                assert(extraParamArgLocation == INT_MAX);
                // We should not have a type argument for the ldvirtftn path since we don't know
                // the exact method to call until the ldvirtftn is resolved, and that only
                // produces a function pointer.

                // We need to copy the this argument to the target function to another var,
                // since var's which are passed to call instructions are destroyed (unless
                // they are global, and there is no reason to promote the this arg to a global)
                AddIns(INTOP_MOV_P);
                m_pLastNewIns->SetSVar(callArgs[0]);
                PushInterpType(InterpTypeO, NULL);
                m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
                int thisVarForLdvirtftn = m_pStackPointer[-1].var;
                m_pStackPointer--;

                EmitPushLdvirtftn(thisVarForLdvirtftn, &resolvedCallToken, &callInfo);
                m_pStackPointer--;
                int synthesizedLdvirtftnPtrVar = m_pStackPointer[0].var;

                calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);