in ProfilingAPI/ReJITEnterLeaveHooks/ILRewriter.cpp [766:817]
HRESULT AddExitProbe(
ILRewriter * pilr,
FunctionID functionId,
UINT_PTR methodAddress,
ULONG32 methodSignature)
{
HRESULT hr;
BOOL fAtLeastOneProbeAdded = FALSE;
// Find all RETs, and insert a call to the exit probe before each one.
for (ILInstr * pInstr = pilr->GetILList()->m_pNext; pInstr != pilr->GetILList(); pInstr = pInstr->m_pNext)
{
switch (pInstr->m_opcode)
{
case CEE_RET:
{
// We want any branches or leaves that targeted the RET instruction to
// actually target the epilog instructions we're adding. So turn the "RET"
// into ["NOP", "RET"], and THEN add the epilog between the NOP & RET. That
// ensures that any branches that went to the RET will now go to the NOP and
// then execute our epilog.
// NOTE: The NOP is not strictly required, but is a simplification of the implementation.
// RET->NOP
pInstr->m_opcode = CEE_NOP;
// Add the new RET after
ILInstr * pNewRet = pilr->NewILInstr();
pNewRet->m_opcode = CEE_RET;
pilr->InsertAfter(pInstr, pNewRet);
// Add now insert the epilog before the new RET
hr = AddProbe(pilr, functionId, methodAddress, methodSignature, pNewRet);
if (FAILED(hr))
return hr;
fAtLeastOneProbeAdded = TRUE;
// Advance pInstr after all this gunk so the for loop continues properly
pInstr = pNewRet;
break;
}
default:
break;
}
}
if (!fAtLeastOneProbeAdded)
return E_FAIL;
return S_OK;
}