/* * 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::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 * 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 Rsp for the profiled method to make sure it matches // what the JIT gave us #ifdef _DEBUG { // setup the context to represent the frame that called ProfileEnterNaked CONTEXT ctx; memset(&ctx, 0, sizeof(CONTEXT)); ctx.Rsp = (UINT64)pData->probeRsp; ctx.Rbp = (UINT64)pData->rbp; ctx.Rip = (UINT64)pData->ip; // walk up a frame to the caller frame (called the managed method which // called ProfileEnterNaked) Thread::VirtualUnwindCallFrame(&ctx); _ASSERTE(pData->profiledRsp == (void*)ctx.Rsp); } #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->profiledRsp + (index * sizeof(SIZE_T))); } } else { EECodeInfo codeInfo((PCODE)pData->ip); // We want to pass the caller SP here. pData->hiddenArg = EECodeManager::GetExactGenericsToken((SIZE_T)(pData->profiledRsp), &codeInfo); } } }