diff options
Diffstat (limited to 'src/vm/arm/profiler.cpp')
-rw-r--r-- | src/vm/arm/profiler.cpp | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/src/vm/arm/profiler.cpp b/src/vm/arm/profiler.cpp new file mode 100644 index 0000000000..d7ddd5ca7c --- /dev/null +++ b/src/vm/arm/profiler.cpp @@ -0,0 +1,358 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// FILE: profiler.cpp +// + +// + +// +// ====================================================================================== + +#include "common.h" + +#ifdef PROFILING_SUPPORTED +#include "proftoeeinterfaceimpl.h" + +MethodDesc *FunctionIdToMethodDesc(FunctionID functionID); + +// TODO: move these to some common.h file +// FLAGS +#define PROFILE_ENTER 0x1 +#define PROFILE_LEAVE 0x2 +#define PROFILE_TAILCALL 0x4 + +typedef struct _PROFILE_PLATFORM_SPECIFIC_DATA +{ + UINT32 r0; // Keep r0 & r1 contiguous to make returning 64-bit results easier + UINT32 r1; + void *R11; + void *Pc; + union // Float arg registers as 32-bit (s0-s15) and 64-bit (d0-d7) + { + UINT32 s[16]; + UINT64 d[8]; + }; + FunctionID functionId; + void *probeSp; // stack pointer of managed function + void *profiledSp; // location of arguments on stack + LPVOID hiddenArg; + UINT32 flags; +} PROFILE_PLATFORM_SPECIFIC_DATA, *PPROFILE_PLATFORM_SPECIFIC_DATA; + + +/* + * ProfileGetIPFromPlatformSpecificHandle + * + * This routine takes the platformSpecificHandle and retrieves from it the + * IP value. + * + * Parameters: + * handle - the platformSpecificHandle passed to ProfileEnter/Leave/Tailcall + * + * Returns: + * The IP value stored in the handle. + */ +UINT_PTR ProfileGetIPFromPlatformSpecificHandle(void *handle) +{ + LIMITED_METHOD_CONTRACT; + + PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)handle; + return (UINT_PTR)pData->Pc; +} + + +/* + * ProfileSetFunctionIDInPlatformSpecificHandle + * + * This routine takes the platformSpecificHandle and functionID, and assign + * functionID to functionID field of platformSpecificHandle. + * + * Parameters: + * pPlatformSpecificHandle - the platformSpecificHandle passed to ProfileEnter/Leave/Tailcall + * functionID - the FunctionID to be assigned + * + * Returns: + * None + */ +void ProfileSetFunctionIDInPlatformSpecificHandle(void * pPlatformSpecificHandle, FunctionID functionID) +{ + LIMITED_METHOD_CONTRACT; + _ASSERTE(pPlatformSpecificHandle != NULL); + _ASSERTE(functionID != NULL); + + PROFILE_PLATFORM_SPECIFIC_DATA * pData = reinterpret_cast<PROFILE_PLATFORM_SPECIFIC_DATA *>(pPlatformSpecificHandle); + pData->functionId = functionID; +} + +/* + * ProfileArgIterator::ProfileArgIterator + * + * Constructor. Does almost nothing. Init must be called after construction. + * + */ +ProfileArgIterator::ProfileArgIterator(MetaSig * pSig, void * platformSpecificHandle) + : m_argIterator(pSig) +{ + WRAPPER_NO_CONTRACT; + + _ASSERTE(pSig != NULL); + _ASSERTE(platformSpecificHandle != NULL); + + m_handle = platformSpecificHandle; + PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)m_handle; + + // unwind a frame and get the SP for the profiled method to make sure it matches + // what the JIT gave us +#ifdef _DEBUG + { +/* + Foo() { + Bar(); + } + +Stack for the above call will look as follows (stack growing downwards): + + | + | Stack Args for Foo | + | pre spill r0-r3 | + | LR | + | R11 | + | Locals of Foo | + | Stack Args for Bar | + | pre spill r0-r3 | __________this Sp value is saved in profiledSP + | LR | + | R11 | + | Satck saved in prolog of Bar | _______ call to profiler hook is made here_____this Sp value is saved in probeSP + | | + + +*/ + + // setup the context to represent the frame that called ProfileEnterNaked + CONTEXT ctx; + memset(&ctx, 0, sizeof(CONTEXT)); + ctx.Sp = (UINT)pData->probeSp; + ctx.R11 = (UINT)pData->R11; + ctx.Pc = (UINT)pData->Pc; + // For some functions which do localloc, sp is saved in r9. In order to perform unwinding for functions r9 must be set in the context. + // r9 is stored at offset (sizeof(PROFILE_PLATFORM_SPECIFIC_DATA) (this also includes the padding done for 8-byte stack alignement) + size required for (r0,r3)) bytes from pData + ctx.R9 = *((UINT*)pData + (sizeof(PROFILE_PLATFORM_SPECIFIC_DATA) + 8)/4); + + // walk up a frame to the caller frame (called the managed method which + // called ProfileEnterNaked) + Thread::VirtualUnwindCallFrame(&ctx); + + // add the prespill register(r0-r3) size to get the stack pointer of previous function + _ASSERTE(pData->profiledSp == (void*)(ctx.Sp - 4*4)); + } +#endif // _DEBUG + + // Get the hidden arg if there is one + MethodDesc * pMD = FunctionIdToMethodDesc(pData->functionId); + + if ( (pData->hiddenArg == NULL) && + (pMD->RequiresInstArg() || pMD->AcquiresInstMethodTableFromThis()) ) + { + // In the enter probe, the JIT may not have pushed the generics token onto the stack yet. + // Luckily, we can inspect the registers reliably at this point. + if (pData->flags & PROFILE_ENTER) + { + _ASSERTE(!((pData->flags & PROFILE_LEAVE) || (pData->flags & PROFILE_TAILCALL))); + + if (pMD->AcquiresInstMethodTableFromThis()) + { + pData->hiddenArg = GetThis(); + } + else + { + // The param type arg comes after the return buffer argument and the "this" pointer. + int index = 0; + + if (m_argIterator.HasThis()) + { + index++; + } + + if (m_argIterator.HasRetBuffArg()) + { + index++; + } + + pData->hiddenArg = *(LPVOID*)((LPBYTE)pData->profiledSp + (index * sizeof(SIZE_T))); + } + } + else + { + EECodeInfo codeInfo((PCODE)pData->Pc); + + // We want to pass the caller SP here. + pData->hiddenArg = EECodeManager::GetExactGenericsToken((SIZE_T)(pData->profiledSp), &codeInfo); + } + } +} + + +/* + * ProfileArgIterator::~ProfileArgIterator + * + * Destructor, releases all resources. + * + */ +ProfileArgIterator::~ProfileArgIterator() +{ + LIMITED_METHOD_CONTRACT; + + m_handle = NULL; +} + + +/* + * ProfileArgIterator::GetNextArgAddr + * + * After initialization, this method is called repeatedly until it + * returns NULL to get the address of each arg. Note: this address + * could be anywhere on the stack. + * + * Returns: + * Address of the argument, or NULL if iteration is complete. + */ +LPVOID ProfileArgIterator::GetNextArgAddr() +{ + WRAPPER_NO_CONTRACT; + + _ASSERTE(m_handle != NULL); + + PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)m_handle; + + if ((pData->flags & PROFILE_LEAVE) || (pData->flags & PROFILE_TAILCALL)) + { + _ASSERTE(!"GetNextArgAddr() - arguments are not available in leave and tailcall probes"); + return NULL; + } + + int argOffset = m_argIterator.GetNextOffset(); + + // argOffset of TransitionBlock::InvalidOffset indicates that we're done + if (argOffset == TransitionBlock::InvalidOffset) + { + return NULL; + } + + if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset)) + { + // Arguments which land up in floating point registers are contained entirely within those + // registers (they're never split onto the stack). + return ((BYTE *)&pData->d) + (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()); + } + + // Argument lives in one or more general registers (and possibly overflows onto the stack). + return (LPBYTE)pData->profiledSp + (argOffset - TransitionBlock::GetOffsetOfArgumentRegisters()); +} + +/* + * ProfileArgIterator::GetHiddenArgValue + * + * Called after initialization, any number of times, to retrieve any + * hidden argument, so that resolution for Generics can be done. + * + * Parameters: + * None. + * + * Returns: + * Value of the hidden parameter, or NULL if none exists. + */ +LPVOID ProfileArgIterator::GetHiddenArgValue(void) +{ + LIMITED_METHOD_CONTRACT; + + PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)m_handle; + + return pData->hiddenArg; +} + +/* + * ProfileArgIterator::GetThis + * + * Called after initialization, any number of times, to retrieve any + * 'this' pointer. + * + * Parameters: + * None. + * + * Returns: + * Address of the 'this', or NULL if none exists. + */ +LPVOID ProfileArgIterator::GetThis(void) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)m_handle; + MethodDesc * pMD = FunctionIdToMethodDesc(pData->functionId); + + // We guarantee to return the correct "this" pointer in the enter probe. + // For the leave and tailcall probes, we only return a valid "this" pointer if it is the generics token. + if (pData->hiddenArg != NULL) + { + if (pMD->AcquiresInstMethodTableFromThis()) + { + return pData->hiddenArg; + } + } + + if (pData->flags & PROFILE_ENTER) + { + if (m_argIterator.HasThis()) + { + return *(LPVOID*)((LPBYTE)pData->profiledSp); + } + } + + return NULL; +} + +/* + * ProfileArgIterator::GetReturnBufferAddr + * + * Called after initialization, any number of times, to retrieve the + * address of the return buffer. NULL indicates no return value. + * + * Parameters: + * None. + * + * Returns: + * Address of the return buffer, or NULL if none exists. + */ +LPVOID ProfileArgIterator::GetReturnBufferAddr(void) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + PROFILE_PLATFORM_SPECIFIC_DATA* pData = (PROFILE_PLATFORM_SPECIFIC_DATA*)m_handle; + MethodDesc * pMD = FunctionIdToMethodDesc(pData->functionId); + + if (m_argIterator.HasRetBuffArg()) + { + return (LPVOID)pData->r0; + } + + if (m_argIterator.GetFPReturnSize() != 0) + return &pData->d[0]; + + if (m_argIterator.GetSig()->GetReturnType() != ELEMENT_TYPE_VOID) + return &pData->r0; + else + return NULL; +} + +#endif // PROFILING_SUPPORTED |