summaryrefslogtreecommitdiff
path: root/src/vm/i386/profiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/i386/profiler.cpp')
-rw-r--r--src/vm/i386/profiler.cpp336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/vm/i386/profiler.cpp b/src/vm/i386/profiler.cpp
new file mode 100644
index 0000000000..11d4247aef
--- /dev/null
+++ b/src/vm/i386/profiler.cpp
@@ -0,0 +1,336 @@
+// 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"
+
+//
+// The following structure is the format on x86 builds of the data
+// being passed in plaformSpecificHandle for ProfileEnter/Leave/Tailcall
+//
+typedef struct _PROFILE_PLATFORM_SPECIFIC_DATA
+{
+ FunctionID functionId;
+ DWORD doubleBuffer1;
+ DWORD doubleBuffer2;
+ DWORD floatBuffer;
+ DWORD floatingPointValuePresent;
+ UINT_PTR eax; // eax and edx must be continuous in this structure to make getting 64 bit return values easier.
+ UINT_PTR edx;
+ UINT_PTR ecx;
+ UINT_PTR esp;
+ UINT_PTR ip;
+} 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;
+
+ return ((PROFILE_PLATFORM_SPECIFIC_DATA *)handle)->ip;
+}
+
+
+/*
+ * 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. Initializes for arg iteration.
+ *
+ * Parameters:
+ * pMetaSig - The signature of the method we are going iterate over
+ * platformSpecificHandle - the value passed to ProfileEnter/Leave/Tailcall
+ *
+ * Returns:
+ * None.
+ */
+ProfileArgIterator::ProfileArgIterator(MetaSig * pMetaSig, void * platformSpecificHandle):
+ m_argIterator(pMetaSig)
+{
+ //
+ // It would be really nice to contract this, but the underlying functions are convolutedly
+ // contracted. Basically everything should be loaded by the time the profiler gets a call
+ // back, so everything is NOTHROW/NOTRIGGER, but there is not mechanism for saying that the
+ // contracts in called functions should be for the best case, not the worst case, now.
+ //
+ WRAPPER_NO_CONTRACT;
+
+ m_handle = platformSpecificHandle;
+}
+
+/*
+ * ProfileArgIterator::~ProfileArgIterator
+ *
+ * Destructor, releases all resources.
+ *
+ */
+ProfileArgIterator::~ProfileArgIterator()
+{
+ LIMITED_METHOD_CONTRACT;
+}
+
+/*
+ * 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()
+{
+ //
+ // It would be really nice to contract this, but the underlying functions are convolutedly
+ // contracted. Basically everything should be loaded by the time the profiler gets a call
+ // back, so everything is NOTHROW/NOTRIGGER, but there is not mechanism for saying that the
+ // contracts in called functions should be for the best case, not the worst case, now.
+ //
+ WRAPPER_NO_CONTRACT;
+
+ int argOffset = m_argIterator.GetNextOffset();
+
+ //
+ // Value is enregistered, figure out where and return that.
+ //
+ PROFILE_PLATFORM_SPECIFIC_DATA *pData = (PROFILE_PLATFORM_SPECIFIC_DATA *)m_handle;
+
+ //
+ // Zero indicates the end of the args.
+ //
+ if (argOffset == TransitionBlock::InvalidOffset)
+ {
+ return NULL;
+ }
+
+ if (pData == NULL)
+ {
+ //
+ // Something wrong.
+ //
+ _ASSERTE(!"Why do we have a NULL data pointer here?");
+ return NULL;
+ }
+
+ //
+ // If this is not enregistered, return the value
+ //
+ if (TransitionBlock::IsStackArgumentOffset(argOffset))
+ {
+ return ((LPBYTE)pData->esp) + (argOffset - TransitionBlock::GetOffsetOfArgs());
+ }
+
+ switch (argOffset - TransitionBlock::GetOffsetOfArgumentRegisters())
+ {
+ case offsetof(ArgumentRegisters, ECX):
+ return &(pData->ecx);
+ case offsetof(ArgumentRegisters, EDX):
+ return &(pData->edx);
+ }
+
+ _ASSERTE(!"Arg is an unsaved register!");
+ return NULL;
+}
+
+/*
+ * 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)
+{
+ //
+ // It would be really nice to contract this, but the underlying functions are convolutedly
+ // contracted. Basically everything should be loaded by the time the profiler gets a call
+ // back, so everything is NOTHROW/NOTRIGGER, but there is not mechanism for saying that the
+ // contracts in called functions should be for the best case, not the worst case, now.
+ //
+ WRAPPER_NO_CONTRACT;
+
+ PROFILE_PLATFORM_SPECIFIC_DATA *pData = (PROFILE_PLATFORM_SPECIFIC_DATA *)m_handle;
+
+ MethodDesc *pMethodDesc = FunctionIdToMethodDesc(pData->functionId);
+
+ if (!pMethodDesc->RequiresInstArg())
+ {
+ return NULL;
+ }
+
+ //
+ // The ArgIterator::GetParamTypeOffset() can only be called after calling GetNextOffset until the
+ // entire signature has been walked, but *before* GetNextOffset returns TransitionBlock::InvalidOffset
+ // - indicating the end.
+ //
+
+ //
+ // Get the offset of the hidden arg
+ //
+ int argOffset = m_argIterator.GetParamTypeArgOffset();
+
+ //
+ // If this is not enregistered, return the value
+ //
+ if (TransitionBlock::IsStackArgumentOffset(argOffset))
+ {
+ return *(LPVOID *)(((LPBYTE)pData->esp) + (argOffset - TransitionBlock::GetOffsetOfArgs()));
+ }
+
+ switch (argOffset - TransitionBlock::GetOffsetOfArgumentRegisters())
+ {
+ case offsetof(ArgumentRegisters, ECX):
+ return (LPVOID)(pData->ecx);
+ case offsetof(ArgumentRegisters, EDX):
+ return (LPVOID)(pData->edx);
+ }
+
+ _ASSERTE(!"Arg is an unsaved register!");
+ return NULL;
+}
+
+/*
+ * ProfileArgIterator::GetThis
+ *
+ * Called after initialization, any number of times, to retrieve the
+ * value of 'this'.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * value of the 'this' parameter, 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;
+
+ if (pData->ip == 0)
+ {
+ return NULL;
+ }
+
+ if (!m_argIterator.HasThis())
+ {
+ return NULL;
+ }
+
+ switch (offsetof(ArgumentRegisters, THIS_REG))
+ {
+ case offsetof(ArgumentRegisters, ECX):
+ return (LPVOID)pData->ecx;
+
+ case offsetof(ArgumentRegisters, EDX):
+ return (LPVOID)pData->edx;
+ }
+
+ _ASSERTE(!"This is an unsaved register!");
+ 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;
+
+ if (m_argIterator.HasRetBuffArg())
+ {
+ return (void *)(pData->eax);
+ }
+
+ switch (m_argIterator.GetSig()->GetReturnType())
+ {
+ case ELEMENT_TYPE_R8:
+ _ASSERTE(pData->floatingPointValuePresent);
+ return (void *)(&(pData->doubleBuffer1));
+
+ case ELEMENT_TYPE_R4:
+ _ASSERTE(pData->floatingPointValuePresent);
+ return (void *)(&(pData->floatBuffer));
+
+ default:
+ return &(pData->eax);
+ }
+}
+
+#endif // PROFILING_SUPPORTED
+