Repository: dotnet/runtime
File: src/coreclr/jit/lower.cpp (C++)

Code before:
        thisExpr = thisExprUse.Def(); // it's changed; reload it.
    }

    // replace original expression feeding into thisPtr with
    // [originalThis + offsetOfDelegateInstance]

    GenTree* newThisAddr = new (m_compiler, GT_LEA)
        GenTreeAddrMode(TYP_BYREF, thisExpr, nullptr, 0, m_compiler->eeGetEEInfo()->offsetOfDelegateInstance);

    GenTree* newThis = m_compiler->gtNewIndir(TYP_REF, newThisAddr);

    // Insert the new 'this' arg right before the call to get the correct null
    // behavior (the NRE that would logically happen inside Delegate.Invoke
    // should happen after all args are evaluated). We must also move the
    // PUTARG_REG node ahead.
#if HAS_FIXED_REGISTER_SET
    thisArgNode->AsOp()->gtOp1 = newThis;
#endif

    BlockRange().Remove(thisArgNode);
    BlockRange().InsertBefore(call, newThisAddr, newThis, thisArgNode);

    ContainCheckIndir(newThis->AsIndir());

    // the control target is
    // [originalThis + firstTgtOffs]

    unsigned targetOffs = m_compiler->eeGetEEInfo()->offsetOfDelegateFirstTarget;
    GenTree* result     = new (m_compiler, GT_LEA) GenTreeAddrMode(TYP_REF, base, nullptr, 0, targetOffs);
    GenTree* callTarget = Ind(result);

    // don't need to sequence and insert this tree, caller will do it

    return callTarget;
}

//------------------------------------------------------------------------
// OptimizeCallIndirectTargetEvaluation:
//   Try to optimize the evaluation of the indirect call target to happen
//   before arguments, if possible.
//
// Parameters:
//   call - Call node
//
void Lowering::OptimizeCallIndirectTargetEvaluation(GenTreeCall* call)
{
    assert((call->gtCallType == CT_INDIRECT) && (call->gtCallAddr != nullptr));

    if (!call->gtCallAddr->IsCall())
    {
        return;

Review comment (suggestion):
I think there are still issues here if I am reading things correctly.

We're replacing the old `this` with ` [this + offsetOfDelegateInstance]` (`newThis`). But here we don't reconnect this `newThis` to the call, it stays being the local we (possibly) replaced it with above.

Furthermore, once that is fixed (via e. g. `thisExprUse.ReplaceWith`), we will be repositioning `thisArgNode`, which is still the old `this` node that we made an operand of a `STORE_LCL_VAR`, now behind it (use-before-def).

Code after:
        base = m_compiler->gtNewLclFldNode(thisExpr->AsLclFld()->GetLclNum(), thisExpr->TypeGet(),
                                           thisExpr->AsLclFld()->GetLclOffs());
    }
    else
    {
        unsigned delegateInvokeTmp = m_compiler->lvaGrabTemp(true DEBUGARG("delegate invoke call"));
        base                       = m_compiler->gtNewLclvNode(delegateInvokeTmp, thisExpr->TypeGet());

        ReplaceWithLclVar(thisExprUse, delegateInvokeTmp);
        thisExpr = thisExprUse.Def(); // it's changed; reload it.
    }

    // replace original expression feeding into thisPtr with
    // [originalThis + offsetOfDelegateInstance]

    GenTree* newThisAddr = new (m_compiler, GT_LEA)
        GenTreeAddrMode(TYP_BYREF, thisExpr, nullptr, 0, m_compiler->eeGetEEInfo()->offsetOfDelegateInstance);

    GenTree* newThis = m_compiler->gtNewIndir(TYP_REF, newThisAddr);

    // Insert the new 'this' arg right before the call to get the correct null
    // behavior (the NRE that would logically happen inside Delegate.Invoke
    // should happen after all args are evaluated). We must also move the
    // PUTARG_REG node ahead.
#if HAS_FIXED_REGISTER_SET
    thisArgNode->AsOp()->gtOp1 = newThis;
    BlockRange().Remove(thisArgNode);
    BlockRange().InsertBefore(call, newThisAddr, newThis, thisArgNode);
#else
    thisExprUse.ReplaceWith(newThis);
    BlockRange().Remove(thisExpr);
    BlockRange().InsertBefore(call, thisExpr, newThisAddr, newThis);
#endif

    ContainCheckIndir(newThis->AsIndir());

    // the control target is
    // [originalThis + firstTgtOffs]

    unsigned targetOffs = m_compiler->eeGetEEInfo()->offsetOfDelegateFirstTarget;
    GenTree* result     = new (m_compiler, GT_LEA) GenTreeAddrMode(TYP_REF, base, nullptr, 0, targetOffs);
    GenTree* callTarget = Ind(result);

    // don't need to sequence and insert this tree, caller will do it

    return callTarget;
}

//------------------------------------------------------------------------
// OptimizeCallIndirectTargetEvaluation:
//   Try to optimize the evaluation of the indirect call target to happen