summaryrefslogtreecommitdiff
path: root/src/vm/arm/profiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/arm/profiler.cpp')
-rw-r--r--src/vm/arm/profiler.cpp358
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