1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // EEToProfInterfaceImpl.cpp
9 // This module implements wrappers around calling the profiler's
10 // ICorProfilerCallaback* interfaces. When code in the EE needs to call the
11 // profiler, it goes through EEToProfInterfaceImpl to do so.
13 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
18 // There are strict rules for how to implement ICorProfilerCallback* wrappers. Please read
19 // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/profilability.md
20 // to understand the rules and why they exist.
22 // As a reminder, here is a short summary of your responsibilities. Every PUBLIC
23 // ENTRYPOINT (from EE to profiler) must have:
25 // - An entrypoint macro at the top. Your choices are:
26 // CLR_TO_PROFILER_ENTRYPOINT (typical choice)
27 // This is used for calling ICorProfilerCallback* methods that either have no
28 // ThreadID parameters, or if they do have a ThreadID parameter, the parameter's
29 // value is always the *current* ThreadID (i.e., param == GetThread()). This will
30 // also force a mode switch to preemptive before calling the profiler.
31 // CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD
32 // Similar to above, except these are used for ICorProfilerCallback* methods that
33 // specify a ThreadID parameter whose value may not always be the *current*
34 // ThreadID. You must specify the ThreadID as the first parameter to these
35 // macros. The macro will then use your ThreadID rather than that of the current
36 // GetThread(), to assert that the callback is currently allowed for that
37 // ThreadID (i.e., that we have not yet issued a ThreadDestroyed() for that
40 // - A complete contract block with comments over every contract choice. Wherever
41 // possible, use the preferred contracts (if not possible, you must comment why):
43 // All callbacks are really NOTHROW, but that's enforced partially by
44 // the profiler, whose try/catch blocks aren't visible to the
45 // contract system. So you'll need to put a scoped
46 // PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout)
47 // around the call to the profiler
49 // MODE_PREEMPTIVE (MODE_COOPERATIVE if passing an ObjectID)
50 // If you use MODE_ANY, you must comment why you don't want an exact mode.
52 // ASSERT_NO_EE_LOCKS_HELD()
54 // Note that the preferred contracts in this file are DIFFERENT than the preferred
55 // contracts for proftoeeinterfaceimpl.cpp.
57 // Private helper functions in this file do not have the same preferred contracts as
58 // public entrypoints, and they should be contracted following the same guidelines
59 // as per the rest of the EE.
61 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
62 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
65 // ======================================================================================
69 #ifdef PROFILING_SUPPORTED
72 #include "eetoprofinterfaceimpl.h"
73 #include "eetoprofinterfaceimpl.inl"
75 #include "proftoeeinterfaceimpl.h"
76 #include "proftoeeinterfaceimpl.inl"
77 #include "profilinghelper.inl"
78 #include "profdetach.h"
79 #include "simplerwlock.hpp"
82 //---------------------------------------------------------------------------------------
85 // Bitmask of flags that may be passed to the CLR_TO_PROFILER_ENTRYPOINT* macros
86 // to constrain when the callback may be issued
87 enum ClrToProfEntrypointFlags
90 kEE2PNone = 0x00000000,
92 // Callback is allowable even for detaching profilers
93 kEE2PAllowableWhileDetaching = 0x00000001,
95 // Callback is allowable even for initializing profilers
96 kEE2PAllowableWhileInitializing = 0x00000002,
98 // Callback is made while in a GC_NOTRIGGER contract. Whereas contracts are
99 // debug-only, this flag is used in retail builds as well.
100 kEE2PNoTrigger = 0x00000004,
103 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
104 #define ASSERT_EVAC_COUNTER_NONZERO() \
105 _ASSERTE((GetThreadNULLOk() == NULL) || \
106 (GetThreadNULLOk()->GetProfilerEvacuationCounter() != 0U))
107 #else // FEATURE_PROFAPI_ATTACH_DETACH
108 #define ASSERT_EVAC_COUNTER_NONZERO()
109 #endif // FEATURE_PROFAPI_ATTACH_DETACH
111 #define CHECK_PROFILER_STATUS(ee2pFlags) \
112 /* If one of these asserts fires, perhaps you forgot to use */ \
113 /* BEGIN/END_PIN_PROFILER */ \
114 ASSERT_EVAC_COUNTER_NONZERO(); \
115 _ASSERTE(g_profControlBlock.pProfInterface.Load() != NULL); \
116 _ASSERTE(g_profControlBlock.pProfInterface == this); \
117 /* Early abort if... */ \
119 /* Profiler isn't active, */ \
120 !CORProfilerPresent() && \
122 /* and it's not the case that both a) this callback is allowed */ \
123 /* on a detaching profiler, and b) the profiler is detaching */ \
125 (((ee2pFlags) & kEE2PAllowableWhileDetaching) != 0) && \
126 (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
129 /* and it's not the case that both a) this callback is allowed */ \
130 /* on an initializing profiler, and b) the profiler is initializing */ \
132 (((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) && \
134 (g_profControlBlock.curProfStatus.Get() \
135 == kProfStatusInitializingForStartupLoad) || \
136 (g_profControlBlock.curProfStatus.Get() \
137 == kProfStatusInitializingForAttachLoad) \
145 // Least common denominator for the callback wrappers. Logs, removes stack
146 // guard (REMOVE_STACK_GUARD_FOR_PROFILER_CALL), records in EE Thread object that
147 // we're in a callback, and asserts that we're allowed to issue callbacks for the
148 // specified ThreadID (i.e., no ThreadDestroyed callback has been issued for the
151 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, threadId, logParams) \
152 INCONTRACT(AssertTriggersContract(!((ee2pFlags) & kEE2PNoTrigger))); \
153 CHECK_PROFILER_STATUS(ee2pFlags); \
155 _ASSERTE(m_pCallback2 != NULL); \
156 REMOVE_STACK_GUARD_FOR_PROFILER_CALL; \
157 /* Normally, set COR_PRF_CALLBACKSTATE_INCALLBACK | */ \
158 /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE in the callback state, but omit */ \
159 /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE if we're in a GC_NOTRIGGERS callback */ \
160 SetCallbackStateFlagsHolder __csf( \
161 (((ee2pFlags) & kEE2PNoTrigger) != 0) ? \
162 COR_PRF_CALLBACKSTATE_INCALLBACK : \
163 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE \
165 _ASSERTE(ProfilerCallbacksAllowedForThread((Thread *) (threadId)))
167 #define CLR_TO_PROFILER_ENTRYPOINT_EX(ee2pFlags, logParams) \
168 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, GetThreadNULLOk(), logParams)
170 // Typical entrypoint macro you'll use. Checks that we're allowed to issue
171 // callbacks for the current thread (i.e., no ThreadDestroyed callback has been
172 // issued for the current thread).
173 #define CLR_TO_PROFILER_ENTRYPOINT(logParams) \
174 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PNone, logParams)
175 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId, logParams) \
176 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(kEE2PNone, threadId, logParams)
179 //---------------------------------------------------------------------------------------
181 // Wrapper around Thread::ProfilerCallbacksAllowed
184 // pThread - Thread on which we need to determine whether callbacks are allowed
187 // TRUE if the profiler portion has marked this thread as allowable, else FALSE.
190 inline BOOL ProfilerCallbacksAllowedForThread(Thread * pThread)
193 return ((pThread == NULL) || (pThread->ProfilerCallbacksAllowed()));
197 //---------------------------------------------------------------------------------------
199 // Wrapper around Thread::SetProfilerCallbacksAllowed
202 // pThread - Thread on which we're setting whether callbacks shall be allowed
203 // fValue - The value to store.
206 inline void SetProfilerCallbacksAllowedForThread(Thread * pThread, BOOL fValue)
209 _ASSERTE(pThread != NULL);
210 pThread->SetProfilerCallbacksAllowed(fValue);
214 //---------------------------------------------------------------------------------------
216 // Low-level function to find and CoCreateInstance the profiler's DLL. Called when
217 // initializing via EEToProfInterfaceImpl::Init()
220 // * pClsid - [in] Profiler's CLSID
221 // * wszClsid - [in] String form of CLSID or progid of profiler to load.
222 // * wszProfileDLL - [in] Path to profiler DLL
223 // * ppCallback - [out] Pointer to profiler's ICorProfilerCallback2 interface
224 // * phmodProfilerDLL - [out] HMODULE of profiler's DLL.
227 // HRESULT indicating success or failure.
230 // * This function (or one of its callees) will log an error to the event log if
231 // there is a failure
233 static HRESULT CoCreateProfiler(
234 const CLSID * pClsid,
235 __in_z LPCWSTR wszClsid,
236 __in_z LPCWSTR wszProfileDLL,
237 ICorProfilerCallback2 ** ppCallback,
238 HMODULE * phmodProfilerDLL)
246 // This causes events to be logged, which loads resource strings,
247 // which takes locks.
253 _ASSERTE(pClsid != NULL);
254 _ASSERTE(wszClsid != NULL);
255 _ASSERTE(ppCallback != NULL);
256 _ASSERTE(phmodProfilerDLL != NULL);
258 LOG((LF_CORPROF, LL_INFO10, "**PROF: Entered CoCreateProfiler.\n"));
261 *phmodProfilerDLL = NULL;
263 // This is the ICorProfilerCallback2 ptr we get back from the profiler's class
264 // factory's CreateInstance()
265 ReleaseHolder<ICorProfilerCallback2> pCallback2FromCreateInstance;
267 // This is the ICorProfilerCallback2 ptr we get back from the profiler's QI (see its
268 // first use below for an explanation on why this is necessary).
269 ReleaseHolder<ICorProfilerCallback2> pCallback2FromQI;
271 // Create an instance of the profiler
272 hr = FakeCoCreateInstanceEx(*pClsid,
274 IID_ICorProfilerCallback2,
275 (LPVOID *) &pCallback2FromCreateInstance,
278 // (pCallback2FromCreateInstance == NULL) should be considered an error!
279 if ((pCallback2FromCreateInstance == NULL) && SUCCEEDED(hr))
284 if (hr == E_NOINTERFACE)
286 // Helpful message for a potentially common problem
287 ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
289 else if (hr == CORPROF_E_PROFILER_CANCEL_ACTIVATION)
291 // Profiler didn't encounter a bad error, but is voluntarily choosing not to
292 // profile this runtime. Profilers that need to set system environment
293 // variables to be able to profile services may use this HRESULT to avoid
294 // profiling all the other managed apps on the box.
295 ProfilingAPIUtility::LogProfInfo(IDS_PROF_CANCEL_ACTIVATION, wszClsid);
299 // Catch-all error for other CoCreateInstance failures
300 ProfilingAPIUtility::LogProfError(IDS_E_PROF_CCI_FAILED, wszClsid, hr);
303 // Now that hr is normalized (set to error if pCallback2FromCreateInstance == NULL),
304 // LOG and abort if there was a problem.
310 "**PROF: Unable to CoCreateInstance profiler class %S. hr=0x%x.\n",
316 // Redundantly QI for ICorProfilerCallback2. This keeps CLR behavior consistent
317 // with Whidbey, and works around the following bug in some profilers' class factory
319 // * CreateInstance() ignores the IID it's given
320 // * CreateInstance() returns a pointer to the object it created, even though
321 // that object might not support the IID passed to CreateInstance().
322 // Whidbey CLR worked around this problem by redundantly QI'ing for the same IID
323 // again after CreateInstance() returned. In this redudant QI, the profiler code would
324 // finally realize it didn't support that IID, and return an error there. Without
325 // the redundant QI, the CLR would accept what it got from CreateInstance(), and
326 // start calling into it using the unsupported interface's vtable, which would
329 // There were many MSDN samples (for example
330 // http://msdn.microsoft.com/msdnmag/issues/03/01/NETProfilerAPI/) which
331 // unfortunately had this CreateInstance() bug, so many profilers might have been
332 // generated based on this code. Since it's easy & cheap to work around the
333 // problem, we do so here with the redundant QI.
334 hr = pCallback2FromCreateInstance->QueryInterface(
335 IID_ICorProfilerCallback2,
336 (LPVOID *) &pCallback2FromQI);
338 // (pCallback2FromQI == NULL) should be considered an error!
339 if ((pCallback2FromQI == NULL) && SUCCEEDED(hr))
344 // Any error at this stage implies IID_ICorProfilerCallback2 is not supported
347 // Helpful message for a potentially common problem
348 ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
352 // Ok, safe to transfer ownership to caller's [out] param
353 *ppCallback = pCallback2FromQI.Extract();
354 pCallback2FromQI = NULL;
360 //---------------------------------------------------------------------------------------
362 // Implementation of CHashTableImpl functions. This class a simple implementation of
363 // CHashTable to provide a very simple implementation of the Cmp pure virtual function
366 EEToProfInterfaceImpl::CHashTableImpl::CHashTableImpl(ULONG iBuckets)
367 : CHashTable(iBuckets)
372 EEToProfInterfaceImpl::CHashTableImpl::~CHashTableImpl()
377 //---------------------------------------------------------------------------------------
379 // Comparison function for hash table of ClassIDs
382 // pc1 - hash key to compare
383 // pc2 - hash value to compare
386 // TRUE if the key & value refer to the same ClassID; otherwise FALSE
389 BOOL EEToProfInterfaceImpl::CHashTableImpl::Cmp(SIZE_T k1, const HASHENTRY * pc2)
391 LIMITED_METHOD_CONTRACT;
393 ClassID key = (ClassID) k1;
394 ClassID val = ((CLASSHASHENTRY *)pc2)->m_clsId;
400 //---------------------------------------------------------------------------------------
401 // Private maintenance functions for initialization, cleanup, etc.
403 EEToProfInterfaceImpl::AllocByClassData *EEToProfInterfaceImpl::m_pSavedAllocDataBlock = NULL;
405 //---------------------------------------------------------------------------------------
407 // EEToProfInterfaceImpl ctor just sets initial values
410 EEToProfInterfaceImpl::EEToProfInterfaceImpl() :
419 m_hmodProfilerDLL(NULL),
420 m_fLoadedViaAttach(FALSE),
422 m_pProfilersFuncIDMapper(NULL),
423 m_pProfilersFuncIDMapper2(NULL),
424 m_pProfilersFuncIDMapper2ClientData(NULL),
427 m_pGCRefDataFreeList(NULL),
428 m_csGCRefDataFreeList(NULL),
435 m_fIsClientIDToFunctionIDMappingEnabled(TRUE),
439 m_pEnter3WithInfo(NULL),
440 m_pLeave3WithInfo(NULL),
441 m_pTailcall3WithInfo(NULL),
442 m_fUnrevertiblyModifiedIL(FALSE),
443 m_pFunctionIDHashTable(NULL),
444 m_pFunctionIDHashTableRWLock(NULL),
445 m_dwConcurrentGCWaitTimeoutInMs(INFINITE),
446 m_bHasTimedOutWaitingForConcurrentGC(FALSE)
448 // Also NULL out this static. (Note: consider making this a member variable.)
449 m_pSavedAllocDataBlock = NULL;
450 LIMITED_METHOD_CONTRACT;
454 //---------------------------------------------------------------------------------------
456 // Post-constructor initialization of EEToProfInterfaceImpl. Sets everything up,
457 // including creating the profiler.
460 // * pProfToEE - A newly-created ProfToEEInterfaceImpl instance that will be passed
461 // to the profiler as the ICorProfilerInfo3 interface implementation.
462 // * pClsid - Profiler's CLSID
463 // * wszClsid - String form of CLSID or progid of profiler to load
464 // * wszProfileDLL - Path to profiler DLL
465 // * fLoadedViaAttach - TRUE iff the profiler is being attach-loaded (else
466 // profiler is being startup-loaded)
469 // HRESULT indicating success or failure.
472 // This function (or one of its callees) will log an error to the event log if there
477 HRESULT EEToProfInterfaceImpl::Init(
478 ProfToEEInterfaceImpl * pProfToEE,
479 const CLSID * pClsid,
480 __in_z LPCWSTR wszClsid,
481 __in_z LPCWSTR wszProfileDLL,
482 BOOL fLoadedViaAttach,
483 DWORD dwConcurrentGCWaitTimeoutInMs)
491 // This causes events to be logged, which loads resource strings,
492 // which takes locks.
499 HRESULT hr = E_UNEXPECTED;
501 _ASSERTE(pProfToEE != NULL);
503 m_fLoadedViaAttach = fLoadedViaAttach;
504 m_dwConcurrentGCWaitTimeoutInMs = dwConcurrentGCWaitTimeoutInMs;
506 // The rule sez your Crst should switch to preemptive when it's taken. We intentionally
507 // break this rule with CRST_UNSAFE_ANYMODE, because this Crst is taken DURING A GC
508 // (see AllocateMovedReferencesData(), called by MovedReference(), called by the GC),
509 // and we don't want to be switching modes in the middle of a GC! Indeed, on server there
510 // may not even be a mode in the first place.
511 CRITSEC_AllocationHolder csGCRefDataFreeList(ClrCreateCriticalSection(CrstProfilerGCRefDataFreeList, CRST_UNSAFE_ANYMODE));
512 if (csGCRefDataFreeList == NULL)
516 "**PROF: Failed to create Crst during initialization.\n"));
518 // A specialized event log entry for this failure would be confusing and
519 // unhelpful. So just log a generic internal failure event
520 ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_FAIL);
524 // CEEInfo::GetProfilingHandle will be PREEMPTIVE mode when trying to update
525 // m_pFunctionIDHashTable while ProfileEnter, ProfileLeave and ProfileTailcall
526 // and LookupClientIDFromCache all will be in COOPERATIVE mode when trying
527 // to read m_pFunctionIDHashTable, so pFunctionIDHashTableRWLock must be created
528 // with COOPERATIVE_OR_PREEMPTIVE. It is safe to so do because FunctionIDHashTable,
529 // synchronized by m_pFunctionIDHashTableRWLock runs only native code and uses
531 NewHolder<SimpleRWLock> pFunctionIDHashTableRWLock(new (nothrow) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT));
533 NewHolder<FunctionIDHashTable> pFunctionIDHashTable(new (nothrow) FunctionIDHashTable());
535 if ((pFunctionIDHashTable == NULL) || (pFunctionIDHashTableRWLock == NULL))
539 "**PROF: Failed to create FunctionIDHashTable or FunctionIDHashTableRWLock during initialization.\n"));
541 // A specialized event log entry for this failure would be confusing and
542 // unhelpful. So just log a generic internal failure event
543 ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_OUTOFMEMORY);
545 return E_OUTOFMEMORY;
548 // This wraps the following profiler calls in a try / catch:
549 // * ClassFactory::CreateInstance
550 // * AddRef/Release/QueryInterface
551 // Although most profiler calls are not protected, these creation calls are
552 // protected here since it's cheap to do so (this is only done once per load of a
553 // profiler), and it would be nice to avoid tearing down the entire process when
554 // attaching a profiler that may pass back bogus vtables.
557 // CoCreate the profiler (but don't call its Initialize() method yet)
558 hr = CreateProfiler(pClsid, wszClsid, wszProfileDLL);
563 ProfilingAPIUtility::LogProfError(IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD, wszClsid);
565 // Intentionally swallowing all exceptions, as we don't want a poorly-written
566 // profiler that throws or AVs on attach to cause the entire process to go away.
567 EX_END_CATCH(SwallowAllExceptions);
572 // CreateProfiler (or catch clause above) has already logged an event to the
573 // event log on failure
577 m_pProfToEE = pProfToEE;
579 m_csGCRefDataFreeList = csGCRefDataFreeList.Extract();
580 csGCRefDataFreeList = NULL;
582 m_pFunctionIDHashTable = pFunctionIDHashTable.Extract();
583 pFunctionIDHashTable = NULL;
585 m_pFunctionIDHashTableRWLock = pFunctionIDHashTableRWLock.Extract();
586 pFunctionIDHashTableRWLock = NULL;
592 //---------------------------------------------------------------------------------------
594 // This is used by Init() to load the user-specified profiler (but not to call
595 // its Initialize() method).
598 // pClsid - Profiler's CLSID
599 // wszClsid - String form of CLSID or progid of profiler to load
600 // wszProfileDLL - Path to profiler DLL
603 // HRESULT indicating success / failure. If this is successful, m_pCallback2 will be
604 // set to the profiler's ICorProfilerCallback2 interface on return. m_pCallback3,4
605 // will be set to the profiler's ICorProfilerCallback3 interface on return if
606 // ICorProfilerCallback3,4 is supported.
609 // Although the profiler has not yet been instantiated, it is assumed that the internal
610 // profiling API structures have already been created
613 // This function (or one of its callees) will log an error to the event log
614 // if there is a failure
616 HRESULT EEToProfInterfaceImpl::CreateProfiler(
617 const CLSID * pClsid,
618 __in_z LPCWSTR wszClsid,
619 __in_z LPCWSTR wszProfileDLL)
627 // This causes events to be logged, which loads resource strings,
628 // which takes locks.
636 // Always called before Thread created.
637 _ASSERTE(GetThreadNULLOk() == NULL);
639 // We'll be calling into the profiler to create its ICorProfilerCallback*
641 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
643 // Try and CoCreate the registered profiler
644 ReleaseHolder<ICorProfilerCallback2> pCallback2;
645 HModuleHolder hmodProfilerDLL;
646 HRESULT hr = CoCreateProfiler(
654 // CoCreateProfiler logs events to the event log on failures
658 // CoCreateProfiler ensures that if it succeeds, we get some valid pointers
659 _ASSERTE(pCallback2 != NULL);
660 _ASSERTE(hmodProfilerDLL != NULL);
662 // Save profiler pointers into this. The reference ownership now
663 // belongs to this class, so NULL out locals without allowing them to release
664 m_pCallback2 = pCallback2.Extract();
666 m_hmodProfilerDLL = hmodProfilerDLL.Extract();
667 hmodProfilerDLL = NULL;
669 // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9. Let's check.
671 ReleaseHolder<ICorProfilerCallback9> pCallback9;
672 hr = m_pCallback2->QueryInterface(
673 IID_ICorProfilerCallback9,
674 (LPVOID *)&pCallback9);
675 if (SUCCEEDED(hr) && (pCallback9 != NULL))
677 // Nifty. Transfer ownership to this class
678 _ASSERTE(m_pCallback9 == NULL);
679 m_pCallback9 = pCallback9.Extract();
682 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6,7,8
683 // due to inheritance relationship of the interfaces
684 _ASSERTE(m_pCallback8 == NULL);
685 m_pCallback8 = static_cast<ICorProfilerCallback8 *>(m_pCallback9);
686 m_pCallback8->AddRef();
688 _ASSERTE(m_pCallback7 == NULL);
689 m_pCallback7 = static_cast<ICorProfilerCallback7 *>(m_pCallback8);
690 m_pCallback7->AddRef();
692 _ASSERTE(m_pCallback6 == NULL);
693 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
694 m_pCallback6->AddRef();
696 _ASSERTE(m_pCallback5 == NULL);
697 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
698 m_pCallback5->AddRef();
700 _ASSERTE(m_pCallback4 == NULL);
701 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
702 m_pCallback4->AddRef();
704 _ASSERTE(m_pCallback3 == NULL);
705 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
706 m_pCallback3->AddRef();
709 if (m_pCallback8 == NULL)
711 ReleaseHolder<ICorProfilerCallback8> pCallback8;
712 hr = m_pCallback2->QueryInterface(
713 IID_ICorProfilerCallback8,
714 (LPVOID *)&pCallback8);
715 if (SUCCEEDED(hr) && (pCallback8 != NULL))
717 // Nifty. Transfer ownership to this class
718 _ASSERTE(m_pCallback8 == NULL);
719 m_pCallback8 = pCallback8.Extract();
722 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6,7
723 // due to inheritance relationship of the interfaces
725 _ASSERTE(m_pCallback7 == NULL);
726 m_pCallback7 = static_cast<ICorProfilerCallback7 *>(m_pCallback8);
727 m_pCallback7->AddRef();
729 _ASSERTE(m_pCallback6 == NULL);
730 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
731 m_pCallback6->AddRef();
733 _ASSERTE(m_pCallback5 == NULL);
734 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
735 m_pCallback5->AddRef();
737 _ASSERTE(m_pCallback4 == NULL);
738 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
739 m_pCallback4->AddRef();
741 _ASSERTE(m_pCallback3 == NULL);
742 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
743 m_pCallback3->AddRef();
747 if (m_pCallback7 == NULL)
749 ReleaseHolder<ICorProfilerCallback7> pCallback7;
750 hr = m_pCallback2->QueryInterface(
751 IID_ICorProfilerCallback7,
752 (LPVOID *)&pCallback7);
753 if (SUCCEEDED(hr) && (pCallback7 != NULL))
755 // Nifty. Transfer ownership to this class
756 _ASSERTE(m_pCallback7 == NULL);
757 m_pCallback7 = pCallback7.Extract();
760 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6
761 // due to inheritance relationship of the interfaces
763 _ASSERTE(m_pCallback6 == NULL);
764 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
765 m_pCallback6->AddRef();
767 _ASSERTE(m_pCallback5 == NULL);
768 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
769 m_pCallback5->AddRef();
771 _ASSERTE(m_pCallback4 == NULL);
772 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
773 m_pCallback4->AddRef();
775 _ASSERTE(m_pCallback3 == NULL);
776 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
777 m_pCallback3->AddRef();
781 if (m_pCallback6 == NULL)
783 ReleaseHolder<ICorProfilerCallback6> pCallback6;
784 hr = m_pCallback2->QueryInterface(
785 IID_ICorProfilerCallback6,
786 (LPVOID *)&pCallback6);
787 if (SUCCEEDED(hr) && (pCallback6 != NULL))
789 // Nifty. Transfer ownership to this class
790 _ASSERTE(m_pCallback6 == NULL);
791 m_pCallback6 = pCallback6.Extract();
794 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5
795 // due to inheritance relationship of the interfaces
797 _ASSERTE(m_pCallback5 == NULL);
798 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
799 m_pCallback5->AddRef();
801 _ASSERTE(m_pCallback4 == NULL);
802 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
803 m_pCallback4->AddRef();
805 _ASSERTE(m_pCallback3 == NULL);
806 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
807 m_pCallback3->AddRef();
811 if (m_pCallback5 == NULL)
813 ReleaseHolder<ICorProfilerCallback5> pCallback5;
814 hr = m_pCallback2->QueryInterface(
815 IID_ICorProfilerCallback5,
816 (LPVOID *) &pCallback5);
817 if (SUCCEEDED(hr) && (pCallback5 != NULL))
819 // Nifty. Transfer ownership to this class
820 _ASSERTE(m_pCallback5 == NULL);
821 m_pCallback5 = pCallback5.Extract();
824 // And while we're at it, we must now also have an ICorProfilerCallback3, and
825 // ICorProfilerCallback4 due to inheritance relationship of the interfaces
826 _ASSERTE(m_pCallback4 == NULL);
827 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
828 m_pCallback4->AddRef();
830 _ASSERTE(m_pCallback3 == NULL);
831 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
832 m_pCallback3->AddRef();
836 if (m_pCallback4 == NULL)
838 ReleaseHolder<ICorProfilerCallback4> pCallback4;
839 hr = m_pCallback2->QueryInterface(
840 IID_ICorProfilerCallback4,
841 (LPVOID *) &pCallback4);
842 if (SUCCEEDED(hr) && (pCallback4 != NULL))
844 // Nifty. Transfer ownership to this class
845 _ASSERTE(m_pCallback4 == NULL);
846 m_pCallback4 = pCallback4.Extract();
849 // And while we're at it, we must now also have an ICorProfilerCallback3, and
850 // due to inheritance relationship of the interfaces
851 _ASSERTE(m_pCallback3 == NULL);
852 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
853 m_pCallback3->AddRef();
857 if (m_pCallback3 == NULL)
859 ReleaseHolder<ICorProfilerCallback3> pCallback3;
860 hr = m_pCallback2->QueryInterface(
861 IID_ICorProfilerCallback3,
862 (LPVOID *) &pCallback3);
863 if (SUCCEEDED(hr) && (pCallback3 != NULL))
865 // Nifty. Transfer ownership to this class
866 _ASSERTE(m_pCallback3 == NULL);
867 m_pCallback3 = pCallback3.Extract();
878 //---------------------------------------------------------------------------------------
880 // Performs cleanup for EEToProfInterfaceImpl, including releasing the profiler's
881 // callback interface. Called on termination of a profiler connection.
884 EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
892 // When we release the profiler's callback interface
893 // below, it may well perform cleanup that takes locks.
894 // Example: profiler may release a metadata interface, which
895 // causes it to take a reader lock
900 // Make sure there's no pointer about to dangle once we disappear.
901 // FUTURE: For reattach-with-neutered-profilers feature crew, change this assert to
902 // scan through list of detaching profilers to make sure none of them give a
903 // GetEEToProfPtr() equal to this
904 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
905 _ASSERTE(ProfilingAPIDetach::GetEEToProfPtr() == NULL);
906 #endif // FEATURE_PROFAPI_ATTACH_DETACH
908 // Release user-specified profiler DLL
909 // NOTE: If we're tearing down the process, then do nothing related
910 // to cleaning up the profiler DLL, as the DLL may no longer
912 if (!IsAtProcessExit())
914 if (m_pCallback2 != NULL)
916 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
917 m_pCallback2->Release();
921 BOOL fIsV4Profiler = (m_pCallback3 != NULL);
925 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
926 m_pCallback3->Release();
930 if (m_pCallback4 != NULL)
932 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
933 m_pCallback4->Release();
937 if (m_pCallback5 != NULL)
939 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
940 m_pCallback5->Release();
944 if (m_pCallback6 != NULL)
946 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
947 m_pCallback6->Release();
951 if (m_pCallback7 != NULL)
953 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
954 m_pCallback7->Release();
958 if (m_pCallback8 != NULL)
960 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
961 m_pCallback8->Release();
965 if (m_pCallback9 != NULL)
967 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
968 m_pCallback9->Release();
972 // Only unload the V4 profiler if this is not part of shutdown. This protects
973 // Whidbey profilers that aren't used to being FreeLibrary'd.
974 if (fIsV4Profiler && !g_fEEShutDown)
976 if (m_hmodProfilerDLL != NULL)
978 FreeLibrary(m_hmodProfilerDLL);
979 m_hmodProfilerDLL = NULL;
982 // Now that the profiler is destroyed, it is no longer referencing our
983 // ProfToEEInterfaceImpl, so it's safe to destroy that, too.
984 if (m_pProfToEE != NULL)
992 // Delete the structs associated with GC moved references
993 while (m_pGCRefDataFreeList)
995 GCReferencesData * pDel = m_pGCRefDataFreeList;
996 m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
1000 if (m_pSavedAllocDataBlock)
1003 _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFFFFFFFFFF);
1005 _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFF);
1008 _ASSERTE(m_pSavedAllocDataBlock->pHashTable != NULL);
1009 // Get rid of the hash table
1010 if (m_pSavedAllocDataBlock->pHashTable)
1011 delete m_pSavedAllocDataBlock->pHashTable;
1013 // Get rid of the two arrays used to hold class<->numinstance info
1014 if (m_pSavedAllocDataBlock->cLength != 0)
1016 _ASSERTE(m_pSavedAllocDataBlock->arrClsId != NULL);
1017 _ASSERTE(m_pSavedAllocDataBlock->arrcObjects != NULL);
1019 delete [] m_pSavedAllocDataBlock->arrClsId;
1020 delete [] m_pSavedAllocDataBlock->arrcObjects;
1023 // Get rid of the hash array used by the hash table
1024 if (m_pSavedAllocDataBlock->arrHash)
1026 delete [] m_pSavedAllocDataBlock->arrHash;
1029 m_pSavedAllocDataBlock = NULL;
1032 m_GUID = k_guidZero;
1034 if (m_csGCRefDataFreeList != NULL)
1036 ClrDeleteCriticalSection(m_csGCRefDataFreeList);
1037 m_csGCRefDataFreeList = NULL;
1040 if (m_pFunctionIDHashTable != NULL)
1042 delete m_pFunctionIDHashTable;
1043 m_pFunctionIDHashTable = NULL;
1046 if (m_pFunctionIDHashTableRWLock != NULL)
1048 delete m_pFunctionIDHashTableRWLock;
1049 m_pFunctionIDHashTableRWLock = NULL;
1055 //---------------------------------------------------------------------------------------
1057 // Initialize the GUID used for the cookie in remoting callbacks. If already
1058 // initialized, this just does nothing and returns S_OK.
1061 // HRESULT indicating success or failure. If the GUID was already initialized,
1062 // just returns S_OK
1066 HRESULT EEToProfInterfaceImpl::InitGUID()
1073 ASSERT_NO_EE_LOCKS_HELD();
1077 if (IsEqualGUID(m_GUID, k_guidZero))
1079 return CoCreateGuid(&m_GUID);
1085 //---------------------------------------------------------------------------------------
1087 // Returns a GUID suitable for use as a remoting callback cookie for this thread.
1088 // The GUID is based on the template GUID (m_GUID), the current thread, and
1092 // pGUID - [out] The GUID requested
1095 void EEToProfInterfaceImpl::GetGUID(GUID * pGUID)
1101 ASSERT_NO_EE_LOCKS_HELD();
1105 // the member GUID and the argument should both be valid
1106 _ASSERTE(!(IsEqualGUID(m_GUID, k_guidZero)));
1109 // Copy the contents of the template GUID
1110 memcpy(pGUID, &m_GUID, sizeof(GUID));
1112 // Adjust the last two bytes
1113 pGUID->Data4[6] = (BYTE) GetCurrentThreadId();
1114 pGUID->Data4[7] = (BYTE) InterlockedIncrement((LPLONG)&m_lGUIDCount);
1117 //---------------------------------------------------------------------------------------
1119 // Wrapper around calling profiler's FunctionIDMapper hook. Called by JIT.
1122 // funcId - FunctionID for profiler to map
1123 // pbHookFunction - [out] Specifies whether the profiler wants to hook (enter/leave)
1127 // The profiler-specified value that we should use to identify this function
1128 // in future hooks (enter/leave).
1129 // If the remapped ID returned by the profiler is NULL, we will replace it with
1130 // funcId. Thus, this function will never return NULL.
1133 UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction)
1135 // This isn't a public callback via ICorProfilerCallback*, but it's close (a
1136 // public callback via a function pointer). So we'll aim to have the preferred
1152 // ListLockEntry typically held during this callback (thanks to
1153 // MethodTable::DoRunClassInitThrowing).
1159 // only called when CORProfilerFunctionIDMapperEnabled() is true,
1160 // which means either m_pProfilersFuncIDMapper or m_pProfilersFuncIDMapper2 should not be NULL;
1161 _ASSERTE((m_pProfilersFuncIDMapper != NULL) || (m_pProfilersFuncIDMapper2 != NULL));
1163 UINT_PTR clientId = NULL;
1165 if (m_pProfilersFuncIDMapper2 != NULL)
1167 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
1169 "**PROF: Calling profiler's FunctionIDMapper2. funcId: 0x%p. clientData: 0x%p.\n",
1171 m_pProfilersFuncIDMapper2ClientData));
1173 // The attached profiler may not want to hook this function, so ask it
1174 clientId = m_pProfilersFuncIDMapper2(funcId, m_pProfilersFuncIDMapper2ClientData, pbHookFunction);
1179 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
1181 "**PROF: Calling profiler's FunctionIDMapper. funcId: 0x%p.\n",
1184 // The attached profiler may not want to hook this function, so ask it
1185 clientId = m_pProfilersFuncIDMapper(funcId, pbHookFunction);
1188 static LONG s_lIsELT2Enabled = -1;
1189 if (s_lIsELT2Enabled == -1)
1191 LONG lEnabled = ((m_pEnter2 != NULL) ||
1192 (m_pLeave2 != NULL) ||
1193 (m_pTailcall2 != NULL));
1195 InterlockedCompareExchange(&s_lIsELT2Enabled, lEnabled, -1);
1198 // We need to keep track the mapping between ClientID and FunctionID for ELT2
1199 if (s_lIsELT2Enabled != 0)
1201 FunctionIDAndClientID functionIDAndClientID;
1202 functionIDAndClientID.functionID = funcId;
1203 functionIDAndClientID.clientID = clientId;
1205 // ClientID Hash table may throw OUTOFMEMORY exception, which is not expected by the caller.
1208 SimpleWriteLockHolder writeLockHolder(m_pFunctionIDHashTableRWLock);
1209 m_pFunctionIDHashTable->AddOrReplace(functionIDAndClientID);
1213 // Running out of heap memory means we no longer can maintain the integrity of the mapping table.
1214 // All ELT2 fast-path hooks are disabled since we cannot report correct FunctionID to the
1215 // profiler at this moment.
1216 m_fIsClientIDToFunctionIDMappingEnabled = FALSE;
1218 EX_END_CATCH(RethrowTerminalExceptions);
1220 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
1221 // instead of using clientID because the profiler may map several functionIDs to a clientID to
1222 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
1223 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
1224 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
1228 // For profilers that support ELT3, clientID will be embedded into the ELT3 probes
1233 //---------------------------------------------------------------------------------------
1235 // Private functions called by GC so we can cache data for later notification to
1239 //---------------------------------------------------------------------------------------
1241 // Called lazily to allocate or use a recycled GCReferencesData.
1244 // GCReferencesData * requested by caller.
1247 // Uses m_csGCRefDataFreeList to find a recycleable GCReferencesData
1248 // Called by GC callbacks that need to record GC references reported
1249 // to the callbacks by the GC as the GC walks the heap.
1252 EEToProfInterfaceImpl::GCReferencesData * EEToProfInterfaceImpl::AllocateMovedReferencesData()
1258 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1260 // We directly take m_csGCRefDataFreeList around accessing the free list below
1263 // Thread store lock normally held during this call
1267 GCReferencesData *pData = NULL;
1269 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1271 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1273 // Anything on the free list for us to grab?
1274 if (m_pGCRefDataFreeList != NULL)
1276 // Yup, get the first element from the free list
1277 pData = m_pGCRefDataFreeList;
1278 m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
1284 // Still not set, so the free list must not have had anything
1285 // available. Go ahead and allocate a struct directly.
1286 pData = new (nothrow) GCReferencesData;
1293 // Now init the new block
1294 _ASSERTE(pData != NULL);
1296 // Set our index to the beginning
1298 pData->compactingCount = 0;
1303 //---------------------------------------------------------------------------------------
1305 // After reporting references to the profiler, this recycles the GCReferencesData
1306 // that was used. See EEToProfInterfaceImpl::EndRootReferences2.
1309 // pData - Pointer to GCReferencesData to recycle
1312 void EEToProfInterfaceImpl::FreeMovedReferencesData(GCReferencesData * pData)
1320 // We directly take m_csGCRefDataFreeList around accessing the free list below
1323 // Thread store lock normally held during this callback
1328 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1330 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1331 pData->pNext = m_pGCRefDataFreeList;
1332 m_pGCRefDataFreeList = pData;
1336 //---------------------------------------------------------------------------------------
1338 // Called by the GC to notify profapi of a moved reference. We cache the
1339 // info here so we can later notify the profiler of all moved references
1343 // pbMemBlockStart - Start of moved block
1344 // pbMemBlockEnd - End of moved block
1345 // cbRelocDistance - Offset from pbMemBlockStart of where the block
1347 // pHeapId - GCReferencesData * used to record the block
1348 // fCompacting - Is this a compacting collection?
1351 // HRESULT indicating success or failure
1354 HRESULT EEToProfInterfaceImpl::MovedReference(BYTE * pbMemBlockStart,
1355 BYTE * pbMemBlockEnd,
1356 ptrdiff_t cbRelocDistance,
1364 // Called during a GC
1366 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1368 // Thread store lock normally held during this callback
1373 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1375 // Get a pointer to the data for this heap
1376 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1378 // If this is the first notification of a moved reference for this heap
1379 // in this particular gc activation, then we need to get a ref data block
1380 // from the free list of blocks, or if that's empty then we need to
1381 // allocate a new one.
1384 pData = AllocateMovedReferencesData();
1387 return E_OUTOFMEMORY;
1390 // Set the cookie so that we will be provided it on subsequent
1392 ((*((size_t *)pHeapId))) = (size_t)pData;
1395 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1397 // If the struct has been filled, then we need to notify the profiler of
1398 // these moved references and clear the struct for the next load of
1400 if (pData->curIdx == kcReferencesMax)
1402 MovedReferences(pData);
1404 pData->compactingCount = 0;
1407 // Now save the information in the struct
1408 pData->arrpbMemBlockStartOld[pData->curIdx] = pbMemBlockStart;
1409 pData->arrpbMemBlockStartNew[pData->curIdx] = pbMemBlockStart + cbRelocDistance;
1410 pData->arrMemBlockSize[pData->curIdx] = pbMemBlockEnd - pbMemBlockStart;
1412 // Increment the index into the parallel arrays
1415 // Keep track of whether this is a compacting collection
1418 pData->compactingCount += 1;
1419 // The gc is supposed to make up its mind whether this is a compacting collection or not
1420 // Thus if this one is compacting, everything so far had to say compacting
1421 _ASSERTE(pData->compactingCount == pData->curIdx);
1425 // The gc is supposed to make up its mind whether this is a compacting collection or not
1426 // Thus if this one is non-compacting, everything so far had to say non-compacting
1427 _ASSERTE(pData->compactingCount == 0 && cbRelocDistance == 0);
1432 //---------------------------------------------------------------------------------------
1434 // Called by the GC to indicate that the GC is finished calling
1435 // EEToProfInterfaceImpl::MovedReference for this collection. This function will
1436 // call into the profiler to notify it of all the moved references we've cached.
1439 // pHeapId - Casted to a GCReferencesData * that contains the moved reference
1440 // data we've cached.
1443 // HRESULT indicating success or failure.
1446 HRESULT EEToProfInterfaceImpl::EndMovedReferences(void * pHeapId)
1452 // Called during a GC
1454 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1456 // We directly take m_csGCRefDataFreeList around accessing the free list below
1459 // Thread store lock normally held during this callback
1464 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1468 // Get a pointer to the data for this heap
1469 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1471 // If there were no moved references, profiler doesn't need to know
1475 // Communicate the moved references to the profiler
1476 _ASSERTE(pData->curIdx> 0);
1477 hr = MovedReferences(pData);
1479 // Now we're done with the data block, we can shove it onto the free list
1480 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1482 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1483 pData->pNext = m_pGCRefDataFreeList;
1484 m_pGCRefDataFreeList = pData;
1488 // Set the cookie to an invalid number
1489 (*((size_t *)pHeapId)) = (size_t)(-1);
1496 #define HASH_ARRAY_SIZE_INITIAL 1024
1497 #define HASH_ARRAY_SIZE_INC 256
1498 #define HASH_NUM_BUCKETS 32
1499 #define HASH(x) ( (ULONG) ((SIZE_T)x) ) // A simple hash function
1501 //---------------------------------------------------------------------------------------
1503 // Callback used by the GC when walking the heap (via AllocByClassHelper in
1504 // ProfToEEInterfaceImpl.cpp).
1507 // objId - Object reference encountered during heap walk
1508 // classId - ClassID for objID
1509 // pHeapId - heap walk context used by this function; it's interpreted
1510 // as an AllocByClassData * to keep track of objects on the
1514 // HRESULT indicating whether to continue with the heap walk (i.e.,
1515 // success HRESULT) or abort it (i.e., failure HRESULT).
1518 HRESULT EEToProfInterfaceImpl::AllocByClass(ObjectID objId, ClassID clsId, void * pHeapId)
1530 // This is a slight attempt to make sure that this is never called in a multi-threaded
1531 // manner. This heap walk should be done by one thread at a time only.
1532 static DWORD dwProcId = 0xFFFFFFFF;
1535 _ASSERTE(pHeapId != NULL);
1536 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1538 // The heapId they pass in is really a AllocByClassData struct ptr.
1539 AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1541 // If it's null, need to allocate one
1545 // This is a slight attempt to make sure that this is never called in a multi-threaded
1546 // manner. This heap walk should be done by one thread at a time only.
1547 dwProcId = GetCurrentProcessId();
1550 // See if we've saved a data block from a previous GC
1551 if (m_pSavedAllocDataBlock != NULL)
1552 pData = m_pSavedAllocDataBlock;
1554 // This means we need to allocate all the memory to keep track of the info
1557 // Get a new alloc data block
1558 pData = new (nothrow) AllocByClassData;
1560 return (E_OUTOFMEMORY);
1562 // Create a new hash table
1563 pData->pHashTable = new (nothrow) CHashTableImpl(HASH_NUM_BUCKETS);
1564 if (!pData->pHashTable)
1567 return (E_OUTOFMEMORY);
1570 // Get the memory for the array that the hash table is going to use
1571 pData->arrHash = new (nothrow) CLASSHASHENTRY[HASH_ARRAY_SIZE_INITIAL];
1572 if (pData->arrHash == NULL)
1574 delete pData->pHashTable;
1576 return (E_OUTOFMEMORY);
1579 // Save the number of elements in the array
1580 pData->cHash = HASH_ARRAY_SIZE_INITIAL;
1582 // Now initialize the hash table
1583 HRESULT hr = pData->pHashTable->NewInit((BYTE *)pData->arrHash, sizeof(CLASSHASHENTRY));
1584 if (hr == E_OUTOFMEMORY)
1586 delete [] pData->arrHash;
1587 delete pData->pHashTable;
1589 return (E_OUTOFMEMORY);
1591 _ASSERTE(pData->pHashTable->IsInited());
1593 // Null some entries
1594 pData->arrClsId = NULL;
1595 pData->arrcObjects = NULL;
1598 // Hold on to the structure
1599 m_pSavedAllocDataBlock = pData;
1602 // Got some memory and hash table to store entries, yay!
1603 *((size_t *)pHeapId) = (size_t)pData;
1605 // Initialize the data
1607 pData->pHashTable->Clear();
1610 _ASSERTE(pData->iHash <= pData->cHash);
1611 _ASSERTE(dwProcId == GetCurrentProcessId());
1613 // Lookup to see if this class already has an entry
1614 CLASSHASHENTRY * pEntry =
1615 reinterpret_cast<CLASSHASHENTRY *>(pData->pHashTable->Find(HASH(clsId), (SIZE_T)clsId));
1617 // If this class has already been encountered, just increment the counter.
1621 // Otherwise, need to add this one as a new entry in the hash table
1624 // If we're full, we need to realloc
1625 if (pData->iHash == pData->cHash)
1627 // Try to realloc the memory
1628 CLASSHASHENTRY *tmp = new (nothrow) CLASSHASHENTRY[pData->cHash + HASH_ARRAY_SIZE_INC];
1631 return (E_OUTOFMEMORY);
1634 _ASSERTE(pData->arrHash);
1635 memcpy (tmp, pData->arrHash, pData->cHash*sizeof(CLASSHASHENTRY));
1636 delete [] pData->arrHash;
1637 pData->arrHash = tmp;
1638 // Tell the hash table that the memory location of the array has changed
1639 pData->pHashTable->SetTable((BYTE *)pData->arrHash);
1641 // Save the new size of the array
1642 pData->cHash += HASH_ARRAY_SIZE_INC;
1645 // Now add the new entry
1646 CLASSHASHENTRY *pNewEntry = (CLASSHASHENTRY *) pData->pHashTable->Add(HASH(clsId), pData->iHash++);
1648 pNewEntry->m_clsId = clsId;
1649 pNewEntry->m_count = 1;
1656 HRESULT EEToProfInterfaceImpl::EndAllocByClass(void *pHeapId)
1658 _ASSERTE(pHeapId != NULL);
1659 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1663 AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1665 // Notify the profiler if there are elements to notify it of
1667 hr = NotifyAllocByClass(pData);
1670 (*((size_t *)pHeapId)) = (size_t)(-1);
1676 //---------------------------------------------------------------------------------------
1678 // Convert ETW-style root flag bitmask to ProfAPI-stye root flag bitmask
1681 // dwEtwRootFlags - ETW-style root flag bitmask
1684 // The corresponding ProfAPI-stye root flag bitmask
1687 DWORD EtwRootFlagsToProfApiRootFlags(DWORD dwEtwRootFlags)
1689 LIMITED_METHOD_CONTRACT;
1691 // If a new ETW flag is added, adjust this assert, and add a case below.
1692 _ASSERTE((dwEtwRootFlags &
1693 ~(kEtwGCRootFlagsPinning | kEtwGCRootFlagsWeakRef | kEtwGCRootFlagsInterior | kEtwGCRootFlagsRefCounted))
1696 DWORD dwProfApiRootFlags = 0;
1698 if ((dwEtwRootFlags & kEtwGCRootFlagsPinning) != 0)
1700 dwProfApiRootFlags |= COR_PRF_GC_ROOT_PINNING;
1702 if ((dwEtwRootFlags & kEtwGCRootFlagsWeakRef) != 0)
1704 dwProfApiRootFlags |= COR_PRF_GC_ROOT_WEAKREF;
1706 if ((dwEtwRootFlags & kEtwGCRootFlagsInterior) != 0)
1708 dwProfApiRootFlags |= COR_PRF_GC_ROOT_INTERIOR;
1710 if ((dwEtwRootFlags & kEtwGCRootFlagsRefCounted) != 0)
1712 dwProfApiRootFlags |= COR_PRF_GC_ROOT_REFCOUNTED;
1714 return dwProfApiRootFlags;
1717 //---------------------------------------------------------------------------------------
1719 // Convert ETW-style root kind enum to ProfAPI-stye root kind enum
1722 // dwEtwRootKind - ETW-style root kind enum
1725 // Corresponding ProfAPI-stye root kind enum
1728 DWORD EtwRootKindToProfApiRootKind(EtwGCRootKind dwEtwRootKind)
1730 LIMITED_METHOD_CONTRACT;
1732 switch(dwEtwRootKind)
1735 // If a new ETW root kind is added, create a profapi root kind as well, and add
1736 // the appropriate case below
1737 _ASSERTE(!"Unrecognized ETW root kind");
1738 // Deliberately fall through to kEtwGCRootKindOther
1740 case kEtwGCRootKindOther:
1741 return COR_PRF_GC_ROOT_OTHER;
1743 case kEtwGCRootKindStack:
1744 return COR_PRF_GC_ROOT_STACK;
1746 case kEtwGCRootKindFinalizer:
1747 return COR_PRF_GC_ROOT_FINALIZER;
1749 case kEtwGCRootKindHandle:
1750 return COR_PRF_GC_ROOT_HANDLE;
1754 //---------------------------------------------------------------------------------------
1756 // Callback used by the GC when scanning the roots (via ScanRootsHelper in
1757 // ProfToEEInterfaceImpl.cpp).
1760 // objectId - Root object reference encountered
1761 // dwEtwRootKind - ETW enum describing what kind of root objectId is
1762 // dwEtwRootFlags - ETW flags describing the root qualities of objectId
1763 // rootID - Root's methoddesc if dwEtwRootKind==kEtwGCRootKindStack, else NULL
1764 // pHeapId - Used as a GCReferencesData * to keep track of the GC references
1767 // HRESULT indicating success or failure.
1770 HRESULT EEToProfInterfaceImpl::RootReference2(BYTE * objectId,
1771 EtwGCRootKind dwEtwRootKind,
1772 EtwGCRootFlags dwEtwRootFlags,
1777 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1779 LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Reference. "
1780 "ObjectID:0x%p dwEtwRootKind:0x%x dwEtwRootFlags:0x%x rootId:0x%p HeadId:0x%p\n",
1781 objectId, dwEtwRootKind, dwEtwRootFlags, rootID, pHeapId));
1783 DWORD dwProfApiRootFlags = EtwRootFlagsToProfApiRootFlags(dwEtwRootFlags);
1784 DWORD dwProfApiRootKind = EtwRootKindToProfApiRootKind((EtwGCRootKind) dwEtwRootKind);
1786 // Get a pointer to the data for this heap
1787 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1789 // If this is the first notification of an extended root reference for this heap
1790 // in this particular gc activation, then we need to get a ref data block
1791 // from the free list of blocks, or if that's empty then we need to
1792 // allocate a new one.
1795 pData = AllocateMovedReferencesData();
1797 return (E_OUTOFMEMORY);
1799 // Set the cookie so that we will be provided it on subsequent
1801 ((*((size_t *)pHeapId))) = (size_t)pData;
1804 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1806 // If the struct has been filled, then we need to notify the profiler of
1807 // these root references and clear the struct for the next load of
1809 if (pData->curIdx == kcReferencesMax)
1811 RootReferences2(pData);
1815 // Now save the information in the struct
1816 pData->arrpbMemBlockStartOld[pData->curIdx] = objectId;
1817 pData->arrpbMemBlockStartNew[pData->curIdx] = (BYTE *)rootID;
1819 // assert that dwProfApiRootKind and dwProfApiRootFlags both fit in 16 bits, so we can
1820 // pack both into a 32-bit word
1821 _ASSERTE((dwProfApiRootKind & 0xffff) == dwProfApiRootKind && (dwProfApiRootFlags & 0xffff) == dwProfApiRootFlags);
1823 pData->arrULONG[pData->curIdx] = (dwProfApiRootKind << 16) | dwProfApiRootFlags;
1825 // Increment the index into the parallel arrays
1831 //---------------------------------------------------------------------------------------
1833 // Called by the GC to indicate that the GC is finished calling
1834 // EEToProfInterfaceImpl::RootReference2 for this collection. This function will
1835 // call into the profiler to notify it of all the root references we've cached.
1838 // pHeapId - Casted to a GCReferencesData * that contains the root references
1842 // HRESULT indicating success or failure.
1845 HRESULT EEToProfInterfaceImpl::EndRootReferences2(void * pHeapId)
1848 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1852 // Get a pointer to the data for this heap
1853 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1855 // If there were no moved references, profiler doesn't need to know
1859 // Communicate the moved references to the profiler
1860 _ASSERTE(pData->curIdx> 0);
1861 hr = RootReferences2(pData);
1863 // Now we're done with the data block, we can shove it onto the free list
1864 FreeMovedReferencesData(pData);
1867 // Set the cookie to an invalid number
1868 (*((size_t *)pHeapId)) = (size_t)(-1);
1874 //---------------------------------------------------------------------------------------
1876 // Callback used by the GC when scanning the roots (via
1877 // Ref_ScanDependentHandlesForProfilerAndETW in ObjectHandle.cpp).
1880 // primaryObjectId - Primary object reference in the DependentHandle
1881 // secondaryObjectId - Secondary object reference in the DependentHandle
1882 // rootID - The DependentHandle maintaining the dependency relationship
1883 // pHeapId - Used as a GCReferencesData * to keep track of the GC references
1886 // HRESULT indicating success or failure.
1889 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReference(BYTE * primaryObjectId,
1890 BYTE * secondaryObjectId,
1895 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1897 // Callers must ensure the profiler asked to be notified about dependent handles,
1898 // since this is only available for profilers implementing ICorProfilerCallback5 and
1900 _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1902 LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Dependent Handle. "
1903 "PrimaryObjectID:0x%p SecondaryObjectID:0x%p rootId:0x%p HeadId:0x%p\n",
1904 primaryObjectId, secondaryObjectId, rootID, pHeapId));
1906 // Get a pointer to the data for this heap
1907 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1909 // If this is the first notification of a dependent handle reference in
1910 // this particular gc activation, then we need to get a ref data block
1911 // from the free list of blocks, or if that's empty then we need to
1912 // allocate a new one.
1915 pData = AllocateMovedReferencesData();
1917 return (E_OUTOFMEMORY);
1919 // Set the cookie so that we will be provided it on subsequent
1921 ((*((size_t *)pHeapId))) = (size_t)pData;
1924 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1926 // If the struct has been filled, then we need to notify the profiler of
1927 // these dependent handle references and clear the struct for the next
1928 // load of dependent handle references
1929 if (pData->curIdx == kcReferencesMax)
1931 ConditionalWeakTableElementReferences(pData);
1935 // Now save the information in the struct
1936 pData->arrpbMemBlockStartOld[pData->curIdx] = primaryObjectId;
1937 pData->arrpbMemBlockStartNew[pData->curIdx] = secondaryObjectId;
1938 pData->arrpbRootId[pData->curIdx] = (BYTE*) rootID;
1940 // Increment the index into the parallel arrays
1946 //---------------------------------------------------------------------------------------
1948 // Called by the GC to indicate that the GC is finished calling
1949 // EEToProfInterfaceImpl::ConditionalWeakTableElementReference for this collection. This
1950 // function will call into the profiler to notify it of all the DependentHandle references
1954 // pHeapId - Casted to a GCReferencesData * that contains the dependent handle
1955 // references we've cached.
1958 // HRESULT indicating success or failure.
1961 HRESULT EEToProfInterfaceImpl::EndConditionalWeakTableElementReferences(void * pHeapId)
1964 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1966 // Callers must ensure the profiler asked to be notified about dependent handles,
1967 // since this is only available for profilers implementing ICorProfilerCallback5 and
1969 _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1973 // Get a pointer to the data for this heap
1974 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1976 // If there were no dependent handles, profiler doesn't need to know
1980 // Communicate the dependent handle references to the profiler
1981 _ASSERTE(pData->curIdx > 0);
1982 hr = ConditionalWeakTableElementReferences(pData);
1984 // Now we're done with the data block, we can shove it onto the free list
1985 FreeMovedReferencesData(pData);
1988 // Set the cookie to an invalid number
1989 (*((size_t *)pHeapId)) = (size_t)(-1);
1997 //---------------------------------------------------------------------------------------
1999 // Returns whether the profiler performed unrevertible acts, such as instrumenting
2000 // code or requesting ELT hooks. RequestProfilerDetach uses this function before
2001 // performing any sealing or evacuation checks to determine whether it's even possible
2002 // for the profiler ever to detach.
2005 // * S_OK if it's safe to attempt a detach. Evacuation checks must still be performed
2006 // before actually unloading the profiler.
2007 // * else, an HRESULT error value indicating what the profiler did that made it
2008 // undetachable. This is a public HRESULT suitable for returning from the
2009 // RequestProfilerDetach API.
2012 HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable()
2014 LIMITED_METHOD_CONTRACT;
2016 if (((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0) ||
2017 ((g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != 0))
2022 "**PROF: Profiler may not detach because it set an immutable flag. Flags = 0x%x.\n",
2023 g_profControlBlock.dwEventMask));
2025 return CORPROF_E_IMMUTABLE_FLAGS_SET;
2028 if ((m_pEnter != NULL) ||
2029 (m_pLeave != NULL) ||
2030 (m_pTailcall != NULL) ||
2031 (m_pEnter2 != NULL) ||
2032 (m_pLeave2 != NULL) ||
2033 (m_pTailcall2 != NULL) ||
2034 (m_pEnter3 != NULL) ||
2035 (m_pEnter3WithInfo != NULL) ||
2036 (m_pLeave3 != NULL) ||
2037 (m_pLeave3WithInfo != NULL) ||
2038 (m_pTailcall3 != NULL) ||
2039 (m_pTailcall3WithInfo != NULL))
2044 "**PROF: Profiler may not detach because it set an ELT(2) hook.\n"));
2046 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2049 if (m_fUnrevertiblyModifiedIL)
2054 "**PROF: Profiler may not detach because it called SetILFunctionBody.\n"));
2056 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2062 // Declarations for asm wrappers of profiler callbacks
2063 EXTERN_C void __stdcall ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID);
2064 EXTERN_C void __stdcall ProfileLeaveNaked(FunctionIDOrClientID functionIDOrClientID);
2065 EXTERN_C void __stdcall ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID);
2066 #define PROFILECALLBACK(name) name##Naked
2068 //---------------------------------------------------------------------------------------
2070 // Determines the hooks (slow path vs. fast path) to which the JIT shall
2071 // insert calls, and then tells the JIT which ones we want
2074 // HRESULT indicating success or failure
2077 HRESULT EEToProfInterfaceImpl::DetermineAndSetEnterLeaveFunctionHooksForJit()
2088 // We're doing all ELT3 hooks, all-Whidbey hooks or all-Everett hooks. No mixing and matching.
2089 BOOL fCLRv4Hooks = (m_pEnter3 != NULL) ||
2090 (m_pLeave3 != NULL) ||
2091 (m_pTailcall3 != NULL) ||
2092 (m_pEnter3WithInfo != NULL) ||
2093 (m_pLeave3WithInfo != NULL) ||
2094 (m_pTailcall3WithInfo != NULL);
2096 BOOL fWhidbeyHooks = (m_pEnter2 != NULL) ||
2097 (m_pLeave2 != NULL) ||
2098 (m_pTailcall2 != NULL);
2100 // If no hooks were set (e.g., SetEventMask called with COR_PRF_MONITOR_ENTERLEAVE,
2101 // but SetEnterLeaveFunctionHooks(*) never called), then nothing to do
2104 (m_pEnter == NULL) &&
2105 (m_pLeave == NULL) &&
2106 (m_pTailcall == NULL))
2118 // For each type of hook (enter/leave/tailcall) we must determine if we can use the
2119 // happy lucky fast path (i.e., direct call from JITd code right into the profiler's
2120 // hook or the JIT default stub (see below)), or the slow path (i.e., call into an
2121 // intermediary FCALL which then calls the profiler's hook) with extra information
2122 // about the current function.
2124 // The casts below are to appease rotor. cl.exe doesn't need them.
2125 hr = SetEnterLeaveFunctionHooksForJit(
2126 (m_pEnter3WithInfo != NULL) ?
2127 reinterpret_cast<FunctionEnter3 *>(PROFILECALLBACK(ProfileEnter)) :
2129 (m_pLeave3WithInfo != NULL) ?
2130 reinterpret_cast<FunctionLeave3 *>(PROFILECALLBACK(ProfileLeave)) :
2132 (m_pTailcall3WithInfo != NULL) ?
2133 reinterpret_cast<FunctionTailcall3 *>(PROFILECALLBACK(ProfileTailcall)) :
2139 // Everett or Whidbey hooks.
2142 // When using Everett or Whidbey hooks, the check looks like this:
2145 // THEN Use slow path
2149 // - If the profiler wants the old-style Whidbey or Everett hooks, we need a wrapper
2150 // to convert from the ELT3 prototype the JIT expects to the Whidbey or Everett
2151 // prototype the profiler expects. It applies to Whidbey fast-path hooks. And due
2152 // to the overhead of looking up FunctionID from cache and using lock to synchronize
2153 // cache accesses, the so-called Whidbey fast-path hooks are much slower than they
2154 // used to be. Whidbey and Everett hooks are supported to keep existing profiler
2155 // running, but the profiler writers are encouraged to use ELT3 interface for the
2156 // best performance.
2158 // Implicit in the above logic is if one of the hook types has no hook pointer
2159 // specified, then we pass NULL as the hook pointer to the JIT, in which case the JIT
2160 // just generates a call to the default stub (a single ret) w/out invoking the slow-path
2161 // wrapper. I call this the "fast path to nowhere"
2163 BOOL fEnter = (m_pEnter != NULL) || (m_pEnter2 != NULL);
2164 BOOL fLeave = (m_pLeave != NULL) || (m_pLeave2 != NULL);
2165 BOOL fTailcall = (m_pTailcall != NULL) || (m_pTailcall2 != NULL);
2167 // The casts below are to appease rotor. cl.exe doesn't need them.
2168 hr = SetEnterLeaveFunctionHooksForJit(
2170 reinterpret_cast<FunctionEnter3 *>(PROFILECALLBACK(ProfileEnter)) :
2173 reinterpret_cast<FunctionLeave3 *>(PROFILECALLBACK(ProfileLeave)) :
2176 reinterpret_cast<FunctionTailcall3 *>(PROFILECALLBACK(ProfileTailcall)) :
2184 // We need to swallow all exceptions, because we will lock otherwise (in addition to
2185 // the IA64-only lock while allocating stub space!). For example, specifying
2186 // RethrowTerminalExceptions forces us to test to see if the caught exception is
2187 // terminal and Exception::IsTerminal() can lock if we get a handle table cache miss
2188 // while getting a handle for the exception. It is good to minimize locks from
2189 // profiler Info functions (and their callees), and this is a dumb lock to have,
2190 // given that we can avoid it altogether by just having terminal exceptions be
2191 // swallowed here, and returning the failure to the profiler. For those who don't
2192 // like swallowing terminal exceptions, this is mitigated by the fact that,
2193 // currently, an exception only gets thrown from SetEnterLeaveFunctionHooksForJit on
2194 // IA64. But to keep consistent (and in case the world changes), we'll do this on
2196 EX_END_CATCH(SwallowAllExceptions);
2202 //---------------------------------------------------------------------------------------
2204 // The Info method SetEventMask() simply defers to this function to do the real work.
2207 // dwEventMask - Event mask specified by the profiler
2210 // HRESULT indicating success / failure to return straight through to the profiler
2213 HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh)
2220 EE_THREAD_NOT_REQUIRED;
2226 static const DWORD kEventFlagsRequiringSlowPathEnterLeaveHooks =
2227 COR_PRF_ENABLE_FUNCTION_ARGS |
2228 COR_PRF_ENABLE_FUNCTION_RETVAL |
2229 COR_PRF_ENABLE_FRAME_INFO
2232 static const DWORD kEventFlagsAffectingEnterLeaveHooks =
2233 COR_PRF_MONITOR_ENTERLEAVE |
2234 kEventFlagsRequiringSlowPathEnterLeaveHooks
2240 // Some tests need to enable immutable flags after startup, when a profiler is
2241 // attached. These flags enable features that are used solely to verify the
2242 // correctness of other, MUTABLE features. Examples: enable immutable ELT to create
2243 // shadow stacks to verify stack walks (which can be done mutably via manual
2244 // EBP-frame walking), or enable immutable DSS to gather IP addresses to verify the
2245 // mutable GetFunctionFromIP.
2247 // Similarly, test profilers may need to extend the set of flags allowable on attach
2248 // to enable features that help verify other parts of the profapi that ARE allowed
2251 // See code:#P2CLRRestrictionsOverview for more information
2252 DWORD dwImmutableEventFlags = COR_PRF_MONITOR_IMMUTABLE;
2253 DWORD dwAllowableAfterAttachEventFlags = COR_PRF_ALLOWABLE_AFTER_ATTACH;
2254 DWORD dwTestOnlyAllowedEventMask = 0;
2255 dwTestOnlyAllowedEventMask = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyAllowedEventMask);
2256 if (dwTestOnlyAllowedEventMask != 0)
2258 // Remove from the immutable flag list those flags that a test-only profiler may
2259 // need to set post-startup (specified via COMPlus_TestOnlyAllowedEventMask)
2260 dwImmutableEventFlags &= ~dwTestOnlyAllowedEventMask;
2262 // And add to the "allowable after attach" list the same test-only flags.
2263 dwAllowableAfterAttachEventFlags |= dwTestOnlyAllowedEventMask;
2265 LOG((LF_CORPROF, LL_INFO10, "**PROF: TestOnlyAllowedEventMask=0x%x. New immutable flags=0x%x. New AllowableAfterAttach flags=0x%x\n",
2266 dwTestOnlyAllowedEventMask,
2267 dwImmutableEventFlags,
2268 dwAllowableAfterAttachEventFlags));
2272 // If we're not in initialization or shutdown, make sure profiler is
2273 // not trying to set an immutable attribute
2274 // FUTURE: If we add immutable flags to the high event mask, this would be a good
2275 // place to check for them as well.
2276 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2279 if (((dwEventMask & dwImmutableEventFlags) !=
2280 (g_profControlBlock.dwEventMask & dwImmutableEventFlags)) ||
2282 if (((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
2283 (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE)) ||
2285 ((dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) !=
2286 (g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE)))
2288 // FUTURE: Should we have a dedicated HRESULT for setting immutable flag?
2293 // If this is an attaching profiler, make sure the profiler only sets flags
2294 // allowable after an attach
2295 if (m_fLoadedViaAttach &&
2297 (((dwEventMask & (~dwAllowableAfterAttachEventFlags)) != 0) ||
2299 (((dwEventMask & (~COR_PRF_ALLOWABLE_AFTER_ATTACH)) != 0) ||
2301 (dwEventMaskHigh & (~COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH))))
2303 return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;
2306 // After fast path ELT hooks are set in Initial callback, the startup profiler is not allowed to change flags
2307 // that require slow path ELT hooks or disable ELT hooks.
2308 if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
2310 (m_pEnter3 != NULL) ||
2311 (m_pLeave3 != NULL) ||
2312 (m_pTailcall3 != NULL)
2315 ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0) ||
2316 ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2320 _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0);
2321 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2324 // After slow path ELT hooks are set in Initial callback, the startup profiler is not allowed to remove
2325 // all flags that require slow path ELT hooks or to change the flag to disable the ELT hooks.
2326 if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
2328 (m_pEnter3WithInfo != NULL) ||
2329 (m_pLeave3WithInfo != NULL) ||
2330 (m_pTailcall3WithInfo != NULL)
2333 ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0) ||
2334 ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2338 _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0);
2339 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2343 // Note whether the caller is changing flags that affect enter leave hooks
2344 BOOL fEnterLeaveHooksAffected =
2345 // Did any of the relevant flags change?
2349 ((g_profControlBlock.dwEventMask & kEventFlagsAffectingEnterLeaveHooks) ^
2350 // XORed w/ the new flags
2351 (dwEventMask & kEventFlagsAffectingEnterLeaveHooks))
2354 // And are any enter/leave hooks set?
2356 (m_pEnter3 != NULL) ||
2357 (m_pEnter3WithInfo != NULL) ||
2358 (m_pEnter2 != NULL) ||
2359 (m_pEnter != NULL) ||
2360 (m_pLeave3 != NULL) ||
2361 (m_pLeave3WithInfo != NULL) ||
2362 (m_pLeave2 != NULL) ||
2363 (m_pLeave != NULL) ||
2364 (m_pTailcall3 != NULL) ||
2365 (m_pTailcall3WithInfo != NULL) ||
2366 (m_pTailcall2 != NULL) ||
2367 (m_pTailcall != NULL)
2370 BOOL fNeedToTurnOffConcurrentGC = FALSE;
2372 if (((dwEventMask & COR_PRF_MONITOR_GC) != 0) &&
2373 ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_GC) == 0))
2375 // We don't need to worry about startup load as we'll turn off concurrent GC later
2376 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2378 // Since we're not an initializing startup profiler, the EE must be fully started up
2379 // so we can check whether concurrent GC is on
2382 return CORPROF_E_RUNTIME_UNINITIALIZED;
2385 // We don't want to change the flag before GC is fully initialized,
2386 // otherwise the concurrent GC setting would be overwritten
2387 // Make sure GC is fully initialized before proceed
2388 if (!IsGarbageCollectorFullyInitialized())
2390 return CORPROF_E_NOT_YET_AVAILABLE;
2393 // If we are attaching and we are turning on COR_PRF_MONITOR_GC, turn off concurrent GC later
2395 if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForAttachLoad)
2397 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2399 // We only allow turning off concurrent GC in the profiler attach thread inside
2400 // InitializeForAttach, otherwise we would be vulnerable to weird races such as
2401 // SetEventMask running on a separate thread and trying to turn off concurrent GC.
2402 // The best option here is to fail with CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE.
2403 // Existing Dev10 profilers should be prepared to handle such case.
2404 if (IsProfilerAttachThread())
2406 fNeedToTurnOffConcurrentGC = TRUE;
2410 return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2416 // Fail if concurrent GC is enabled
2417 // This should only happen for attach profilers if user didn't turn on COR_PRF_MONITOR_GC
2419 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2421 return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2429 if (((dwEventMaskHigh & COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES) != 0) &&
2430 !IsCallback6Supported())
2432 return CORPROF_E_CALLBACK6_REQUIRED;
2435 if (((dwEventMaskHigh & COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED) != 0) &&
2436 !IsCallback7Supported())
2438 return CORPROF_E_CALLBACK7_REQUIRED;
2441 // Now save the modified masks
2442 g_profControlBlock.dwEventMask = dwEventMask;
2443 g_profControlBlock.dwEventMaskHigh = dwEventMaskHigh;
2445 if (fEnterLeaveHooksAffected)
2447 hr = DetermineAndSetEnterLeaveFunctionHooksForJit();
2454 if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad)
2456 // If the profiler has requested remoting cookies so that it can
2457 // track logical call stacks, then we must initialize the cookie
2459 if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_REMOTING_COOKIE)
2460 == COR_PRF_MONITOR_REMOTING_COOKIE)
2470 // Turn off concurrent GC as the last step so that we don't need to turn it back on if something
2471 // else failed after that
2472 if (fNeedToTurnOffConcurrentGC)
2474 // Turn off concurrent GC if it is on so that user can walk the heap safely in GC callbacks
2475 IGCHeap * pGCHeap = GCHeapUtilities::GetGCHeap();
2477 LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at attach.\n"));
2479 // First turn off concurrent GC
2480 pGCHeap->TemporaryDisableConcurrentGC();
2483 // Then wait until concurrent GC to finish if concurrent GC is in progress
2484 // User can use a timeout that can be set by environment variable if the GC turns out
2485 // to be too long. The default value is INFINITE.
2488 // If we don't do it in this order there might be a new concurrent GC started
2489 // before we actually turn off concurrent GC
2491 hr = pGCHeap->WaitUntilConcurrentGCCompleteAsync(m_dwConcurrentGCWaitTimeoutInMs);
2494 if (hr == HRESULT_FROM_WIN32(ERROR_TIMEOUT))
2496 // Convert it to a more specific HRESULT
2497 hr = CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC;
2499 // Since we cannot call LogProfEvent here due to contact violations, we'll need to
2500 // remember the fact that we've failed, and report the failure later after InitializeForAttach
2501 m_bHasTimedOutWaitingForConcurrentGC = TRUE;
2504 pGCHeap->TemporaryEnableConcurrentGC();
2508 // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
2509 g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE;
2511 LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at attach.\n"));
2518 //---------------------------------------------------------------------------------------
2520 // The Info method SetEnterLeaveFunctionHooks() simply defers to this function to do the
2524 // (same as specified in the public API docs)
2527 // HRESULT indicating success / failure to return straight through to the profiler
2530 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
2531 FunctionLeave * pFuncLeave,
2532 FunctionTailcall * pFuncTailcall)
2539 EE_THREAD_NOT_REQUIRED;
2545 // You have to be setting at least one hook
2546 if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2548 return E_INVALIDARG;
2551 // ELT3 hooks beat Whidbey and Whidbey hooks beat Everett hooks. So if any ELT3 or
2552 // Whidbey hooks were set (SetEnterLeaveFunctionHooks3(WithInfo) or SetEnterLeaveFunctionHooks2),
2553 // this should be a noop
2554 if ((m_pEnter3 != NULL) ||
2555 (m_pEnter3WithInfo != NULL) ||
2556 (m_pLeave3 != NULL) ||
2557 (m_pLeave3WithInfo != NULL) ||
2558 (m_pTailcall3 != NULL) ||
2559 (m_pTailcall3WithInfo != NULL) ||
2560 (m_pEnter2 != NULL) ||
2561 (m_pLeave2 != NULL) ||
2562 (m_pTailcall2 != NULL))
2567 // Always save onto the function pointers, since we won't know if the profiler
2568 // is going to tracking enter/leave until after it returns from Initialize
2569 m_pEnter = pFuncEnter;
2570 m_pLeave = pFuncLeave;
2571 m_pTailcall = pFuncTailcall;
2573 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2576 //---------------------------------------------------------------------------------------
2578 // The Info method SetEnterLeaveFunctionHooks2() simply defers to this function to do the
2582 // (same as specified in the public API docs)
2585 // HRESULT indicating success / failure to return straight through to the profiler
2588 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
2589 FunctionLeave2 * pFuncLeave,
2590 FunctionTailcall2 * pFuncTailcall)
2597 EE_THREAD_NOT_REQUIRED;
2603 // You have to be setting at least one hook
2604 if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2606 return E_INVALIDARG;
2609 // ELT3 hooks beat Whidbey. So if any ELT3 hooks were set (SetEnterLeaveFunctionHooks3(WithInfo)),
2610 // this should be a noop
2611 if ((m_pEnter3 != NULL) ||
2612 (m_pEnter3WithInfo != NULL) ||
2613 (m_pLeave3 != NULL) ||
2614 (m_pLeave3WithInfo != NULL) ||
2615 (m_pTailcall3 != NULL) ||
2616 (m_pTailcall3WithInfo != NULL))
2621 // Always save onto the function pointers, since we won't know if the profiler
2622 // is going to track enter/leave until after it returns from Initialize
2623 m_pEnter2 = pFuncEnter;
2624 m_pLeave2 = pFuncLeave;
2625 m_pTailcall2 = pFuncTailcall;
2627 // Whidbey hooks override Everett hooks
2632 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2635 //---------------------------------------------------------------------------------------
2637 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2641 // (same as specified in the public API docs)
2644 // HRESULT indicating success / failure to return straight through to the profiler
2647 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
2648 FunctionLeave3 * pFuncLeave3,
2649 FunctionTailcall3 * pFuncTailcall3)
2656 EE_THREAD_NOT_REQUIRED;
2662 // You have to be setting at least one hook
2663 if ((pFuncEnter3 == NULL) &&
2664 (pFuncLeave3 == NULL) &&
2665 (pFuncTailcall3 == NULL))
2667 return E_INVALIDARG;
2670 if (CORProfilerELT3SlowPathEnabled())
2672 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2675 // Always save onto the function pointers, since we won't know if the profiler
2676 // is going to track enter/leave until after it returns from Initialize
2677 m_pEnter3 = pFuncEnter3;
2678 m_pLeave3 = pFuncLeave3;
2679 m_pTailcall3 = pFuncTailcall3;
2680 m_pEnter3WithInfo = NULL;
2681 m_pLeave3WithInfo = NULL;
2682 m_pTailcall3WithInfo = NULL;
2684 // ELT3 hooks override Whidbey hooks and Everett hooks.
2687 m_pTailcall2 = NULL;
2692 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2696 //---------------------------------------------------------------------------------------
2698 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2702 // (same as specified in the public API docs)
2705 // HRESULT indicating success / failure to return straight through to the profiler
2708 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
2709 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
2710 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
2717 EE_THREAD_NOT_REQUIRED;
2723 // You have to be setting at least one hook
2724 if ((pFuncEnter3WithInfo == NULL) &&
2725 (pFuncLeave3WithInfo == NULL) &&
2726 (pFuncTailcall3WithInfo == NULL))
2728 return E_INVALIDARG;
2731 if (!CORProfilerELT3SlowPathEnabled())
2733 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2736 // Always save onto the function pointers, since we won't know if the profiler
2737 // is going to track enter/leave until after it returns from Initialize
2738 m_pEnter3WithInfo = pFuncEnter3WithInfo;
2739 m_pLeave3WithInfo = pFuncLeave3WithInfo;
2740 m_pTailcall3WithInfo = pFuncTailcall3WithInfo;
2743 m_pTailcall3 = NULL;
2745 // ELT3 hooks override Whidbey hooks and Everett hooks.
2748 m_pTailcall2 = NULL;
2753 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2758 //---------------------------------------------------------------------------------------
2760 // ************************
2761 // Public callback wrappers
2762 // ************************
2764 // NOTE: All public callback wrappers must follow the rules stated at the top
2767 // See corprof.idl / MSDN for detailed comments about each of these public
2768 // functions, their parameters, return values, etc.
2772 //---------------------------------------------------------------------------------------
2773 // INITIALIZE CALLBACKS
2776 HRESULT EEToProfInterfaceImpl::Initialize()
2793 ASSERT_NO_EE_LOCKS_HELD();
2799 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2802 "**PROF: Calling profiler's Initialize() method.\n"));
2804 _ASSERTE(m_pProfToEE != NULL);
2806 // Startup initialization occurs before an EEThread object is created for this
2808 _ASSERTE(GetThreadNULLOk() == NULL);
2811 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2812 // whose try/catch blocks aren't visible to the contract system
2813 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2814 return m_pCallback2->Initialize(m_pProfToEE);
2819 HRESULT EEToProfInterfaceImpl::InitializeForAttach(void * pvClientData, UINT cbClientData)
2836 ASSERT_NO_EE_LOCKS_HELD();
2842 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2845 "**PROF: Calling profiler's InitializeForAttach() method.\n"));
2847 _ASSERTE(m_pProfToEE != NULL);
2849 // Attach initialization occurs on the AttachThread, which does not have an EEThread
2851 _ASSERTE(GetThreadNULLOk() == NULL);
2853 // Should only be called on profilers that support ICorProfilerCallback3
2854 _ASSERTE(m_pCallback3 != NULL);
2856 HRESULT hr = E_UNEXPECTED;
2858 // This wraps the profiler's InitializeForAttach callback in a try / catch. Although
2859 // most profiler calls are not protected, this initial callback IS, since it's cheap
2860 // to do so (this is only called once per attach of a profiler), and it would be nice to
2861 // avoid tearing down the entire process when attaching a profiler that may pass back
2865 hr = m_pCallback3->InitializeForAttach(m_pProfToEE, pvClientData, cbClientData);
2871 // Intentionally swallowing all exceptions, as we don't want a poorly-written
2872 // profiler that throws or AVs on attach to cause the entire process to go away.
2873 EX_END_CATCH(SwallowAllExceptions);
2878 HRESULT EEToProfInterfaceImpl::ProfilerAttachComplete()
2895 ASSERT_NO_EE_LOCKS_HELD();
2901 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
2903 "**PROF: Calling profiler's ProfilerAttachComplete() method.\n"));
2905 // Attach initialization occurs on the AttachThread, which does not have an EEThread
2907 _ASSERTE(GetThreadNULLOk() == NULL);
2909 // Should only be called on profilers that support ICorProfilerCallback3
2910 _ASSERTE(m_pCallback3 != NULL);
2912 HRESULT hr = E_UNEXPECTED;
2914 // This wraps the profiler's ProfilerAttachComplete callback in a try / catch.
2915 // Although most profiler calls are not protected, this early callback IS, since it's
2916 // cheap to do so (this is only called once per attach of a profiler), and it would be
2917 // nice to avoid tearing down the entire process when attaching a profiler that has
2918 // serious troubles initializing itself (e.g., in this case, with processing catch-up
2922 hr = m_pCallback3->ProfilerAttachComplete();
2928 // Intentionally swallowing all exceptions, as we don't want a poorly-written
2929 // profiler that throws or AVs on attach to cause the entire process to go away.
2930 EX_END_CATCH(SwallowAllExceptions);
2936 //---------------------------------------------------------------------------------------
2941 HRESULT EEToProfInterfaceImpl::ThreadCreated(ThreadID threadId)
2951 // Preemptive mode is particularly important here. See comment in
2952 // EEToProfInterfaceImpl::ThreadDestroyed for more information.
2959 ASSERT_NO_EE_LOCKS_HELD();
2965 // Normally these callback wrappers ask IsGCSpecial() and return without calling the
2966 // profiler if true. However, ThreadCreated() is the special case where no caller
2967 // should even get this far for GC Special threads, since our callers need to know to
2968 // avoid the GCX_PREEMP around the call to this function in the first place. See
2969 // code:Thread::m_fGCSpecial
2970 _ASSERTE(!reinterpret_cast<Thread *>(threadId)->IsGCSpecial());
2972 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
2975 "**PROF: Notifying profiler of created thread. ThreadId: 0x%p.\n",
2978 // Notify the profiler of the newly created thread.
2980 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2981 // whose try/catch blocks aren't visible to the contract system
2982 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2983 return m_pCallback2->ThreadCreated(threadId);
2987 HRESULT EEToProfInterfaceImpl::ThreadDestroyed(ThreadID threadId)
2997 // See comment below
3003 // Thread store lock is typically held during this callback
3009 if (reinterpret_cast<Thread *>(threadId)->IsGCSpecial())
3012 // In general, we like callbacks to switch to preemptive before calling into the
3013 // profiler. And this is particularly important to do in the ThreadCreated &
3014 // ThreadDestroyed callbacks.
3016 // The profiler will typically block in the ThreadDestroyed callback, because
3017 // it must coordinate the use of this threadid amongst all profiler
3018 // threads. For instance, if a separate thread A is walking "this" (via DoStackSnapshot),
3019 // then the profiler must block in ThreadDestroyed until A is finished. Otherwise,
3020 // "this" will complete its destruction before A's walk is complete.
3022 // Since the profiler will block indefinitely in ThreadDestroyed, we need
3023 // to switch to preemptive mode. Otherwise, if another thread B needs to suspend
3024 // the runtime (due to appdomain unload, GC, etc.), thread B will block
3025 // waiting for "this" (assuming we allow "this" to remain in cooperative mode),
3026 // while the profiler forces "this" to block on thread A from
3027 // the example above. And thread A may need to block on thread B, since
3028 // the stackwalking occasionally needs to switch to cooperative to access a
3029 // hash map (thus DoStackSnapshot forces the switch to cooperative up-front, before
3030 // the target thread to be walked gets suspended (yet another deadlock possibility)),
3031 // and switching to cooperative requires a wait until an in-progress GC or
3032 // EE suspension is complete. In other words, allowing "this" to remain
3033 // in cooperative mode could lead to a 3-way deadlock:
3034 // "this" waits on A
3036 // B waits on "this".
3037 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
3040 "**PROF: Notifying profiler of destroyed thread. ThreadId: 0x%p.\n",
3043 // From now on, issue no more callbacks for this thread
3044 SetProfilerCallbacksAllowedForThread((Thread *) threadId, FALSE);
3046 // Notify the profiler of the destroyed thread
3048 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3049 // whose try/catch blocks aren't visible to the contract system
3050 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3051 return m_pCallback2->ThreadDestroyed(threadId);
3055 HRESULT EEToProfInterfaceImpl::ThreadAssignedToOSThread(ThreadID managedThreadId,
3063 // Called by notrigger Thread::DetachThread & CorHost::SwitchOutLogicalThreadState
3064 // which do look to be dangerous times to be triggering a GC
3067 // This is called in notrigger zones (see above), so it's not safe to switch to preemptive
3074 ASSERT_NO_EE_LOCKS_HELD();
3080 if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3083 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(
3088 "**PROF: Notifying profiler of thread assignment. ThreadId: 0x%p, OSThreadId: 0x%08x\n",
3092 // Notify the profiler of the thread being assigned to the OS thread
3094 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3095 // whose try/catch blocks aren't visible to the contract system
3096 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3097 return m_pCallback2->ThreadAssignedToOSThread(managedThreadId, osThreadId);
3101 HRESULT EEToProfInterfaceImpl::ThreadNameChanged(ThreadID managedThreadId,
3103 __in_ecount_opt(cchName) WCHAR name[])
3120 ASSERT_NO_EE_LOCKS_HELD();
3126 if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3129 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(managedThreadId,
3132 "**PROF: Notifying profiler of thread name change.\n"));
3135 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3136 // whose try/catch blocks aren't visible to the contract system
3137 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3138 return m_pCallback2->ThreadNameChanged(managedThreadId, cchName, name);
3142 //---------------------------------------------------------------------------------------
3143 // EE STARTUP/SHUTDOWN EVENTS
3146 HRESULT EEToProfInterfaceImpl::Shutdown()
3163 ASSERT_NO_EE_LOCKS_HELD();
3169 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3171 "**PROF: Notifying profiler that shutdown is beginning.\n"));
3174 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3175 // whose try/catch blocks aren't visible to the contract system
3176 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3177 return m_pCallback2->Shutdown();
3181 //---------------------------------------------------------------------------------------
3182 // JIT/FUNCTION EVENTS
3185 HRESULT EEToProfInterfaceImpl::FunctionUnloadStarted(FunctionID functionId)
3187 _ASSERTE(!"FunctionUnloadStarted() callback no longer issued");
3191 HRESULT EEToProfInterfaceImpl::JITCompilationFinished(FunctionID functionId,
3193 BOOL fIsSafeToBlock)
3209 // The JIT / MethodDesc code likely hold locks while this callback is made
3215 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3217 "**PROF: JITCompilationFinished 0x%p, hr=0x%08x.\n",
3221 _ASSERTE(functionId);
3224 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3225 // whose try/catch blocks aren't visible to the contract system
3226 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3227 return m_pCallback2->JITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3232 HRESULT EEToProfInterfaceImpl::JITCompilationStarted(FunctionID functionId,
3233 BOOL fIsSafeToBlock)
3249 // The JIT / MethodDesc code likely hold locks while this callback is made
3255 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3257 "**PROF: JITCompilationStarted 0x%p.\n",
3260 // Currently JITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3261 // it's safe to remove this assert, but this should serve as a trigger to change our
3262 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3263 _ASSERTE(fIsSafeToBlock);
3265 _ASSERTE(functionId);
3268 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3269 // whose try/catch blocks aren't visible to the contract system
3270 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3271 return m_pCallback2->JITCompilationStarted(functionId, fIsSafeToBlock);
3275 HRESULT EEToProfInterfaceImpl::DynamicMethodUnloaded(FunctionID functionId)
3281 MODE_COOPERATIVE; // RuntimeMethodHandle::Destroy (the caller) moves from QCALL to GCX_COOP
3287 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3289 "**PROF: DynamicMethodUnloaded 0x%p.\n",
3292 _ASSERTE(functionId);
3294 if (m_pCallback9 == NULL)
3300 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3301 // whose try/catch blocks aren't visible to the contract system
3302 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3303 return m_pCallback9->DynamicMethodUnloaded(functionId);
3307 HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationFinished(FunctionID functionId,
3309 BOOL fIsSafeToBlock)
3318 // The JIT / MethodDesc code likely hold locks while this callback is made
3324 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3326 "**PROF: DynamicMethodJITCompilationFinished 0x%p.\n",
3329 _ASSERTE(functionId);
3331 if (m_pCallback8 == NULL)
3337 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3338 // whose try/catch blocks aren't visible to the contract system
3339 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3340 return m_pCallback8->DynamicMethodJITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3344 HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationStarted(FunctionID functionId,
3345 BOOL fIsSafeToBlock,
3356 // The JIT / MethodDesc code likely hold locks while this callback is made
3362 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3364 "**PROF: DynamicMethodJITCompilationStarted 0x%p.\n",
3367 _ASSERTE(functionId);
3369 // Currently DynamicMethodJITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3370 // it's safe to remove this assert, but this should serve as a trigger to change our
3371 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3372 _ASSERTE(fIsSafeToBlock);
3374 if (m_pCallback8 == NULL)
3380 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3381 // whose try/catch blocks aren't visible to the contract system
3382 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3383 return m_pCallback8->DynamicMethodJITCompilationStarted(functionId, fIsSafeToBlock, pILHeader, cbILHeader);
3387 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchStarted(
3388 /* [in] */ FunctionID functionId,
3389 /* [out] */ BOOL *pbUseCachedFunction)
3405 // The JIT / MethodDesc code likely hold locks while this callback is made
3411 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3413 "**PROF: JITCachedFunctionSearchStarted 0x%p.\n",
3415 _ASSERTE(functionId);
3416 _ASSERTE(pbUseCachedFunction != NULL);
3419 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3420 // whose try/catch blocks aren't visible to the contract system
3421 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3422 return m_pCallback2->JITCachedFunctionSearchStarted(functionId, pbUseCachedFunction);
3426 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchFinished(
3427 /* [in] */ FunctionID functionId,
3428 /* [in] */ COR_PRF_JIT_CACHE result)
3444 // The JIT / MethodDesc code likely hold locks while this callback is made
3450 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3452 "**PROF: JITCachedFunctionSearchFinished 0x%p, %s.\n",
3454 (result == COR_PRF_CACHED_FUNCTION_FOUND ?
3455 "Cached function found" :
3456 "Cached function not found")));
3458 _ASSERTE(functionId);
3461 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3462 // whose try/catch blocks aren't visible to the contract system
3463 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3464 return m_pCallback2->JITCachedFunctionSearchFinished(functionId, result);
3469 HRESULT EEToProfInterfaceImpl::JITFunctionPitched(FunctionID functionId)
3471 _ASSERTE(!"JITFunctionPitched() callback no longer issued");
3475 HRESULT EEToProfInterfaceImpl::JITInlining(
3476 /* [in] */ FunctionID callerId,
3477 /* [in] */ FunctionID calleeId,
3478 /* [out] */ BOOL * pfShouldInline)
3494 // The JIT / MethodDesc code likely hold locks while this callback is made
3500 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3502 "**PROF: JITInlining caller: 0x%p, callee: 0x%p.\n",
3510 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3511 // whose try/catch blocks aren't visible to the contract system
3512 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3513 return m_pCallback2->JITInlining(callerId, calleeId, pfShouldInline);
3517 HRESULT EEToProfInterfaceImpl::ReJITCompilationStarted(
3518 /* [in] */ FunctionID functionId,
3519 /* [in] */ ReJITID reJitId,
3520 /* [in] */ BOOL fIsSafeToBlock)
3536 // The JIT / MethodDesc code likely hold locks while this callback is made
3542 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3544 "**PROF: ReJITCompilationStarted 0x%p 0x%p.\n",
3545 functionId, reJitId));
3547 // Should only be called on profilers that support ICorProfilerCallback4
3548 _ASSERTE(m_pCallback4 != NULL);
3550 // Currently ReJITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3551 // it's safe to remove this assert, but this should serve as a trigger to change our
3552 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3553 _ASSERTE(fIsSafeToBlock);
3555 _ASSERTE(functionId);
3559 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3560 // whose try/catch blocks aren't visible to the contract system
3561 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3562 return m_pCallback4->ReJITCompilationStarted(functionId, reJitId, fIsSafeToBlock);
3566 HRESULT EEToProfInterfaceImpl::GetReJITParameters(
3567 /* [in] */ ModuleID moduleId,
3568 /* [in] */ mdMethodDef methodId,
3569 /* [in] */ ICorProfilerFunctionControl *
3586 // The ReJIT code holds a lock while this callback is made
3592 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3594 "**PROF: GetReJITParameters 0x%p 0x%p.\n",
3595 moduleId, methodId));
3597 // Should only be called on profilers that support ICorProfilerCallback4
3598 _ASSERTE(m_pCallback4 != NULL);
3603 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3604 // whose try/catch blocks aren't visible to the contract system
3605 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3606 return m_pCallback4->GetReJITParameters(moduleId, methodId, pFunctionControl);
3610 HRESULT EEToProfInterfaceImpl::ReJITCompilationFinished(
3611 /* [in] */ FunctionID functionId,
3612 /* [in] */ ReJITID reJitId,
3613 /* [in] */ HRESULT hrStatus,
3614 /* [in] */ BOOL fIsSafeToBlock)
3630 // ReJit holds a lock as well as possibly others...
3636 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3638 "**PROF: ReJITCompilationFinished 0x%p 0x%p hr=0x%x.\n",
3639 functionId, reJitId, hrStatus));
3641 // Should only be called on profilers that support ICorProfilerCallback4
3642 _ASSERTE(m_pCallback4 != NULL);
3644 _ASSERTE(functionId);
3648 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3649 // whose try/catch blocks aren't visible to the contract system
3650 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3651 return m_pCallback4->ReJITCompilationFinished(functionId, reJitId, hrStatus, fIsSafeToBlock);
3656 HRESULT EEToProfInterfaceImpl::ReJITError(
3657 /* [in] */ ModuleID moduleId,
3658 /* [in] */ mdMethodDef methodId,
3659 /* [in] */ FunctionID functionId,
3660 /* [in] */ HRESULT hrStatus)
3680 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3682 "**PROF: ReJITError 0x%p 0x%x 0x%p 0x%x.\n",
3683 moduleId, methodId, functionId, hrStatus));
3685 // Should only be called on profilers that support ICorProfilerCallback4
3686 _ASSERTE(m_pCallback4 != NULL);
3689 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3690 // whose try/catch blocks aren't visible to the contract system
3691 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3692 return m_pCallback4->ReJITError(moduleId, methodId, functionId, hrStatus);
3696 //---------------------------------------------------------------------------------------
3700 HRESULT EEToProfInterfaceImpl::ModuleLoadStarted(ModuleID moduleId)
3710 // This has historically not run in preemptive, and is called from cooperative-mode
3711 // functions. However, since we're triggers, it might actually be safe to consider
3712 // letting this run in preemptive mode.
3719 ASSERT_NO_EE_LOCKS_HELD();
3725 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3727 "**PROF: ModuleLoadStarted 0x%p.\n",
3730 _ASSERTE(moduleId != 0);
3733 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3734 // whose try/catch blocks aren't visible to the contract system
3735 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3736 return m_pCallback2->ModuleLoadStarted(moduleId);
3741 HRESULT EEToProfInterfaceImpl::ModuleLoadFinished(
3760 ASSERT_NO_EE_LOCKS_HELD();
3766 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3768 "**PROF: ModuleLoadFinished 0x%p.\n",
3771 _ASSERTE(moduleId != 0);
3774 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3775 // whose try/catch blocks aren't visible to the contract system
3776 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3777 return m_pCallback2->ModuleLoadFinished(moduleId, hrStatus);
3783 HRESULT EEToProfInterfaceImpl::ModuleUnloadStarted(
3801 ASSERT_NO_EE_LOCKS_HELD();
3807 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3809 "**PROF: ModuleUnloadStarted 0x%p.\n",
3812 _ASSERTE(moduleId != 0);
3815 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3816 // whose try/catch blocks aren't visible to the contract system
3817 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3818 return m_pCallback2->ModuleUnloadStarted(moduleId);
3823 HRESULT EEToProfInterfaceImpl::ModuleUnloadFinished(
3842 ASSERT_NO_EE_LOCKS_HELD();
3848 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3850 "**PROF: ModuleUnloadFinished 0x%p.\n",
3852 _ASSERTE(moduleId != 0);
3854 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3855 // whose try/catch blocks aren't visible to the contract system
3856 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3857 return m_pCallback2->ModuleUnloadFinished(moduleId, hrStatus);
3862 HRESULT EEToProfInterfaceImpl::ModuleAttachedToAssembly(
3864 AssemblyID AssemblyId)
3881 ASSERT_NO_EE_LOCKS_HELD();
3887 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3889 "**PROF: ModuleAttachedToAssembly 0x%p, 0x%p.\n",
3893 _ASSERTE(moduleId != 0);
3896 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3897 // whose try/catch blocks aren't visible to the contract system
3898 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3899 return m_pCallback2->ModuleAttachedToAssembly(moduleId, AssemblyId);
3903 HRESULT EEToProfInterfaceImpl::ModuleInMemorySymbolsUpdated(ModuleID moduleId)
3923 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3925 "**PROF: ModuleInMemorySymbolsUpdated. moduleId: 0x%p.\n",
3930 _ASSERTE(IsCallback7Supported());
3933 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3934 // whose try/catch blocks aren't visible to the contract system
3935 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3936 hr = m_pCallback7->ModuleInMemorySymbolsUpdated(moduleId);
3942 //---------------------------------------------------------------------------------------
3946 HRESULT EEToProfInterfaceImpl::ClassLoadStarted(
3963 // UnresolvedClassLock typically held during this callback
3969 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3971 "**PROF: ClassLoadStarted 0x%p.\n",
3977 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3978 // whose try/catch blocks aren't visible to the contract system
3979 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3980 return m_pCallback2->ClassLoadStarted(classId);
3985 HRESULT EEToProfInterfaceImpl::ClassLoadFinished(
4003 // UnresolvedClassLock typically held during this callback
4009 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4011 "**PROF: ClassLoadFinished 0x%p, 0x%08x.\n",
4018 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4019 // whose try/catch blocks aren't visible to the contract system
4020 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4021 return m_pCallback2->ClassLoadFinished(classId, hrStatus);
4026 HRESULT EEToProfInterfaceImpl::ClassUnloadStarted(
4043 // Although not typical, it's possible for UnresolvedClassLock to be held
4044 // during this callback. This can occur if, during the class load, an
4045 // exception is thrown, and EEClass::Destruct is called from the catch clause
4046 // inside ClassLoader::CreateTypeHandleForTypeDefThrowing.
4052 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4054 "**PROF: ClassUnloadStarted 0x%p.\n",
4060 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4061 // whose try/catch blocks aren't visible to the contract system
4062 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4063 return m_pCallback2->ClassUnloadStarted(classId);
4068 HRESULT EEToProfInterfaceImpl::ClassUnloadFinished(
4086 // Locks can be held when this is called. See comment in ClassUnloadStarted
4092 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4094 "**PROF: ClassUnloadFinished 0x%p, 0x%08x.\n",
4101 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4102 // whose try/catch blocks aren't visible to the contract system
4103 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4104 return m_pCallback2->ClassUnloadFinished(classId, hrStatus);
4108 //---------------------------------------------------------------------------------------
4112 HRESULT EEToProfInterfaceImpl::AppDomainCreationStarted(
4113 AppDomainID appDomainId)
4130 ASSERT_NO_EE_LOCKS_HELD();
4136 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4138 "**PROF: AppDomainCreationStarted 0x%p.\n",
4141 _ASSERTE(appDomainId != 0);
4144 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4145 // whose try/catch blocks aren't visible to the contract system
4146 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4147 return m_pCallback2->AppDomainCreationStarted(appDomainId);
4152 HRESULT EEToProfInterfaceImpl::AppDomainCreationFinished(
4153 AppDomainID appDomainId,
4171 ASSERT_NO_EE_LOCKS_HELD();
4177 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4179 "**PROF: AppDomainCreationFinished 0x%p, 0x%08x.\n",
4183 _ASSERTE(appDomainId != 0);
4186 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4187 // whose try/catch blocks aren't visible to the contract system
4188 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4189 return m_pCallback2->AppDomainCreationFinished(appDomainId, hrStatus);
4193 HRESULT EEToProfInterfaceImpl::AppDomainShutdownStarted(
4194 AppDomainID appDomainId)
4211 ASSERT_NO_EE_LOCKS_HELD();
4217 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4219 "**PROF: AppDomainShutdownStarted 0x%p.\n",
4222 _ASSERTE(appDomainId != 0);
4225 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4226 // whose try/catch blocks aren't visible to the contract system
4227 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4228 return m_pCallback2->AppDomainShutdownStarted(appDomainId);
4232 HRESULT EEToProfInterfaceImpl::AppDomainShutdownFinished(
4233 AppDomainID appDomainId,
4251 ASSERT_NO_EE_LOCKS_HELD();
4257 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4259 "**PROF: AppDomainShutdownFinished 0x%p, 0x%08x.\n",
4263 _ASSERTE(appDomainId != 0);
4266 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4267 // whose try/catch blocks aren't visible to the contract system
4268 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4269 return m_pCallback2->AppDomainShutdownFinished(appDomainId, hrStatus);
4273 //---------------------------------------------------------------------------------------
4277 HRESULT EEToProfInterfaceImpl::AssemblyLoadStarted(
4278 AssemblyID assemblyId)
4288 // This has historically not run in preemptive, and is called from cooperative-mode
4289 // functions. However, since we're triggers, it might actually be safe to consider
4290 // letting this run in preemptive mode.
4297 ASSERT_NO_EE_LOCKS_HELD();
4303 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4305 "**PROF: AssemblyLoadStarted 0x%p.\n",
4308 _ASSERTE(assemblyId != 0);
4311 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4312 // whose try/catch blocks aren't visible to the contract system
4313 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4314 return m_pCallback2->AssemblyLoadStarted(assemblyId);
4318 HRESULT EEToProfInterfaceImpl::AssemblyLoadFinished(
4319 AssemblyID assemblyId,
4330 // This has historically not run in preemptive, and is called from cooperative-mode
4331 // functions. However, since we're triggers, it might actually be safe to consider
4332 // letting this run in preemptive mode.
4339 ASSERT_NO_EE_LOCKS_HELD();
4345 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4347 "**PROF: AssemblyLoadFinished 0x%p, 0x%08x.\n",
4351 _ASSERTE(assemblyId != 0);
4354 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4355 // whose try/catch blocks aren't visible to the contract system
4356 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4357 return m_pCallback2->AssemblyLoadFinished(assemblyId, hrStatus);
4361 HRESULT EEToProfInterfaceImpl::AssemblyUnloadStarted(
4362 AssemblyID assemblyId)
4379 ASSERT_NO_EE_LOCKS_HELD();
4385 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4387 "**PROF: AssemblyUnloadStarted 0x%p.\n",
4390 _ASSERTE(assemblyId != 0);
4393 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4394 // whose try/catch blocks aren't visible to the contract system
4395 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4396 return m_pCallback2->AssemblyUnloadStarted(assemblyId);
4400 HRESULT EEToProfInterfaceImpl::AssemblyUnloadFinished(
4401 AssemblyID assemblyId,
4419 ASSERT_NO_EE_LOCKS_HELD();
4425 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4427 "**PROF: AssemblyUnloadFinished 0x%p, 0x%08x.\n",
4431 _ASSERTE(assemblyId != 0);
4434 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4435 // whose try/catch blocks aren't visible to the contract system
4436 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4437 return m_pCallback2->AssemblyUnloadFinished(assemblyId, hrStatus);
4441 //---------------------------------------------------------------------------------------
4442 // TRANSITION EVENTS
4445 HRESULT EEToProfInterfaceImpl::UnmanagedToManagedTransition(
4446 FunctionID functionId,
4447 COR_PRF_TRANSITION_REASON reason)
4464 ASSERT_NO_EE_LOCKS_HELD();
4470 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4472 "**PROF: UnmanagedToManagedTransition 0x%p.\n",
4475 _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4478 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4479 // whose try/catch blocks aren't visible to the contract system
4480 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4481 return m_pCallback2->UnmanagedToManagedTransition(functionId, reason);
4485 HRESULT EEToProfInterfaceImpl::ManagedToUnmanagedTransition(
4486 FunctionID functionId,
4487 COR_PRF_TRANSITION_REASON reason)
4504 ASSERT_NO_EE_LOCKS_HELD();
4510 _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4512 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4514 "**PROF: ManagedToUnmanagedTransition 0x%p.\n",
4518 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4519 // whose try/catch blocks aren't visible to the contract system
4520 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4521 return m_pCallback2->ManagedToUnmanagedTransition(functionId, reason);
4525 //---------------------------------------------------------------------------------------
4529 HRESULT EEToProfInterfaceImpl::ExceptionThrown(
4530 ObjectID thrownObjectId)
4540 // Preemptive mode would be bad, dude. There's an objectId in the param list!
4547 ASSERT_NO_EE_LOCKS_HELD();
4553 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4555 "**PROF: ExceptionThrown. ObjectID: 0x%p. ThreadID: 0x%p\n",
4560 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4561 // whose try/catch blocks aren't visible to the contract system
4562 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4563 return m_pCallback2->ExceptionThrown(thrownObjectId);
4567 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionEnter(
4568 FunctionID functionId)
4585 ASSERT_NO_EE_LOCKS_HELD();
4591 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4593 "**PROF: ExceptionSearchFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4598 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4599 // whose try/catch blocks aren't visible to the contract system
4600 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4601 return m_pCallback2->ExceptionSearchFunctionEnter(functionId);
4605 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionLeave()
4622 ASSERT_NO_EE_LOCKS_HELD();
4628 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4630 "**PROF: ExceptionSearchFunctionLeave. ThreadID: 0x%p\n",
4634 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4635 // whose try/catch blocks aren't visible to the contract system
4636 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4637 return m_pCallback2->ExceptionSearchFunctionLeave();
4641 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterEnter(FunctionID functionId)
4658 ASSERT_NO_EE_LOCKS_HELD();
4664 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4666 "**PROF: ExceptionSearchFilterEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4671 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4672 // whose try/catch blocks aren't visible to the contract system
4673 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4674 return m_pCallback2->ExceptionSearchFilterEnter(functionId);
4678 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterLeave()
4695 ASSERT_NO_EE_LOCKS_HELD();
4701 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4703 "**PROF: ExceptionFilterLeave. ThreadID: 0x%p\n",
4707 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4708 // whose try/catch blocks aren't visible to the contract system
4709 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4710 return m_pCallback2->ExceptionSearchFilterLeave();
4714 HRESULT EEToProfInterfaceImpl::ExceptionSearchCatcherFound(FunctionID functionId)
4731 ASSERT_NO_EE_LOCKS_HELD();
4737 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4739 "**PROF: ExceptionSearchCatcherFound. ThreadID: 0x%p\n",
4743 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4744 // whose try/catch blocks aren't visible to the contract system
4745 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4746 return m_pCallback2->ExceptionSearchCatcherFound(functionId);
4750 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerEnter(FunctionID functionId)
4752 _ASSERTE(!"ExceptionOSHandlerEnter() callback no longer issued");
4756 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerLeave(FunctionID functionId)
4758 _ASSERTE(!"ExceptionOSHandlerLeave() callback no longer issued");
4762 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionEnter(FunctionID functionId)
4769 // Called by COMPlusUnwindCallback, which is notrigger
4772 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4773 // Thus, the profiler cannot block on this call.
4780 ASSERT_NO_EE_LOCKS_HELD();
4786 CLR_TO_PROFILER_ENTRYPOINT_EX(
4790 "**PROF: ExceptionUnwindFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4795 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4796 // whose try/catch blocks aren't visible to the contract system
4797 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4798 return m_pCallback2->ExceptionUnwindFunctionEnter(functionId);
4802 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionLeave()
4809 // Called by COMPlusUnwindCallback, which is notrigger
4812 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4813 // Thus, the profiler cannot block on this call.
4820 ASSERT_NO_EE_LOCKS_HELD();
4826 CLR_TO_PROFILER_ENTRYPOINT_EX(
4830 "**PROF: ExceptionUnwindFunctionLeave. ThreadID: 0x%p\n",
4834 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4835 // whose try/catch blocks aren't visible to the contract system
4836 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4837 return m_pCallback2->ExceptionUnwindFunctionLeave();
4841 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyEnter(FunctionID functionId)
4848 // Called by COMPlusUnwindCallback, which is notrigger
4851 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4852 // Thus, the profiler cannot block on this call.
4859 ASSERT_NO_EE_LOCKS_HELD();
4865 CLR_TO_PROFILER_ENTRYPOINT_EX(
4869 "**PROF: ExceptionUnwindFinallyEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4874 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4875 // whose try/catch blocks aren't visible to the contract system
4876 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4877 return m_pCallback2->ExceptionUnwindFinallyEnter(functionId);
4881 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyLeave()
4888 // Called by COMPlusUnwindCallback, which is notrigger
4891 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4892 // Thus, the profiler cannot block on this call.
4899 ASSERT_NO_EE_LOCKS_HELD();
4905 CLR_TO_PROFILER_ENTRYPOINT_EX(
4909 "**PROF: ExceptionUnwindFinallyLeave. ThreadID: 0x%p\n",
4913 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4914 // whose try/catch blocks aren't visible to the contract system
4915 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4916 return m_pCallback2->ExceptionUnwindFinallyLeave();
4920 HRESULT EEToProfInterfaceImpl::ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId)
4927 // Called by COMPlusUnwindCallback, which is notrigger
4930 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4931 // Thus, the profiler cannot block on this call.
4938 ASSERT_NO_EE_LOCKS_HELD();
4944 CLR_TO_PROFILER_ENTRYPOINT_EX(
4947 LL_INFO1000, "**PROF: ExceptionCatcherEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4952 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4953 // whose try/catch blocks aren't visible to the contract system
4954 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4955 return m_pCallback2->ExceptionCatcherEnter(functionId, objectId);
4959 HRESULT EEToProfInterfaceImpl::ExceptionCatcherLeave()
4969 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4970 // Thus, the profiler cannot block on this call.
4977 ASSERT_NO_EE_LOCKS_HELD();
4983 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4985 "**PROF: ExceptionCatcherLeave. ThreadID: 0x%p\n",
4990 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4991 // whose try/catch blocks aren't visible to the contract system
4992 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4993 return m_pCallback2->ExceptionCatcherLeave();
4998 //---------------------------------------------------------------------------------------
4999 // COM Callable Wrapper EVENTS
5002 HRESULT EEToProfInterfaceImpl::COMClassicVTableCreated(
5003 /* [in] */ ClassID classId,
5004 /* [in] */ REFGUID implementedIID,
5005 /* [in] */ void *pVTable,
5006 /* [in] */ ULONG cSlots)
5023 ASSERT_NO_EE_LOCKS_HELD();
5029 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5031 "**PROF: COMClassicWrapperCreated %#x %#08x... %#x %d.\n",
5033 implementedIID.Data1,
5038 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5039 // whose try/catch blocks aren't visible to the contract system
5040 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5041 return m_pCallback2->COMClassicVTableCreated(classId, implementedIID, pVTable, cSlots);
5045 HRESULT EEToProfInterfaceImpl::COMClassicVTableDestroyed(
5046 /* [in] */ ClassID classId,
5047 /* [in] */ REFGUID implementedIID,
5048 /* [in] */ void *pVTable)
5065 ASSERT_NO_EE_LOCKS_HELD();
5071 // NOTE: There is no problem with this code, and it is ready and willing
5072 // to be called. However, this callback is intentionally not being
5073 // issued currently. See comment in ComMethodTable::Cleanup() for more
5076 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5078 "**PROF: COMClassicWrapperDestroyed %#x %#08x... %#x.\n",
5080 implementedIID.Data1,
5084 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5085 // whose try/catch blocks aren't visible to the contract system
5086 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5087 return m_pCallback2->COMClassicVTableDestroyed(classId, implementedIID, pVTable);
5092 //---------------------------------------------------------------------------------------
5093 // GC THREADING EVENTS
5096 HRESULT EEToProfInterfaceImpl::RuntimeSuspendStarted(
5097 COR_PRF_SUSPEND_REASON suspendReason)
5104 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5105 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5106 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
5107 // this thread at this time, we might see potential recursion or deadlock.
5115 // Thread store lock is typically held during this callback
5121 CLR_TO_PROFILER_ENTRYPOINT_EX(
5125 "**PROF: RuntimeSuspendStarted. ThreadID 0x%p.\n",
5129 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5130 // whose try/catch blocks aren't visible to the contract system
5131 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5132 return m_pCallback2->RuntimeSuspendStarted(suspendReason);
5136 HRESULT EEToProfInterfaceImpl::RuntimeSuspendFinished()
5143 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5144 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5145 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
5146 // this thread at this time, we might see potential recursion or deadlock.
5154 // Thread store lock is typically held during this callback
5160 CLR_TO_PROFILER_ENTRYPOINT_EX(
5164 "**PROF: RuntimeSuspendFinished. ThreadID 0x%p.\n",
5169 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5170 // whose try/catch blocks aren't visible to the contract system
5171 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5172 return m_pCallback2->RuntimeSuspendFinished();
5176 HRESULT EEToProfInterfaceImpl::RuntimeSuspendAborted()
5183 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5184 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5185 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
5186 // this thread at this time, we might see potential recursion or deadlock.
5189 // NOTE: I have no empirical data for gc mode: none of the self-host BVTs call this
5190 // So for now, assume this is callable in any mode.
5191 // This has historically not caused a mode change to preemptive, and is called from
5192 // cooperative-mode functions. Also, switching to preemptive while we're suspending
5193 // the runtime just seems like a bad idea.
5199 // Thread store lock is typically held during this callback
5205 CLR_TO_PROFILER_ENTRYPOINT_EX(
5209 "**PROF: RuntimeSuspendAborted. ThreadID 0x%p.\n",
5213 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5214 // whose try/catch blocks aren't visible to the contract system
5215 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5216 return m_pCallback2->RuntimeSuspendAborted();
5220 HRESULT EEToProfInterfaceImpl::RuntimeResumeStarted()
5230 // This has historically not caused a mode change to preemptive, and is called from
5231 // cooperative-mode functions. Also, switching to preemptive while we're resuming
5232 // the runtime just seems like a bad idea.
5238 // Thread store lock is typically held during this callback
5244 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5246 "**PROF: RuntimeResumeStarted. ThreadID 0x%p.\n",
5250 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5251 // whose try/catch blocks aren't visible to the contract system
5252 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5253 return m_pCallback2->RuntimeResumeStarted();
5257 HRESULT EEToProfInterfaceImpl::RuntimeResumeFinished()
5273 // Thread store lock is typically held during this callback
5279 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5281 "**PROF: RuntimeResumeFinished. ThreadID 0x%p.\n",
5285 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5286 // whose try/catch blocks aren't visible to the contract system
5287 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5288 return m_pCallback2->RuntimeResumeFinished();
5292 HRESULT EEToProfInterfaceImpl::RuntimeThreadSuspended(ThreadID suspendedThreadId)
5299 // Called by Thread::SuspendThread, which is notrigger.
5302 // Although I've verified we're called from both coop and preemp, we need to
5303 // avoid switching to preemptive to satisfy our notrigger paths.
5309 // Thread store lock is typically held during this callback
5315 if (reinterpret_cast<Thread *>(suspendedThreadId)->IsGCSpecial())
5318 // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5319 // we might be called at a time when profiler callbacks have been disallowed for
5320 // this thread. So we cannot simply ASSERT that callbacks are allowed (as this macro
5321 // does). Instead, we must explicitly check for this condition and return gracefully
5322 // if callbacks are disallowed. So the macro is unwrapped here manually
5324 CHECK_PROFILER_STATUS(kEE2PNone);
5326 LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadSuspended. ThreadID 0x%p.\n",
5327 suspendedThreadId));
5329 // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5331 // We may have already indicated to the profiler that this thread has died, but
5332 // the runtime may continue to suspend this thread during the process of destroying
5333 // the thread, so we do not want to indicate to the profiler these suspensions.
5334 if (!ProfilerCallbacksAllowedForThread((Thread *) suspendedThreadId))
5339 // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5340 SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5341 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
5342 _ASSERTE(m_pCallback2 != NULL);
5345 // SCOPE: ForbidSuspendThreadHolder
5347 // The ForbidSuspendThreadHolder prevents deadlocks under the following scenario:
5348 // 1) Thread A blocks waiting for the current GC to complete (this can happen if A is trying to
5349 // switch to cooperative during a GC).
5350 // 2) This causes us to send a RuntimeThreadSuspended callback to the profiler. (Although
5351 // A isn't technically being "suspended", this blocking is considered suspension as far as the
5352 // profapi is concerned.)
5353 // 3) Profiler, in turn, may take one of its own private locks to synchronize this callback with
5354 // the profiler's attempt to hijack thread A. Specifically, the profiler knows it's not allowed
5355 // to hijack A if A is getting suspended by the runtime, because this suspension might be due to
5356 // the GC trying to hijack A. And if the GC tries to hijack A at the same time as the profiler
5357 // hijacking A and the profiler wins, then GC asserts because A is no longer at the IP that
5358 // the GC thought (VsWhidbey 428477, 429741)
5359 // 4) Meanwhile, thread B (GC thread) is suspending the runtime, and calls Thread::SuspendThread()
5360 // on A. This is the bad thing we're trying to avoid, because when this happens, we call into
5361 // the profiler AGAIN with RuntimeThreadSuspended for thread A, and the profiler again
5362 // tries to grab the lock it acquired in step 3). Yes, at this point we now have two simultaneous
5363 // calls into the profiler's RuntimeThreadSuspended() callback. One saying A is suspending A
5364 // (3 above), and one saying B is suspending A (this step (4)). The problem is that A is now officially
5365 // hard suspended, OS-style, so the lock acquired on 3) ain't never getting released until
5366 // A is resumed. But A won't be resumed until B resumes it. And B won't resume A until
5367 // the profiler returns from its RuntimeThreadSuspended callback. And the profiler
5368 // can't return from its RuntimeThreadSuspended callback until it acquires this lock it tried to
5369 // acquire in 4). And it can't acquire this lock until A is finally resumed so that the acquire
5370 // from 3) is released. Have we gone in a circle yet?
5371 // In order to avoid 4) we inc the ForbidSuspendThread count during 3) to prevent the hard suspension
5372 // (4) from occurring until 3) is completely done. It's sufficient to determine we're in 3) by noting
5373 // whether the callback is reporting that a thread is "suspending itself" (i.e., suspendedThreadId == threadId)
5375 ForbidSuspendThreadHolder forbidSuspendThread((Thread *) suspendedThreadId == GetThread());
5378 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5379 // whose try/catch blocks aren't visible to the contract system
5380 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5381 return m_pCallback2->RuntimeThreadSuspended(suspendedThreadId);
5386 HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId)
5393 // This gets called in response to another profapi function:
5394 // ICorProfilerInfo2::DoStackSnapshot! And that dude is called asynchronously and
5395 // must therefore never cause a GC.
5396 // Other reasons for notrigger: also called by notrigger dudes Thread::SysStartSuspendForDebug,
5397 // CheckSuspended, Thread::IsRunningIn, Thread::IsExecutingWithinCer, Thread::IsExecutingWithinCer,
5401 // Although we cannot trigger, verified empirically that this called coop & preemp
5407 // Thread store lock is typically held during this callback
5413 if (reinterpret_cast<Thread *>(resumedThreadId)->IsGCSpecial())
5416 // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5417 // we might be called at a time when profiler callbacks have been disallowed for
5418 // this thread. So we cannot simply ASSERT that callbacks are allowed (as this macro
5419 // does). Instead, we must explicitly check for this condition and return gracefully
5420 // if callbacks are disallowed. So the macro is unwrapped here manually
5422 CHECK_PROFILER_STATUS(kEE2PNone);
5424 LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadResumed. ThreadID 0x%p.\n", resumedThreadId));
5426 // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5428 // We may have already indicated to the profiler that this thread has died, but
5429 // the runtime may resume this thread during the process of destroying
5430 // the thread, so we do not want to indicate to the profiler these resumes.
5431 if (!ProfilerCallbacksAllowedForThread((Thread *) resumedThreadId))
5436 // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5437 SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5438 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
5439 _ASSERTE(m_pCallback2 != NULL);
5442 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5443 // whose try/catch blocks aren't visible to the contract system
5444 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5445 return m_pCallback2->RuntimeThreadResumed(resumedThreadId);
5449 //---------------------------------------------------------------------------------------
5453 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationStarted()
5470 ASSERT_NO_EE_LOCKS_HELD();
5476 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5478 "**PROF: RemotingClientInvocationStarted. ThreadID: 0x%p\n",
5482 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5483 // whose try/catch blocks aren't visible to the contract system
5484 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5485 return m_pCallback2->RemotingClientInvocationStarted();
5489 HRESULT EEToProfInterfaceImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync)
5506 ASSERT_NO_EE_LOCKS_HELD();
5512 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5514 "**PROF: RemotingClientSendingMessage. ThreadID: 0x%p\n",
5518 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5519 // whose try/catch blocks aren't visible to the contract system
5520 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5521 return m_pCallback2->RemotingClientSendingMessage(pCookie, fIsAsync);
5525 HRESULT EEToProfInterfaceImpl::RemotingClientReceivingReply(GUID * pCookie, BOOL fIsAsync)
5542 ASSERT_NO_EE_LOCKS_HELD();
5548 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5550 "**PROF: RemotingClientReceivingReply. ThreadID: 0x%p\n",
5554 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5555 // whose try/catch blocks aren't visible to the contract system
5556 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5557 return m_pCallback2->RemotingClientReceivingReply(pCookie, fIsAsync);
5561 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationFinished()
5578 ASSERT_NO_EE_LOCKS_HELD();
5584 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5586 "**PROF: RemotingClientInvocationFinished. ThreadID: 0x%p\n",
5590 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5591 // whose try/catch blocks aren't visible to the contract system
5592 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5593 return m_pCallback2->RemotingClientInvocationFinished();
5597 HRESULT EEToProfInterfaceImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync)
5614 ASSERT_NO_EE_LOCKS_HELD();
5620 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5622 "**PROF: RemotingServerReceivingMessage. ThreadID: 0x%p\n",
5626 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5627 // whose try/catch blocks aren't visible to the contract system
5628 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5629 return m_pCallback2->RemotingServerReceivingMessage(pCookie, fIsAsync);
5633 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationStarted()
5650 ASSERT_NO_EE_LOCKS_HELD();
5656 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5658 "**PROF: RemotingServerInvocationStarted. ThreadID: 0x%p\n",
5662 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5663 // whose try/catch blocks aren't visible to the contract system
5664 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5665 return m_pCallback2->RemotingServerInvocationStarted();
5669 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationReturned()
5686 ASSERT_NO_EE_LOCKS_HELD();
5692 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5694 "**PROF: RemotingServerInvocationReturned. ThreadID: 0x%p\n",
5698 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5699 // whose try/catch blocks aren't visible to the contract system
5700 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5701 return m_pCallback2->RemotingServerInvocationReturned();
5705 HRESULT EEToProfInterfaceImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync)
5722 ASSERT_NO_EE_LOCKS_HELD();
5728 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5730 "**PROF: RemotingServerSendingReply. ThreadID: 0x%p\n",
5734 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5735 // whose try/catch blocks aren't visible to the contract system
5736 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5737 return m_pCallback2->RemotingServerSendingReply(pCookie, fIsAsync);
5741 //---------------------------------------------------------------------------------------
5745 HRESULT EEToProfInterfaceImpl::ObjectAllocated(
5746 /* [in] */ ObjectID objectId,
5747 /* [in] */ ClassID classId)
5757 // Preemptive mode would be bad, dude. There's an objectId in the param list!
5763 // CrstAppDomainHandleTable can be held while this is called
5769 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5771 "**PROF: ObjectAllocated. ObjectID: 0x%p. ClassID: 0x%p\n",
5776 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5777 // whose try/catch blocks aren't visible to the contract system
5778 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5779 return m_pCallback2->ObjectAllocated(objectId, classId);
5784 HRESULT EEToProfInterfaceImpl::MovedReferences(GCReferencesData *pData)
5791 // This is called by the thread doing a GC WHILE it does the GC
5794 // This is called by the thread doing a GC WHILE it does the GC
5795 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5800 // Thread store lock normally held during this callback
5806 CLR_TO_PROFILER_ENTRYPOINT_EX(
5810 "**PROF: MovedReferences.\n"));
5812 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5814 if (pData->curIdx == 0)
5821 if (pData->compactingCount != 0)
5823 _ASSERTE(pData->curIdx == pData->compactingCount);
5825 if (m_pCallback4 != NULL)
5827 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5828 // whose try/catch blocks aren't visible to the contract system
5829 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5830 hr = m_pCallback4->MovedReferences2((ULONG)pData->curIdx,
5831 (ObjectID *)pData->arrpbMemBlockStartOld,
5832 (ObjectID *)pData->arrpbMemBlockStartNew,
5833 (SIZE_T *)pData->arrMemBlockSize);
5839 // Recompute sizes as ULONGs for legacy callback
5840 for (ULONG i = 0; i < pData->curIdx; i++)
5841 pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5845 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5846 // whose try/catch blocks aren't visible to the contract system
5847 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5848 hr = m_pCallback2->MovedReferences((ULONG)pData->curIdx,
5849 (ObjectID *)pData->arrpbMemBlockStartOld,
5850 (ObjectID *)pData->arrpbMemBlockStartNew,
5856 if (m_pCallback4 != NULL)
5858 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5859 // whose try/catch blocks aren't visible to the contract system
5860 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5861 hr = m_pCallback4->SurvivingReferences2((ULONG)pData->curIdx,
5862 (ObjectID *)pData->arrpbMemBlockStartOld,
5863 (SIZE_T *)pData->arrMemBlockSize);
5869 // Recompute sizes as ULONGs for legacy callback
5870 for (ULONG i = 0; i < pData->curIdx; i++)
5871 pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5875 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5876 // whose try/catch blocks aren't visible to the contract system
5877 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5878 hr = m_pCallback2->SurvivingReferences((ULONG)pData->curIdx,
5879 (ObjectID *)pData->arrpbMemBlockStartOld,
5887 HRESULT EEToProfInterfaceImpl::NotifyAllocByClass(AllocByClassData *pData)
5894 // This is called by the thread doing a GC WHILE it does the GC
5897 // This is called by the thread doing a GC WHILE it does the GC
5898 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5903 // Thread store lock normally held during this callback
5909 CLR_TO_PROFILER_ENTRYPOINT_EX(
5913 "**PROF: ObjectsAllocatedByClass.\n"));
5915 _ASSERTE(pData != NULL);
5916 _ASSERTE(pData->iHash > 0);
5918 // If the arrays are not long enough, get rid of them.
5919 if (pData->cLength != 0 && pData->iHash > pData->cLength)
5921 _ASSERTE(pData->arrClsId != NULL && pData->arrcObjects != NULL);
5922 delete [] pData->arrClsId;
5923 delete [] pData->arrcObjects;
5927 // If there are no arrays, must allocate them.
5928 if (pData->cLength == 0)
5930 pData->arrClsId = new (nothrow) ClassID[pData->iHash];
5931 if (pData->arrClsId == NULL)
5933 return E_OUTOFMEMORY;
5936 pData->arrcObjects = new (nothrow) ULONG[pData->iHash];
5937 if (pData->arrcObjects == NULL)
5939 delete [] pData->arrClsId;
5940 pData->arrClsId= NULL;
5942 return E_OUTOFMEMORY;
5945 // Indicate that the memory was successfully allocated
5946 pData->cLength = pData->iHash;
5949 // Now copy all the data
5951 CLASSHASHENTRY * pCur = (CLASSHASHENTRY *) pData->pHashTable->FindFirstEntry(&hFind);
5952 size_t iCur = 0; // current index for arrays
5954 while (pCur != NULL)
5956 _ASSERTE(iCur < pData->iHash);
5958 pData->arrClsId[iCur] = pCur->m_clsId;
5959 pData->arrcObjects[iCur] = (DWORD) pCur->m_count;
5961 // Move to the next entry
5963 pCur = (CLASSHASHENTRY *) pData->pHashTable->FindNextEntry(&hFind);
5966 _ASSERTE(iCur == pData->iHash);
5968 // Now communicate the results to the profiler
5970 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5971 // whose try/catch blocks aren't visible to the contract system
5972 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5973 return m_pCallback2->ObjectsAllocatedByClass((ULONG)pData->iHash, pData->arrClsId, pData->arrcObjects);
5977 HRESULT EEToProfInterfaceImpl::ObjectReference(ObjectID objId,
5980 ObjectID *arrObjRef)
5987 // This is called by the thread doing a GC WHILE it does the GC
5990 // This is called by the thread doing a GC WHILE it does the GC
5991 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5996 // Thread store lock normally held during this callback
6002 CLR_TO_PROFILER_ENTRYPOINT_EX(
6006 "**PROF: ObjectReferences.\n"));
6008 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6011 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6012 // whose try/catch blocks aren't visible to the contract system
6013 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6014 return m_pCallback2->ObjectReferences(objId, classId, cNumRefs, arrObjRef);
6019 HRESULT EEToProfInterfaceImpl::FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID)
6029 // Can't be in preemptive when we're dealing in objectIDs!
6030 // However, it's possible we're on a non-EE Thread--that happens when this
6031 // is a server-mode GC thread.
6037 // Thread store lock normally held during this callback
6043 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
6045 "**PROF: Notifying profiler of finalizeable object.\n"));
6047 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6050 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6051 // whose try/catch blocks aren't visible to the contract system
6052 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6053 return m_pCallback2->FinalizeableObjectQueued(isCritical ? COR_PRF_FINALIZER_CRITICAL : 0, objectID);
6058 HRESULT EEToProfInterfaceImpl::RootReferences2(GCReferencesData *pData)
6065 // This is called by the thread doing a GC WHILE it does the GC
6068 // This is called by the thread doing a GC WHILE it does the GC
6069 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6074 // Thread store lock normally held during this callback
6080 CLR_TO_PROFILER_ENTRYPOINT_EX(
6084 "**PROF: RootReferences2.\n"));
6086 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6090 COR_PRF_GC_ROOT_FLAGS flags[kcReferencesMax];
6092 _ASSERTE(pData->curIdx <= kcReferencesMax);
6093 for (ULONG i = 0; i < pData->curIdx; i++)
6095 flags[i] = (COR_PRF_GC_ROOT_FLAGS)(pData->arrULONG[i] & 0xffff);
6096 pData->arrULONG[i] >>= 16;
6100 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6101 // whose try/catch blocks aren't visible to the contract system
6102 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6103 hr = m_pCallback2->RootReferences2((ULONG)pData->curIdx,
6104 (ObjectID *)pData->arrpbMemBlockStartOld,
6105 (COR_PRF_GC_ROOT_KIND *)pData->arrULONG,
6107 (ObjectID *)pData->arrpbMemBlockStartNew);
6113 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6114 // whose try/catch blocks aren't visible to the contract system
6115 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6116 hr = m_pCallback2->RootReferences((ULONG)pData->curIdx, (ObjectID *)pData->arrpbMemBlockStartOld);
6123 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReferences(GCReferencesData * pData)
6130 // This is called by the thread doing a GC WHILE it does the GC
6133 // This is called by the thread doing a GC WHILE it does the GC
6134 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6139 // Thread store lock normally held during this callback
6145 CLR_TO_PROFILER_ENTRYPOINT_EX(
6149 "**PROF: ConditionalWeakTableElementReferences.\n"));
6151 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6155 _ASSERTE(pData->curIdx <= kcReferencesMax);
6158 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6159 // whose try/catch blocks aren't visible to the contract system
6160 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6161 hr = m_pCallback5->ConditionalWeakTableElementReferences(
6162 (ULONG)pData->curIdx,
6163 (ObjectID *)pData->arrpbMemBlockStartOld,
6164 (ObjectID *)pData->arrpbMemBlockStartNew,
6165 (GCHandleID *)pData->arrpbRootId);
6171 HRESULT EEToProfInterfaceImpl::HandleCreated(UINT_PTR handleId, ObjectID initialObjectId)
6178 // Called by HndCreateHandle which is notrigger
6181 // This can be called in preemptive mode if initialObjectId is NULL.
6182 // Otherwise, this will be in cooperative mode. Note that, although this
6183 // can be called in preemptive, when it's called in cooperative we must not
6184 // switch to preemptive (as we normally do in callbacks) and must not trigger,
6185 // as this would really tick off some of our callers (as well as invalidating
6186 // initialObjectId).
6187 if (initialObjectId != NULL)
6199 // CrstAppDomainHandleTable can be held during this callback
6205 CLR_TO_PROFILER_ENTRYPOINT_EX(
6209 "**PROF: HandleCreated.\n"));
6212 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6213 // whose try/catch blocks aren't visible to the contract system
6214 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6215 return m_pCallback2->HandleCreated(handleId, initialObjectId);
6219 HRESULT EEToProfInterfaceImpl::HandleDestroyed(UINT_PTR handleId)
6226 // Called by HndDestroyHandle, which is notrigger. But HndDestroyHandle is also
6227 // MODE_ANY, so perhaps we can change the whole call path to be triggers?
6230 // Although we're called from a notrigger function, I verified empirically that
6231 // this is called coop & preemp
6237 // Thread store lock is typically held during this callback
6243 CLR_TO_PROFILER_ENTRYPOINT_EX(
6247 "**PROF: HandleDestroyed.\n"));
6250 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6251 // whose try/catch blocks aren't visible to the contract system
6252 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6253 return m_pCallback2->HandleDestroyed(handleId);
6257 HRESULT EEToProfInterfaceImpl::GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason)
6264 // This is called by the thread doing a GC WHILE it does the GC
6267 // This is called by the thread doing a GC WHILE it does the GC
6268 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6273 // Thread store lock normally held during this callback
6279 CLR_TO_PROFILER_ENTRYPOINT_EX(
6283 "**PROF: GarbageCollectionStarted.\n"));
6285 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6288 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6289 // whose try/catch blocks aren't visible to the contract system
6290 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6291 return m_pCallback2->GarbageCollectionStarted(cGenerations, generationCollected, reason);
6295 HRESULT EEToProfInterfaceImpl::GarbageCollectionFinished()
6302 // This is called by the thread doing a GC WHILE it does the GC
6305 // This is called by the thread doing a GC WHILE it does the GC
6306 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6311 // Thread store lock normally held during this callback
6317 CLR_TO_PROFILER_ENTRYPOINT_EX(
6321 "**PROF: GarbageCollectionFinished.\n"));
6323 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6326 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6327 // whose try/catch blocks aren't visible to the contract system
6328 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6329 return m_pCallback2->GarbageCollectionFinished();
6333 HRESULT EEToProfInterfaceImpl::ProfilerDetachSucceeded()
6349 // ProfilingAPIUtility::s_csStatus is held while this callback is issued.
6355 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileDetaching,
6358 "**PROF: ProfilerDetachSucceeded.\n"));
6360 // Should only be called on profilers that support ICorProfilerCallback3
6361 _ASSERTE(m_pCallback3 != NULL);
6364 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6365 // whose try/catch blocks aren't visible to the contract system
6366 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6367 return m_pCallback3->ProfilerDetachSucceeded();
6373 HRESULT EEToProfInterfaceImpl::GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext)
6393 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
6395 "**PROF: AssemblyReferenceClosureWalkStarted. wszAssemblyPath: 0x%p.\n",
6405 #endif // PROFILING_SUPPORTED