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()
53 // Note that the preferred contracts in this file are DIFFERENT than the preferred
54 // contracts for proftoeeinterfaceimpl.cpp.
56 // Private helper functions in this file do not have the same preferred contracts as
57 // public entrypoints, and they should be contracted following the same guidelines
58 // as per the rest of the EE.
60 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
61 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
64 // ======================================================================================
68 #ifdef PROFILING_SUPPORTED
71 #include "eetoprofinterfaceimpl.h"
72 #include "eetoprofinterfaceimpl.inl"
74 #include "proftoeeinterfaceimpl.h"
75 #include "proftoeeinterfaceimpl.inl"
76 #include "profilinghelper.inl"
77 #include "profdetach.h"
78 #include "simplerwlock.hpp"
81 //---------------------------------------------------------------------------------------
84 // Bitmask of flags that may be passed to the CLR_TO_PROFILER_ENTRYPOINT* macros
85 // to constrain when the callback may be issued
86 enum ClrToProfEntrypointFlags
89 kEE2PNone = 0x00000000,
91 // Callback is allowable even for detaching profilers
92 kEE2PAllowableWhileDetaching = 0x00000001,
94 // Callback is allowable even for initializing profilers
95 kEE2PAllowableWhileInitializing = 0x00000002,
97 // Callback is made while in a GC_NOTRIGGER contract. Whereas contracts are
98 // debug-only, this flag is used in retail builds as well.
99 kEE2PNoTrigger = 0x00000004,
102 #define ASSERT_EVAC_COUNTER_NONZERO() \
103 _ASSERTE((GetThreadNULLOk() == NULL) || \
104 (GetThreadNULLOk()->GetProfilerEvacuationCounter() != 0U))
106 #define CHECK_PROFILER_STATUS(ee2pFlags) \
107 /* If one of these asserts fires, perhaps you forgot to use */ \
108 /* BEGIN/END_PIN_PROFILER */ \
109 ASSERT_EVAC_COUNTER_NONZERO(); \
110 _ASSERTE(g_profControlBlock.pProfInterface.Load() != NULL); \
111 _ASSERTE(g_profControlBlock.pProfInterface == this); \
112 /* Early abort if... */ \
114 /* Profiler isn't active, */ \
115 !CORProfilerPresent() && \
117 /* and it's not the case that both a) this callback is allowed */ \
118 /* on a detaching profiler, and b) the profiler is detaching */ \
120 (((ee2pFlags) & kEE2PAllowableWhileDetaching) != 0) && \
121 (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
124 /* and it's not the case that both a) this callback is allowed */ \
125 /* on an initializing profiler, and b) the profiler is initializing */ \
127 (((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) && \
129 (g_profControlBlock.curProfStatus.Get() \
130 == kProfStatusInitializingForStartupLoad) || \
131 (g_profControlBlock.curProfStatus.Get() \
132 == kProfStatusInitializingForAttachLoad) \
140 // Least common denominator for the callback wrappers. Logs, records in EE Thread object
141 // that we're in a callback, and asserts that we're allowed to issue callbacks for the
142 // specified ThreadID (i.e., no ThreadDestroyed callback has been issued for the
145 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, threadId, logParams) \
146 INCONTRACT(AssertTriggersContract(!((ee2pFlags) & kEE2PNoTrigger))); \
147 CHECK_PROFILER_STATUS(ee2pFlags); \
149 _ASSERTE(m_pCallback2 != NULL); \
150 /* Normally, set COR_PRF_CALLBACKSTATE_INCALLBACK | */ \
151 /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE in the callback state, but omit */ \
152 /* COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE if we're in a GC_NOTRIGGERS callback */ \
153 SetCallbackStateFlagsHolder __csf( \
154 (((ee2pFlags) & kEE2PNoTrigger) != 0) ? \
155 COR_PRF_CALLBACKSTATE_INCALLBACK : \
156 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE \
158 _ASSERTE(ProfilerCallbacksAllowedForThread((Thread *) (threadId)))
160 #define CLR_TO_PROFILER_ENTRYPOINT_EX(ee2pFlags, logParams) \
161 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(ee2pFlags, GetThreadNULLOk(), logParams)
163 // Typical entrypoint macro you'll use. Checks that we're allowed to issue
164 // callbacks for the current thread (i.e., no ThreadDestroyed callback has been
165 // issued for the current thread).
166 #define CLR_TO_PROFILER_ENTRYPOINT(logParams) \
167 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PNone, logParams)
168 #define CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId, logParams) \
169 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(kEE2PNone, threadId, logParams)
172 //---------------------------------------------------------------------------------------
174 // Wrapper around Thread::ProfilerCallbacksAllowed
177 // pThread - Thread on which we need to determine whether callbacks are allowed
180 // TRUE if the profiler portion has marked this thread as allowable, else FALSE.
183 inline BOOL ProfilerCallbacksAllowedForThread(Thread * pThread)
186 return ((pThread == NULL) || (pThread->ProfilerCallbacksAllowed()));
190 //---------------------------------------------------------------------------------------
192 // Wrapper around Thread::SetProfilerCallbacksAllowed
195 // pThread - Thread on which we're setting whether callbacks shall be allowed
196 // fValue - The value to store.
199 inline void SetProfilerCallbacksAllowedForThread(Thread * pThread, BOOL fValue)
202 _ASSERTE(pThread != NULL);
203 pThread->SetProfilerCallbacksAllowed(fValue);
207 //---------------------------------------------------------------------------------------
209 // Low-level function to find and CoCreateInstance the profiler's DLL. Called when
210 // initializing via EEToProfInterfaceImpl::Init()
213 // * pClsid - [in] Profiler's CLSID
214 // * wszClsid - [in] String form of CLSID or progid of profiler to load.
215 // * wszProfileDLL - [in] Path to profiler DLL
216 // * ppCallback - [out] Pointer to profiler's ICorProfilerCallback2 interface
217 // * phmodProfilerDLL - [out] HMODULE of profiler's DLL.
220 // HRESULT indicating success or failure.
223 // * This function (or one of its callees) will log an error to the event log if
224 // there is a failure
226 static HRESULT CoCreateProfiler(
227 const CLSID * pClsid,
228 __in_z LPCWSTR wszClsid,
229 __in_z LPCWSTR wszProfileDLL,
230 ICorProfilerCallback2 ** ppCallback,
231 HMODULE * phmodProfilerDLL)
239 // This causes events to be logged, which loads resource strings,
240 // which takes locks.
245 _ASSERTE(pClsid != NULL);
246 _ASSERTE(wszClsid != NULL);
247 _ASSERTE(ppCallback != NULL);
248 _ASSERTE(phmodProfilerDLL != NULL);
250 LOG((LF_CORPROF, LL_INFO10, "**PROF: Entered CoCreateProfiler.\n"));
253 *phmodProfilerDLL = NULL;
255 // This is the ICorProfilerCallback2 ptr we get back from the profiler's class
256 // factory's CreateInstance()
257 ReleaseHolder<ICorProfilerCallback2> pCallback2FromCreateInstance;
259 // This is the ICorProfilerCallback2 ptr we get back from the profiler's QI (see its
260 // first use below for an explanation on why this is necessary).
261 ReleaseHolder<ICorProfilerCallback2> pCallback2FromQI;
263 // Create an instance of the profiler
264 hr = FakeCoCreateInstanceEx(*pClsid,
266 IID_ICorProfilerCallback2,
267 (LPVOID *) &pCallback2FromCreateInstance,
270 // (pCallback2FromCreateInstance == NULL) should be considered an error!
271 if ((pCallback2FromCreateInstance == NULL) && SUCCEEDED(hr))
276 if (hr == E_NOINTERFACE)
278 // Helpful message for a potentially common problem
279 ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
281 else if (hr == CORPROF_E_PROFILER_CANCEL_ACTIVATION)
283 // Profiler didn't encounter a bad error, but is voluntarily choosing not to
284 // profile this runtime. Profilers that need to set system environment
285 // variables to be able to profile services may use this HRESULT to avoid
286 // profiling all the other managed apps on the box.
287 ProfilingAPIUtility::LogProfInfo(IDS_PROF_CANCEL_ACTIVATION, wszClsid);
291 // Catch-all error for other CoCreateInstance failures
292 ProfilingAPIUtility::LogProfError(IDS_E_PROF_CCI_FAILED, wszClsid, hr);
295 // Now that hr is normalized (set to error if pCallback2FromCreateInstance == NULL),
296 // LOG and abort if there was a problem.
302 "**PROF: Unable to CoCreateInstance profiler class %S. hr=0x%x.\n",
308 // Redundantly QI for ICorProfilerCallback2. This keeps CLR behavior consistent
309 // with Whidbey, and works around the following bug in some profilers' class factory
311 // * CreateInstance() ignores the IID it's given
312 // * CreateInstance() returns a pointer to the object it created, even though
313 // that object might not support the IID passed to CreateInstance().
314 // Whidbey CLR worked around this problem by redundantly QI'ing for the same IID
315 // again after CreateInstance() returned. In this redudant QI, the profiler code would
316 // finally realize it didn't support that IID, and return an error there. Without
317 // the redundant QI, the CLR would accept what it got from CreateInstance(), and
318 // start calling into it using the unsupported interface's vtable, which would
321 // There were many MSDN samples (for example
322 // http://msdn.microsoft.com/msdnmag/issues/03/01/NETProfilerAPI/) which
323 // unfortunately had this CreateInstance() bug, so many profilers might have been
324 // generated based on this code. Since it's easy & cheap to work around the
325 // problem, we do so here with the redundant QI.
326 hr = pCallback2FromCreateInstance->QueryInterface(
327 IID_ICorProfilerCallback2,
328 (LPVOID *) &pCallback2FromQI);
330 // (pCallback2FromQI == NULL) should be considered an error!
331 if ((pCallback2FromQI == NULL) && SUCCEEDED(hr))
336 // Any error at this stage implies IID_ICorProfilerCallback2 is not supported
339 // Helpful message for a potentially common problem
340 ProfilingAPIUtility::LogNoInterfaceError(IID_ICorProfilerCallback2, wszClsid);
344 // Ok, safe to transfer ownership to caller's [out] param
345 *ppCallback = pCallback2FromQI.Extract();
346 pCallback2FromQI = NULL;
352 //---------------------------------------------------------------------------------------
354 // Implementation of CHashTableImpl functions. This class a simple implementation of
355 // CHashTable to provide a very simple implementation of the Cmp pure virtual function
358 EEToProfInterfaceImpl::CHashTableImpl::CHashTableImpl(ULONG iBuckets)
359 : CHashTable(iBuckets)
364 EEToProfInterfaceImpl::CHashTableImpl::~CHashTableImpl()
369 //---------------------------------------------------------------------------------------
371 // Comparison function for hash table of ClassIDs
374 // pc1 - hash key to compare
375 // pc2 - hash value to compare
378 // TRUE if the key & value refer to the same ClassID; otherwise FALSE
381 BOOL EEToProfInterfaceImpl::CHashTableImpl::Cmp(SIZE_T k1, const HASHENTRY * pc2)
383 LIMITED_METHOD_CONTRACT;
385 ClassID key = (ClassID) k1;
386 ClassID val = ((CLASSHASHENTRY *)pc2)->m_clsId;
392 //---------------------------------------------------------------------------------------
393 // Private maintenance functions for initialization, cleanup, etc.
395 EEToProfInterfaceImpl::AllocByClassData *EEToProfInterfaceImpl::m_pSavedAllocDataBlock = NULL;
397 //---------------------------------------------------------------------------------------
399 // EEToProfInterfaceImpl ctor just sets initial values
402 EEToProfInterfaceImpl::EEToProfInterfaceImpl() :
411 m_hmodProfilerDLL(NULL),
412 m_fLoadedViaAttach(FALSE),
414 m_pProfilersFuncIDMapper(NULL),
415 m_pProfilersFuncIDMapper2(NULL),
416 m_pProfilersFuncIDMapper2ClientData(NULL),
419 m_pGCRefDataFreeList(NULL),
420 m_csGCRefDataFreeList(NULL),
427 m_fIsClientIDToFunctionIDMappingEnabled(TRUE),
431 m_pEnter3WithInfo(NULL),
432 m_pLeave3WithInfo(NULL),
433 m_pTailcall3WithInfo(NULL),
434 m_fUnrevertiblyModifiedIL(FALSE),
435 m_fModifiedRejitState(FALSE),
436 m_pFunctionIDHashTable(NULL),
437 m_pFunctionIDHashTableRWLock(NULL),
438 m_dwConcurrentGCWaitTimeoutInMs(INFINITE),
439 m_bHasTimedOutWaitingForConcurrentGC(FALSE)
441 // Also NULL out this static. (Note: consider making this a member variable.)
442 m_pSavedAllocDataBlock = NULL;
443 LIMITED_METHOD_CONTRACT;
447 //---------------------------------------------------------------------------------------
449 // Post-constructor initialization of EEToProfInterfaceImpl. Sets everything up,
450 // including creating the profiler.
453 // * pProfToEE - A newly-created ProfToEEInterfaceImpl instance that will be passed
454 // to the profiler as the ICorProfilerInfo3 interface implementation.
455 // * pClsid - Profiler's CLSID
456 // * wszClsid - String form of CLSID or progid of profiler to load
457 // * wszProfileDLL - Path to profiler DLL
458 // * fLoadedViaAttach - TRUE iff the profiler is being attach-loaded (else
459 // profiler is being startup-loaded)
462 // HRESULT indicating success or failure.
465 // This function (or one of its callees) will log an error to the event log if there
470 HRESULT EEToProfInterfaceImpl::Init(
471 ProfToEEInterfaceImpl * pProfToEE,
472 const CLSID * pClsid,
473 __in_z LPCWSTR wszClsid,
474 __in_z LPCWSTR wszProfileDLL,
475 BOOL fLoadedViaAttach,
476 DWORD dwConcurrentGCWaitTimeoutInMs)
484 // This causes events to be logged, which loads resource strings,
485 // which takes locks.
492 HRESULT hr = E_UNEXPECTED;
494 _ASSERTE(pProfToEE != NULL);
496 m_fLoadedViaAttach = fLoadedViaAttach;
497 m_dwConcurrentGCWaitTimeoutInMs = dwConcurrentGCWaitTimeoutInMs;
499 // The rule sez your Crst should switch to preemptive when it's taken. We intentionally
500 // break this rule with CRST_UNSAFE_ANYMODE, because this Crst is taken DURING A GC
501 // (see AllocateMovedReferencesData(), called by MovedReference(), called by the GC),
502 // and we don't want to be switching modes in the middle of a GC! Indeed, on server there
503 // may not even be a mode in the first place.
504 CRITSEC_AllocationHolder csGCRefDataFreeList(ClrCreateCriticalSection(CrstProfilerGCRefDataFreeList, CRST_UNSAFE_ANYMODE));
505 if (csGCRefDataFreeList == NULL)
509 "**PROF: Failed to create Crst during initialization.\n"));
511 // A specialized event log entry for this failure would be confusing and
512 // unhelpful. So just log a generic internal failure event
513 ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_FAIL);
517 // CEEInfo::GetProfilingHandle will be PREEMPTIVE mode when trying to update
518 // m_pFunctionIDHashTable while ProfileEnter, ProfileLeave and ProfileTailcall
519 // and LookupClientIDFromCache all will be in COOPERATIVE mode when trying
520 // to read m_pFunctionIDHashTable, so pFunctionIDHashTableRWLock must be created
521 // with COOPERATIVE_OR_PREEMPTIVE. It is safe to so do because FunctionIDHashTable,
522 // synchronized by m_pFunctionIDHashTableRWLock runs only native code and uses
524 NewHolder<SimpleRWLock> pFunctionIDHashTableRWLock(new (nothrow) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT));
526 NewHolder<FunctionIDHashTable> pFunctionIDHashTable(new (nothrow) FunctionIDHashTable());
528 if ((pFunctionIDHashTable == NULL) || (pFunctionIDHashTableRWLock == NULL))
532 "**PROF: Failed to create FunctionIDHashTable or FunctionIDHashTableRWLock during initialization.\n"));
534 // A specialized event log entry for this failure would be confusing and
535 // unhelpful. So just log a generic internal failure event
536 ProfilingAPIUtility::LogProfError(IDS_E_PROF_INTERNAL_INIT, wszClsid, E_OUTOFMEMORY);
538 return E_OUTOFMEMORY;
541 // This wraps the following profiler calls in a try / catch:
542 // * ClassFactory::CreateInstance
543 // * AddRef/Release/QueryInterface
544 // Although most profiler calls are not protected, these creation calls are
545 // protected here since it's cheap to do so (this is only done once per load of a
546 // profiler), and it would be nice to avoid tearing down the entire process when
547 // attaching a profiler that may pass back bogus vtables.
550 // CoCreate the profiler (but don't call its Initialize() method yet)
551 hr = CreateProfiler(pClsid, wszClsid, wszProfileDLL);
556 ProfilingAPIUtility::LogProfError(IDS_E_PROF_UNHANDLED_EXCEPTION_ON_LOAD, wszClsid);
558 // Intentionally swallowing all exceptions, as we don't want a poorly-written
559 // profiler that throws or AVs on attach to cause the entire process to go away.
560 EX_END_CATCH(SwallowAllExceptions);
565 // CreateProfiler (or catch clause above) has already logged an event to the
566 // event log on failure
570 m_pProfToEE = pProfToEE;
572 m_csGCRefDataFreeList = csGCRefDataFreeList.Extract();
573 csGCRefDataFreeList = NULL;
575 m_pFunctionIDHashTable = pFunctionIDHashTable.Extract();
576 pFunctionIDHashTable = NULL;
578 m_pFunctionIDHashTableRWLock = pFunctionIDHashTableRWLock.Extract();
579 pFunctionIDHashTableRWLock = NULL;
585 //---------------------------------------------------------------------------------------
587 // This is used by Init() to load the user-specified profiler (but not to call
588 // its Initialize() method).
591 // pClsid - Profiler's CLSID
592 // wszClsid - String form of CLSID or progid of profiler to load
593 // wszProfileDLL - Path to profiler DLL
596 // HRESULT indicating success / failure. If this is successful, m_pCallback2 will be
597 // set to the profiler's ICorProfilerCallback2 interface on return. m_pCallback3,4
598 // will be set to the profiler's ICorProfilerCallback3 interface on return if
599 // ICorProfilerCallback3,4 is supported.
602 // Although the profiler has not yet been instantiated, it is assumed that the internal
603 // profiling API structures have already been created
606 // This function (or one of its callees) will log an error to the event log
607 // if there is a failure
609 HRESULT EEToProfInterfaceImpl::CreateProfiler(
610 const CLSID * pClsid,
611 __in_z LPCWSTR wszClsid,
612 __in_z LPCWSTR wszProfileDLL)
620 // This causes events to be logged, which loads resource strings,
621 // which takes locks.
628 // Always called before Thread created.
629 _ASSERTE(GetThreadNULLOk() == NULL);
631 // Try and CoCreate the registered profiler
632 ReleaseHolder<ICorProfilerCallback2> pCallback2;
633 HModuleHolder hmodProfilerDLL;
634 HRESULT hr = CoCreateProfiler(
642 // CoCreateProfiler logs events to the event log on failures
646 // CoCreateProfiler ensures that if it succeeds, we get some valid pointers
647 _ASSERTE(pCallback2 != NULL);
648 _ASSERTE(hmodProfilerDLL != NULL);
650 // Save profiler pointers into this. The reference ownership now
651 // belongs to this class, so NULL out locals without allowing them to release
652 m_pCallback2 = pCallback2.Extract();
654 m_hmodProfilerDLL = hmodProfilerDLL.Extract();
655 hmodProfilerDLL = NULL;
657 // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9. Let's check.
659 ReleaseHolder<ICorProfilerCallback9> pCallback9;
660 hr = m_pCallback2->QueryInterface(
661 IID_ICorProfilerCallback9,
662 (LPVOID *)&pCallback9);
663 if (SUCCEEDED(hr) && (pCallback9 != NULL))
665 // Nifty. Transfer ownership to this class
666 _ASSERTE(m_pCallback9 == NULL);
667 m_pCallback9 = pCallback9.Extract();
670 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6,7,8
671 // due to inheritance relationship of the interfaces
672 _ASSERTE(m_pCallback8 == NULL);
673 m_pCallback8 = static_cast<ICorProfilerCallback8 *>(m_pCallback9);
674 m_pCallback8->AddRef();
676 _ASSERTE(m_pCallback7 == NULL);
677 m_pCallback7 = static_cast<ICorProfilerCallback7 *>(m_pCallback8);
678 m_pCallback7->AddRef();
680 _ASSERTE(m_pCallback6 == NULL);
681 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
682 m_pCallback6->AddRef();
684 _ASSERTE(m_pCallback5 == NULL);
685 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
686 m_pCallback5->AddRef();
688 _ASSERTE(m_pCallback4 == NULL);
689 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
690 m_pCallback4->AddRef();
692 _ASSERTE(m_pCallback3 == NULL);
693 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
694 m_pCallback3->AddRef();
697 if (m_pCallback8 == NULL)
699 ReleaseHolder<ICorProfilerCallback8> pCallback8;
700 hr = m_pCallback2->QueryInterface(
701 IID_ICorProfilerCallback8,
702 (LPVOID *)&pCallback8);
703 if (SUCCEEDED(hr) && (pCallback8 != NULL))
705 // Nifty. Transfer ownership to this class
706 _ASSERTE(m_pCallback8 == NULL);
707 m_pCallback8 = pCallback8.Extract();
710 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6,7
711 // due to inheritance relationship of the interfaces
713 _ASSERTE(m_pCallback7 == NULL);
714 m_pCallback7 = static_cast<ICorProfilerCallback7 *>(m_pCallback8);
715 m_pCallback7->AddRef();
717 _ASSERTE(m_pCallback6 == NULL);
718 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
719 m_pCallback6->AddRef();
721 _ASSERTE(m_pCallback5 == NULL);
722 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
723 m_pCallback5->AddRef();
725 _ASSERTE(m_pCallback4 == NULL);
726 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
727 m_pCallback4->AddRef();
729 _ASSERTE(m_pCallback3 == NULL);
730 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
731 m_pCallback3->AddRef();
735 if (m_pCallback7 == NULL)
737 ReleaseHolder<ICorProfilerCallback7> pCallback7;
738 hr = m_pCallback2->QueryInterface(
739 IID_ICorProfilerCallback7,
740 (LPVOID *)&pCallback7);
741 if (SUCCEEDED(hr) && (pCallback7 != NULL))
743 // Nifty. Transfer ownership to this class
744 _ASSERTE(m_pCallback7 == NULL);
745 m_pCallback7 = pCallback7.Extract();
748 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5,6
749 // due to inheritance relationship of the interfaces
751 _ASSERTE(m_pCallback6 == NULL);
752 m_pCallback6 = static_cast<ICorProfilerCallback6 *>(m_pCallback7);
753 m_pCallback6->AddRef();
755 _ASSERTE(m_pCallback5 == NULL);
756 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
757 m_pCallback5->AddRef();
759 _ASSERTE(m_pCallback4 == NULL);
760 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
761 m_pCallback4->AddRef();
763 _ASSERTE(m_pCallback3 == NULL);
764 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
765 m_pCallback3->AddRef();
769 if (m_pCallback6 == NULL)
771 ReleaseHolder<ICorProfilerCallback6> pCallback6;
772 hr = m_pCallback2->QueryInterface(
773 IID_ICorProfilerCallback6,
774 (LPVOID *)&pCallback6);
775 if (SUCCEEDED(hr) && (pCallback6 != NULL))
777 // Nifty. Transfer ownership to this class
778 _ASSERTE(m_pCallback6 == NULL);
779 m_pCallback6 = pCallback6.Extract();
782 // And while we're at it, we must now also have an ICorProfilerCallback3,4,5
783 // due to inheritance relationship of the interfaces
785 _ASSERTE(m_pCallback5 == NULL);
786 m_pCallback5 = static_cast<ICorProfilerCallback5 *>(m_pCallback6);
787 m_pCallback5->AddRef();
789 _ASSERTE(m_pCallback4 == NULL);
790 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
791 m_pCallback4->AddRef();
793 _ASSERTE(m_pCallback3 == NULL);
794 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
795 m_pCallback3->AddRef();
799 if (m_pCallback5 == NULL)
801 ReleaseHolder<ICorProfilerCallback5> pCallback5;
802 hr = m_pCallback2->QueryInterface(
803 IID_ICorProfilerCallback5,
804 (LPVOID *) &pCallback5);
805 if (SUCCEEDED(hr) && (pCallback5 != NULL))
807 // Nifty. Transfer ownership to this class
808 _ASSERTE(m_pCallback5 == NULL);
809 m_pCallback5 = pCallback5.Extract();
812 // And while we're at it, we must now also have an ICorProfilerCallback3, and
813 // ICorProfilerCallback4 due to inheritance relationship of the interfaces
814 _ASSERTE(m_pCallback4 == NULL);
815 m_pCallback4 = static_cast<ICorProfilerCallback4 *>(m_pCallback5);
816 m_pCallback4->AddRef();
818 _ASSERTE(m_pCallback3 == NULL);
819 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
820 m_pCallback3->AddRef();
824 if (m_pCallback4 == NULL)
826 ReleaseHolder<ICorProfilerCallback4> pCallback4;
827 hr = m_pCallback2->QueryInterface(
828 IID_ICorProfilerCallback4,
829 (LPVOID *) &pCallback4);
830 if (SUCCEEDED(hr) && (pCallback4 != NULL))
832 // Nifty. Transfer ownership to this class
833 _ASSERTE(m_pCallback4 == NULL);
834 m_pCallback4 = pCallback4.Extract();
837 // And while we're at it, we must now also have an ICorProfilerCallback3, and
838 // due to inheritance relationship of the interfaces
839 _ASSERTE(m_pCallback3 == NULL);
840 m_pCallback3 = static_cast<ICorProfilerCallback3 *>(m_pCallback4);
841 m_pCallback3->AddRef();
845 if (m_pCallback3 == NULL)
847 ReleaseHolder<ICorProfilerCallback3> pCallback3;
848 hr = m_pCallback2->QueryInterface(
849 IID_ICorProfilerCallback3,
850 (LPVOID *) &pCallback3);
851 if (SUCCEEDED(hr) && (pCallback3 != NULL))
853 // Nifty. Transfer ownership to this class
854 _ASSERTE(m_pCallback3 == NULL);
855 m_pCallback3 = pCallback3.Extract();
866 //---------------------------------------------------------------------------------------
868 // Performs cleanup for EEToProfInterfaceImpl, including releasing the profiler's
869 // callback interface. Called on termination of a profiler connection.
872 EEToProfInterfaceImpl::~EEToProfInterfaceImpl()
880 // When we release the profiler's callback interface
881 // below, it may well perform cleanup that takes locks.
882 // Example: profiler may release a metadata interface, which
883 // causes it to take a reader lock
888 // Make sure there's no pointer about to dangle once we disappear.
889 // FUTURE: For reattach-with-neutered-profilers feature crew, change this assert to
890 // scan through list of detaching profilers to make sure none of them give a
891 // GetEEToProfPtr() equal to this
892 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
893 _ASSERTE(ProfilingAPIDetach::GetEEToProfPtr() == NULL);
894 #endif // FEATURE_PROFAPI_ATTACH_DETACH
896 // Release user-specified profiler DLL
897 // NOTE: If we're tearing down the process, then do nothing related
898 // to cleaning up the profiler DLL, as the DLL may no longer
900 if (!IsAtProcessExit())
902 if (m_pCallback2 != NULL)
904 m_pCallback2->Release();
908 BOOL fIsV4Profiler = (m_pCallback3 != NULL);
912 m_pCallback3->Release();
916 if (m_pCallback4 != NULL)
918 m_pCallback4->Release();
922 if (m_pCallback5 != NULL)
924 m_pCallback5->Release();
928 if (m_pCallback6 != NULL)
930 m_pCallback6->Release();
934 if (m_pCallback7 != NULL)
936 m_pCallback7->Release();
940 if (m_pCallback8 != NULL)
942 m_pCallback8->Release();
946 if (m_pCallback9 != NULL)
948 m_pCallback9->Release();
952 // Only unload the V4 profiler if this is not part of shutdown. This protects
953 // Whidbey profilers that aren't used to being FreeLibrary'd.
954 if (fIsV4Profiler && !g_fEEShutDown)
956 if (m_hmodProfilerDLL != NULL)
958 FreeLibrary(m_hmodProfilerDLL);
959 m_hmodProfilerDLL = NULL;
962 // Now that the profiler is destroyed, it is no longer referencing our
963 // ProfToEEInterfaceImpl, so it's safe to destroy that, too.
964 if (m_pProfToEE != NULL)
972 // Delete the structs associated with GC moved references
973 while (m_pGCRefDataFreeList)
975 GCReferencesData * pDel = m_pGCRefDataFreeList;
976 m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
980 if (m_pSavedAllocDataBlock)
983 _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFFFFFFFFFF);
985 _ASSERTE((UINT_PTR)m_pSavedAllocDataBlock != 0xFFFFFFFF);
988 _ASSERTE(m_pSavedAllocDataBlock->pHashTable != NULL);
989 // Get rid of the hash table
990 if (m_pSavedAllocDataBlock->pHashTable)
991 delete m_pSavedAllocDataBlock->pHashTable;
993 // Get rid of the two arrays used to hold class<->numinstance info
994 if (m_pSavedAllocDataBlock->cLength != 0)
996 _ASSERTE(m_pSavedAllocDataBlock->arrClsId != NULL);
997 _ASSERTE(m_pSavedAllocDataBlock->arrcObjects != NULL);
999 delete [] m_pSavedAllocDataBlock->arrClsId;
1000 delete [] m_pSavedAllocDataBlock->arrcObjects;
1003 // Get rid of the hash array used by the hash table
1004 if (m_pSavedAllocDataBlock->arrHash)
1006 delete [] m_pSavedAllocDataBlock->arrHash;
1009 m_pSavedAllocDataBlock = NULL;
1012 m_GUID = k_guidZero;
1014 if (m_csGCRefDataFreeList != NULL)
1016 ClrDeleteCriticalSection(m_csGCRefDataFreeList);
1017 m_csGCRefDataFreeList = NULL;
1020 if (m_pFunctionIDHashTable != NULL)
1022 delete m_pFunctionIDHashTable;
1023 m_pFunctionIDHashTable = NULL;
1026 if (m_pFunctionIDHashTableRWLock != NULL)
1028 delete m_pFunctionIDHashTableRWLock;
1029 m_pFunctionIDHashTableRWLock = NULL;
1035 //---------------------------------------------------------------------------------------
1037 // Initialize the GUID used for the cookie in remoting callbacks. If already
1038 // initialized, this just does nothing and returns S_OK.
1041 // HRESULT indicating success or failure. If the GUID was already initialized,
1042 // just returns S_OK
1046 HRESULT EEToProfInterfaceImpl::InitGUID()
1053 ASSERT_NO_EE_LOCKS_HELD();
1057 if (IsEqualGUID(m_GUID, k_guidZero))
1059 return CoCreateGuid(&m_GUID);
1065 //---------------------------------------------------------------------------------------
1067 // Returns a GUID suitable for use as a remoting callback cookie for this thread.
1068 // The GUID is based on the template GUID (m_GUID), the current thread, and
1072 // pGUID - [out] The GUID requested
1075 void EEToProfInterfaceImpl::GetGUID(GUID * pGUID)
1081 ASSERT_NO_EE_LOCKS_HELD();
1085 // the member GUID and the argument should both be valid
1086 _ASSERTE(!(IsEqualGUID(m_GUID, k_guidZero)));
1089 // Copy the contents of the template GUID
1090 memcpy(pGUID, &m_GUID, sizeof(GUID));
1092 // Adjust the last two bytes
1093 pGUID->Data4[6] = (BYTE) GetCurrentThreadId();
1094 pGUID->Data4[7] = (BYTE) InterlockedIncrement((LPLONG)&m_lGUIDCount);
1097 //---------------------------------------------------------------------------------------
1099 // Wrapper around calling profiler's FunctionIDMapper hook. Called by JIT.
1102 // funcId - FunctionID for profiler to map
1103 // pbHookFunction - [out] Specifies whether the profiler wants to hook (enter/leave)
1107 // The profiler-specified value that we should use to identify this function
1108 // in future hooks (enter/leave).
1109 // If the remapped ID returned by the profiler is NULL, we will replace it with
1110 // funcId. Thus, this function will never return NULL.
1113 UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction)
1115 // This isn't a public callback via ICorProfilerCallback*, but it's close (a
1116 // public callback via a function pointer). So we'll aim to have the preferred
1132 // ListLockEntry typically held during this callback (thanks to
1133 // MethodTable::DoRunClassInitThrowing).
1138 // only called when CORProfilerFunctionIDMapperEnabled() is true,
1139 // which means either m_pProfilersFuncIDMapper or m_pProfilersFuncIDMapper2 should not be NULL;
1140 _ASSERTE((m_pProfilersFuncIDMapper != NULL) || (m_pProfilersFuncIDMapper2 != NULL));
1142 UINT_PTR clientId = NULL;
1144 if (m_pProfilersFuncIDMapper2 != NULL)
1146 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
1148 "**PROF: Calling profiler's FunctionIDMapper2. funcId: 0x%p. clientData: 0x%p.\n",
1150 m_pProfilersFuncIDMapper2ClientData));
1152 // The attached profiler may not want to hook this function, so ask it
1153 clientId = m_pProfilersFuncIDMapper2(funcId, m_pProfilersFuncIDMapper2ClientData, pbHookFunction);
1158 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
1160 "**PROF: Calling profiler's FunctionIDMapper. funcId: 0x%p.\n",
1163 // The attached profiler may not want to hook this function, so ask it
1164 clientId = m_pProfilersFuncIDMapper(funcId, pbHookFunction);
1167 static LONG s_lIsELT2Enabled = -1;
1168 if (s_lIsELT2Enabled == -1)
1170 LONG lEnabled = ((m_pEnter2 != NULL) ||
1171 (m_pLeave2 != NULL) ||
1172 (m_pTailcall2 != NULL));
1174 InterlockedCompareExchange(&s_lIsELT2Enabled, lEnabled, -1);
1177 // We need to keep track the mapping between ClientID and FunctionID for ELT2
1178 if (s_lIsELT2Enabled != 0)
1180 FunctionIDAndClientID functionIDAndClientID;
1181 functionIDAndClientID.functionID = funcId;
1182 functionIDAndClientID.clientID = clientId;
1184 // ClientID Hash table may throw OUTOFMEMORY exception, which is not expected by the caller.
1187 SimpleWriteLockHolder writeLockHolder(m_pFunctionIDHashTableRWLock);
1188 m_pFunctionIDHashTable->AddOrReplace(functionIDAndClientID);
1192 // Running out of heap memory means we no longer can maintain the integrity of the mapping table.
1193 // All ELT2 fast-path hooks are disabled since we cannot report correct FunctionID to the
1194 // profiler at this moment.
1195 m_fIsClientIDToFunctionIDMappingEnabled = FALSE;
1197 EX_END_CATCH(RethrowTerminalExceptions);
1199 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
1200 // instead of using clientID because the profiler may map several functionIDs to a clientID to
1201 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
1202 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
1203 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
1207 // For profilers that support ELT3, clientID will be embedded into the ELT3 probes
1212 //---------------------------------------------------------------------------------------
1214 // Private functions called by GC so we can cache data for later notification to
1218 //---------------------------------------------------------------------------------------
1220 // Called lazily to allocate or use a recycled GCReferencesData.
1223 // GCReferencesData * requested by caller.
1226 // Uses m_csGCRefDataFreeList to find a recycleable GCReferencesData
1227 // Called by GC callbacks that need to record GC references reported
1228 // to the callbacks by the GC as the GC walks the heap.
1231 EEToProfInterfaceImpl::GCReferencesData * EEToProfInterfaceImpl::AllocateMovedReferencesData()
1237 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1239 // We directly take m_csGCRefDataFreeList around accessing the free list below
1242 // Thread store lock normally held during this call
1246 GCReferencesData *pData = NULL;
1248 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1250 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1252 // Anything on the free list for us to grab?
1253 if (m_pGCRefDataFreeList != NULL)
1255 // Yup, get the first element from the free list
1256 pData = m_pGCRefDataFreeList;
1257 m_pGCRefDataFreeList = m_pGCRefDataFreeList->pNext;
1263 // Still not set, so the free list must not have had anything
1264 // available. Go ahead and allocate a struct directly.
1265 pData = new (nothrow) GCReferencesData;
1272 // Now init the new block
1273 _ASSERTE(pData != NULL);
1275 // Set our index to the beginning
1277 pData->compactingCount = 0;
1282 //---------------------------------------------------------------------------------------
1284 // After reporting references to the profiler, this recycles the GCReferencesData
1285 // that was used. See EEToProfInterfaceImpl::EndRootReferences2.
1288 // pData - Pointer to GCReferencesData to recycle
1291 void EEToProfInterfaceImpl::FreeMovedReferencesData(GCReferencesData * pData)
1299 // We directly take m_csGCRefDataFreeList around accessing the free list below
1302 // Thread store lock normally held during this callback
1307 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1309 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1310 pData->pNext = m_pGCRefDataFreeList;
1311 m_pGCRefDataFreeList = pData;
1315 //---------------------------------------------------------------------------------------
1317 // Called by the GC to notify profapi of a moved reference. We cache the
1318 // info here so we can later notify the profiler of all moved references
1322 // pbMemBlockStart - Start of moved block
1323 // pbMemBlockEnd - End of moved block
1324 // cbRelocDistance - Offset from pbMemBlockStart of where the block
1326 // pHeapId - GCReferencesData * used to record the block
1327 // fCompacting - Is this a compacting collection?
1330 // HRESULT indicating success or failure
1333 HRESULT EEToProfInterfaceImpl::MovedReference(BYTE * pbMemBlockStart,
1334 BYTE * pbMemBlockEnd,
1335 ptrdiff_t cbRelocDistance,
1343 // Called during a GC
1345 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1347 // Thread store lock normally held during this callback
1352 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1354 // Get a pointer to the data for this heap
1355 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1357 // If this is the first notification of a moved reference for this heap
1358 // in this particular gc activation, then we need to get a ref data block
1359 // from the free list of blocks, or if that's empty then we need to
1360 // allocate a new one.
1363 pData = AllocateMovedReferencesData();
1366 return E_OUTOFMEMORY;
1369 // Set the cookie so that we will be provided it on subsequent
1371 ((*((size_t *)pHeapId))) = (size_t)pData;
1374 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1376 // If the struct has been filled, then we need to notify the profiler of
1377 // these moved references and clear the struct for the next load of
1379 if (pData->curIdx == kcReferencesMax)
1381 MovedReferences(pData);
1383 pData->compactingCount = 0;
1386 // Now save the information in the struct
1387 pData->arrpbMemBlockStartOld[pData->curIdx] = pbMemBlockStart;
1388 pData->arrpbMemBlockStartNew[pData->curIdx] = pbMemBlockStart + cbRelocDistance;
1389 pData->arrMemBlockSize[pData->curIdx] = pbMemBlockEnd - pbMemBlockStart;
1391 // Increment the index into the parallel arrays
1394 // Keep track of whether this is a compacting collection
1397 pData->compactingCount += 1;
1398 // The gc is supposed to make up its mind whether this is a compacting collection or not
1399 // Thus if this one is compacting, everything so far had to say compacting
1400 _ASSERTE(pData->compactingCount == pData->curIdx);
1404 // The gc is supposed to make up its mind whether this is a compacting collection or not
1405 // Thus if this one is non-compacting, everything so far had to say non-compacting
1406 _ASSERTE(pData->compactingCount == 0 && cbRelocDistance == 0);
1411 //---------------------------------------------------------------------------------------
1413 // Called by the GC to indicate that the GC is finished calling
1414 // EEToProfInterfaceImpl::MovedReference for this collection. This function will
1415 // call into the profiler to notify it of all the moved references we've cached.
1418 // pHeapId - Casted to a GCReferencesData * that contains the moved reference
1419 // data we've cached.
1422 // HRESULT indicating success or failure.
1425 HRESULT EEToProfInterfaceImpl::EndMovedReferences(void * pHeapId)
1431 // Called during a GC
1433 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
1435 // We directly take m_csGCRefDataFreeList around accessing the free list below
1438 // Thread store lock normally held during this callback
1443 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1447 // Get a pointer to the data for this heap
1448 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1450 // If there were no moved references, profiler doesn't need to know
1454 // Communicate the moved references to the profiler
1455 _ASSERTE(pData->curIdx> 0);
1456 hr = MovedReferences(pData);
1458 // Now we're done with the data block, we can shove it onto the free list
1459 // SCOPE: Lock m_csGCRefDataFreeList for access to the free list
1461 CRITSEC_Holder csh(m_csGCRefDataFreeList);
1462 pData->pNext = m_pGCRefDataFreeList;
1463 m_pGCRefDataFreeList = pData;
1467 // Set the cookie to an invalid number
1468 (*((size_t *)pHeapId)) = (size_t)(-1);
1475 #define HASH_ARRAY_SIZE_INITIAL 1024
1476 #define HASH_ARRAY_SIZE_INC 256
1477 #define HASH_NUM_BUCKETS 32
1478 #define HASH(x) ( (ULONG) ((SIZE_T)x) ) // A simple hash function
1480 //---------------------------------------------------------------------------------------
1482 // Callback used by the GC when walking the heap (via AllocByClassHelper in
1483 // ProfToEEInterfaceImpl.cpp).
1486 // objId - Object reference encountered during heap walk
1487 // classId - ClassID for objID
1488 // pHeapId - heap walk context used by this function; it's interpreted
1489 // as an AllocByClassData * to keep track of objects on the
1493 // HRESULT indicating whether to continue with the heap walk (i.e.,
1494 // success HRESULT) or abort it (i.e., failure HRESULT).
1497 HRESULT EEToProfInterfaceImpl::AllocByClass(ObjectID objId, ClassID clsId, void * pHeapId)
1508 // This is a slight attempt to make sure that this is never called in a multi-threaded
1509 // manner. This heap walk should be done by one thread at a time only.
1510 static DWORD dwProcId = 0xFFFFFFFF;
1513 _ASSERTE(pHeapId != NULL);
1514 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1516 // The heapId they pass in is really a AllocByClassData struct ptr.
1517 AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1519 // If it's null, need to allocate one
1523 // This is a slight attempt to make sure that this is never called in a multi-threaded
1524 // manner. This heap walk should be done by one thread at a time only.
1525 dwProcId = GetCurrentProcessId();
1528 // See if we've saved a data block from a previous GC
1529 if (m_pSavedAllocDataBlock != NULL)
1530 pData = m_pSavedAllocDataBlock;
1532 // This means we need to allocate all the memory to keep track of the info
1535 // Get a new alloc data block
1536 pData = new (nothrow) AllocByClassData;
1538 return (E_OUTOFMEMORY);
1540 // Create a new hash table
1541 pData->pHashTable = new (nothrow) CHashTableImpl(HASH_NUM_BUCKETS);
1542 if (!pData->pHashTable)
1545 return (E_OUTOFMEMORY);
1548 // Get the memory for the array that the hash table is going to use
1549 pData->arrHash = new (nothrow) CLASSHASHENTRY[HASH_ARRAY_SIZE_INITIAL];
1550 if (pData->arrHash == NULL)
1552 delete pData->pHashTable;
1554 return (E_OUTOFMEMORY);
1557 // Save the number of elements in the array
1558 pData->cHash = HASH_ARRAY_SIZE_INITIAL;
1560 // Now initialize the hash table
1561 HRESULT hr = pData->pHashTable->NewInit((BYTE *)pData->arrHash, sizeof(CLASSHASHENTRY));
1562 if (hr == E_OUTOFMEMORY)
1564 delete [] pData->arrHash;
1565 delete pData->pHashTable;
1567 return (E_OUTOFMEMORY);
1569 _ASSERTE(pData->pHashTable->IsInited());
1571 // Null some entries
1572 pData->arrClsId = NULL;
1573 pData->arrcObjects = NULL;
1576 // Hold on to the structure
1577 m_pSavedAllocDataBlock = pData;
1580 // Got some memory and hash table to store entries, yay!
1581 *((size_t *)pHeapId) = (size_t)pData;
1583 // Initialize the data
1585 pData->pHashTable->Clear();
1588 _ASSERTE(pData->iHash <= pData->cHash);
1589 _ASSERTE(dwProcId == GetCurrentProcessId());
1591 // Lookup to see if this class already has an entry
1592 CLASSHASHENTRY * pEntry =
1593 reinterpret_cast<CLASSHASHENTRY *>(pData->pHashTable->Find(HASH(clsId), (SIZE_T)clsId));
1595 // If this class has already been encountered, just increment the counter.
1599 // Otherwise, need to add this one as a new entry in the hash table
1602 // If we're full, we need to realloc
1603 if (pData->iHash == pData->cHash)
1605 // Try to realloc the memory
1606 CLASSHASHENTRY *tmp = new (nothrow) CLASSHASHENTRY[pData->cHash + HASH_ARRAY_SIZE_INC];
1609 return (E_OUTOFMEMORY);
1612 _ASSERTE(pData->arrHash);
1613 memcpy (tmp, pData->arrHash, pData->cHash*sizeof(CLASSHASHENTRY));
1614 delete [] pData->arrHash;
1615 pData->arrHash = tmp;
1616 // Tell the hash table that the memory location of the array has changed
1617 pData->pHashTable->SetTable((BYTE *)pData->arrHash);
1619 // Save the new size of the array
1620 pData->cHash += HASH_ARRAY_SIZE_INC;
1623 // Now add the new entry
1624 CLASSHASHENTRY *pNewEntry = (CLASSHASHENTRY *) pData->pHashTable->Add(HASH(clsId), pData->iHash++);
1626 pNewEntry->m_clsId = clsId;
1627 pNewEntry->m_count = 1;
1634 HRESULT EEToProfInterfaceImpl::EndAllocByClass(void *pHeapId)
1636 _ASSERTE(pHeapId != NULL);
1637 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1641 AllocByClassData *pData = (AllocByClassData *)(*((size_t *)pHeapId));
1643 // Notify the profiler if there are elements to notify it of
1645 hr = NotifyAllocByClass(pData);
1648 (*((size_t *)pHeapId)) = (size_t)(-1);
1654 //---------------------------------------------------------------------------------------
1656 // Convert ETW-style root flag bitmask to ProfAPI-stye root flag bitmask
1659 // dwEtwRootFlags - ETW-style root flag bitmask
1662 // The corresponding ProfAPI-stye root flag bitmask
1665 DWORD EtwRootFlagsToProfApiRootFlags(DWORD dwEtwRootFlags)
1667 LIMITED_METHOD_CONTRACT;
1669 // If a new ETW flag is added, adjust this assert, and add a case below.
1670 _ASSERTE((dwEtwRootFlags &
1671 ~(kEtwGCRootFlagsPinning | kEtwGCRootFlagsWeakRef | kEtwGCRootFlagsInterior | kEtwGCRootFlagsRefCounted))
1674 DWORD dwProfApiRootFlags = 0;
1676 if ((dwEtwRootFlags & kEtwGCRootFlagsPinning) != 0)
1678 dwProfApiRootFlags |= COR_PRF_GC_ROOT_PINNING;
1680 if ((dwEtwRootFlags & kEtwGCRootFlagsWeakRef) != 0)
1682 dwProfApiRootFlags |= COR_PRF_GC_ROOT_WEAKREF;
1684 if ((dwEtwRootFlags & kEtwGCRootFlagsInterior) != 0)
1686 dwProfApiRootFlags |= COR_PRF_GC_ROOT_INTERIOR;
1688 if ((dwEtwRootFlags & kEtwGCRootFlagsRefCounted) != 0)
1690 dwProfApiRootFlags |= COR_PRF_GC_ROOT_REFCOUNTED;
1692 return dwProfApiRootFlags;
1695 //---------------------------------------------------------------------------------------
1697 // Convert ETW-style root kind enum to ProfAPI-stye root kind enum
1700 // dwEtwRootKind - ETW-style root kind enum
1703 // Corresponding ProfAPI-stye root kind enum
1706 DWORD EtwRootKindToProfApiRootKind(EtwGCRootKind dwEtwRootKind)
1708 LIMITED_METHOD_CONTRACT;
1710 switch(dwEtwRootKind)
1713 // If a new ETW root kind is added, create a profapi root kind as well, and add
1714 // the appropriate case below
1715 _ASSERTE(!"Unrecognized ETW root kind");
1716 // Deliberately fall through to kEtwGCRootKindOther
1718 case kEtwGCRootKindOther:
1719 return COR_PRF_GC_ROOT_OTHER;
1721 case kEtwGCRootKindStack:
1722 return COR_PRF_GC_ROOT_STACK;
1724 case kEtwGCRootKindFinalizer:
1725 return COR_PRF_GC_ROOT_FINALIZER;
1727 case kEtwGCRootKindHandle:
1728 return COR_PRF_GC_ROOT_HANDLE;
1732 //---------------------------------------------------------------------------------------
1734 // Callback used by the GC when scanning the roots (via ScanRootsHelper in
1735 // ProfToEEInterfaceImpl.cpp).
1738 // objectId - Root object reference encountered
1739 // dwEtwRootKind - ETW enum describing what kind of root objectId is
1740 // dwEtwRootFlags - ETW flags describing the root qualities of objectId
1741 // rootID - Root's methoddesc if dwEtwRootKind==kEtwGCRootKindStack, else NULL
1742 // pHeapId - Used as a GCReferencesData * to keep track of the GC references
1745 // HRESULT indicating success or failure.
1748 HRESULT EEToProfInterfaceImpl::RootReference2(BYTE * objectId,
1749 EtwGCRootKind dwEtwRootKind,
1750 EtwGCRootFlags dwEtwRootFlags,
1755 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1757 LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Reference. "
1758 "ObjectID:0x%p dwEtwRootKind:0x%x dwEtwRootFlags:0x%x rootId:0x%p HeadId:0x%p\n",
1759 objectId, dwEtwRootKind, dwEtwRootFlags, rootID, pHeapId));
1761 DWORD dwProfApiRootFlags = EtwRootFlagsToProfApiRootFlags(dwEtwRootFlags);
1762 DWORD dwProfApiRootKind = EtwRootKindToProfApiRootKind((EtwGCRootKind) dwEtwRootKind);
1764 // Get a pointer to the data for this heap
1765 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1767 // If this is the first notification of an extended root reference for this heap
1768 // in this particular gc activation, then we need to get a ref data block
1769 // from the free list of blocks, or if that's empty then we need to
1770 // allocate a new one.
1773 pData = AllocateMovedReferencesData();
1775 return (E_OUTOFMEMORY);
1777 // Set the cookie so that we will be provided it on subsequent
1779 ((*((size_t *)pHeapId))) = (size_t)pData;
1782 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1784 // If the struct has been filled, then we need to notify the profiler of
1785 // these root references and clear the struct for the next load of
1787 if (pData->curIdx == kcReferencesMax)
1789 RootReferences2(pData);
1793 // Now save the information in the struct
1794 pData->arrpbMemBlockStartOld[pData->curIdx] = objectId;
1795 pData->arrpbMemBlockStartNew[pData->curIdx] = (BYTE *)rootID;
1797 // assert that dwProfApiRootKind and dwProfApiRootFlags both fit in 16 bits, so we can
1798 // pack both into a 32-bit word
1799 _ASSERTE((dwProfApiRootKind & 0xffff) == dwProfApiRootKind && (dwProfApiRootFlags & 0xffff) == dwProfApiRootFlags);
1801 pData->arrULONG[pData->curIdx] = (dwProfApiRootKind << 16) | dwProfApiRootFlags;
1803 // Increment the index into the parallel arrays
1809 //---------------------------------------------------------------------------------------
1811 // Called by the GC to indicate that the GC is finished calling
1812 // EEToProfInterfaceImpl::RootReference2 for this collection. This function will
1813 // call into the profiler to notify it of all the root references we've cached.
1816 // pHeapId - Casted to a GCReferencesData * that contains the root references
1820 // HRESULT indicating success or failure.
1823 HRESULT EEToProfInterfaceImpl::EndRootReferences2(void * pHeapId)
1826 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1830 // Get a pointer to the data for this heap
1831 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1833 // If there were no moved references, profiler doesn't need to know
1837 // Communicate the moved references to the profiler
1838 _ASSERTE(pData->curIdx> 0);
1839 hr = RootReferences2(pData);
1841 // Now we're done with the data block, we can shove it onto the free list
1842 FreeMovedReferencesData(pData);
1845 // Set the cookie to an invalid number
1846 (*((size_t *)pHeapId)) = (size_t)(-1);
1852 //---------------------------------------------------------------------------------------
1854 // Callback used by the GC when scanning the roots (via
1855 // Ref_ScanDependentHandlesForProfilerAndETW in ObjectHandle.cpp).
1858 // primaryObjectId - Primary object reference in the DependentHandle
1859 // secondaryObjectId - Secondary object reference in the DependentHandle
1860 // rootID - The DependentHandle maintaining the dependency relationship
1861 // pHeapId - Used as a GCReferencesData * to keep track of the GC references
1864 // HRESULT indicating success or failure.
1867 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReference(BYTE * primaryObjectId,
1868 BYTE * secondaryObjectId,
1873 _ASSERTE(*((size_t *)pHeapId) != (size_t)(-1));
1875 // Callers must ensure the profiler asked to be notified about dependent handles,
1876 // since this is only available for profilers implementing ICorProfilerCallback5 and
1878 _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1880 LOG((LF_CORPROF, LL_INFO100000, "**PROF: Root Dependent Handle. "
1881 "PrimaryObjectID:0x%p SecondaryObjectID:0x%p rootId:0x%p HeadId:0x%p\n",
1882 primaryObjectId, secondaryObjectId, rootID, pHeapId));
1884 // Get a pointer to the data for this heap
1885 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1887 // If this is the first notification of a dependent handle reference in
1888 // this particular gc activation, then we need to get a ref data block
1889 // from the free list of blocks, or if that's empty then we need to
1890 // allocate a new one.
1893 pData = AllocateMovedReferencesData();
1895 return (E_OUTOFMEMORY);
1897 // Set the cookie so that we will be provided it on subsequent
1899 ((*((size_t *)pHeapId))) = (size_t)pData;
1902 _ASSERTE(pData->curIdx >= 0 && pData->curIdx <= kcReferencesMax);
1904 // If the struct has been filled, then we need to notify the profiler of
1905 // these dependent handle references and clear the struct for the next
1906 // load of dependent handle references
1907 if (pData->curIdx == kcReferencesMax)
1909 ConditionalWeakTableElementReferences(pData);
1913 // Now save the information in the struct
1914 pData->arrpbMemBlockStartOld[pData->curIdx] = primaryObjectId;
1915 pData->arrpbMemBlockStartNew[pData->curIdx] = secondaryObjectId;
1916 pData->arrpbRootId[pData->curIdx] = (BYTE*) rootID;
1918 // Increment the index into the parallel arrays
1924 //---------------------------------------------------------------------------------------
1926 // Called by the GC to indicate that the GC is finished calling
1927 // EEToProfInterfaceImpl::ConditionalWeakTableElementReference for this collection. This
1928 // function will call into the profiler to notify it of all the DependentHandle references
1932 // pHeapId - Casted to a GCReferencesData * that contains the dependent handle
1933 // references we've cached.
1936 // HRESULT indicating success or failure.
1939 HRESULT EEToProfInterfaceImpl::EndConditionalWeakTableElementReferences(void * pHeapId)
1942 _ASSERTE((*((size_t *)pHeapId)) != (size_t)(-1));
1944 // Callers must ensure the profiler asked to be notified about dependent handles,
1945 // since this is only available for profilers implementing ICorProfilerCallback5 and
1947 _ASSERTE(CORProfilerTrackConditionalWeakTableElements());
1951 // Get a pointer to the data for this heap
1952 GCReferencesData *pData = (GCReferencesData *)(*((size_t *)pHeapId));
1954 // If there were no dependent handles, profiler doesn't need to know
1958 // Communicate the dependent handle references to the profiler
1959 _ASSERTE(pData->curIdx > 0);
1960 hr = ConditionalWeakTableElementReferences(pData);
1962 // Now we're done with the data block, we can shove it onto the free list
1963 FreeMovedReferencesData(pData);
1966 // Set the cookie to an invalid number
1967 (*((size_t *)pHeapId)) = (size_t)(-1);
1975 //---------------------------------------------------------------------------------------
1977 // Returns whether the profiler performed unrevertible acts, such as instrumenting
1978 // code or requesting ELT hooks. RequestProfilerDetach uses this function before
1979 // performing any sealing or evacuation checks to determine whether it's even possible
1980 // for the profiler ever to detach.
1983 // * S_OK if it's safe to attempt a detach. Evacuation checks must still be performed
1984 // before actually unloading the profiler.
1985 // * else, an HRESULT error value indicating what the profiler did that made it
1986 // undetachable. This is a public HRESULT suitable for returning from the
1987 // RequestProfilerDetach API.
1990 HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable()
1992 LIMITED_METHOD_CONTRACT;
1994 if (((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0) ||
1995 ((g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != 0))
2000 "**PROF: Profiler may not detach because it set an immutable flag. Flags = 0x%x.\n",
2001 g_profControlBlock.dwEventMask));
2003 return CORPROF_E_IMMUTABLE_FLAGS_SET;
2006 if ((m_pEnter != NULL) ||
2007 (m_pLeave != NULL) ||
2008 (m_pTailcall != NULL) ||
2009 (m_pEnter2 != NULL) ||
2010 (m_pLeave2 != NULL) ||
2011 (m_pTailcall2 != NULL) ||
2012 (m_pEnter3 != NULL) ||
2013 (m_pEnter3WithInfo != NULL) ||
2014 (m_pLeave3 != NULL) ||
2015 (m_pLeave3WithInfo != NULL) ||
2016 (m_pTailcall3 != NULL) ||
2017 (m_pTailcall3WithInfo != NULL))
2022 "**PROF: Profiler may not detach because it set an ELT(2) hook.\n"));
2024 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2027 if (m_fUnrevertiblyModifiedIL)
2032 "**PROF: Profiler may not detach because it called SetILFunctionBody.\n"));
2034 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2037 if (m_fModifiedRejitState)
2042 "**PROF: Profiler may not detach because it enabled Rejit.\n"));
2044 return CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT;
2050 // Declarations for asm wrappers of profiler callbacks
2051 EXTERN_C void STDMETHODCALLTYPE ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID);
2052 EXTERN_C void STDMETHODCALLTYPE ProfileLeaveNaked(FunctionIDOrClientID functionIDOrClientID);
2053 EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID);
2054 #define PROFILECALLBACK(name) name##Naked
2056 //---------------------------------------------------------------------------------------
2058 // Determines the hooks (slow path vs. fast path) to which the JIT shall
2059 // insert calls, and then tells the JIT which ones we want
2062 // HRESULT indicating success or failure
2065 HRESULT EEToProfInterfaceImpl::DetermineAndSetEnterLeaveFunctionHooksForJit()
2076 // We're doing all ELT3 hooks, all-Whidbey hooks or all-Everett hooks. No mixing and matching.
2077 BOOL fCLRv4Hooks = (m_pEnter3 != NULL) ||
2078 (m_pLeave3 != NULL) ||
2079 (m_pTailcall3 != NULL) ||
2080 (m_pEnter3WithInfo != NULL) ||
2081 (m_pLeave3WithInfo != NULL) ||
2082 (m_pTailcall3WithInfo != NULL);
2084 BOOL fWhidbeyHooks = (m_pEnter2 != NULL) ||
2085 (m_pLeave2 != NULL) ||
2086 (m_pTailcall2 != NULL);
2088 // If no hooks were set (e.g., SetEventMask called with COR_PRF_MONITOR_ENTERLEAVE,
2089 // but SetEnterLeaveFunctionHooks(*) never called), then nothing to do
2092 (m_pEnter == NULL) &&
2093 (m_pLeave == NULL) &&
2094 (m_pTailcall == NULL))
2106 // For each type of hook (enter/leave/tailcall) we must determine if we can use the
2107 // happy lucky fast path (i.e., direct call from JITd code right into the profiler's
2108 // hook or the JIT default stub (see below)), or the slow path (i.e., call into an
2109 // intermediary FCALL which then calls the profiler's hook) with extra information
2110 // about the current function.
2112 hr = SetEnterLeaveFunctionHooksForJit(
2113 (m_pEnter3WithInfo != NULL) ?
2114 PROFILECALLBACK(ProfileEnter) :
2116 (m_pLeave3WithInfo != NULL) ?
2117 PROFILECALLBACK(ProfileLeave) :
2119 (m_pTailcall3WithInfo != NULL) ?
2120 PROFILECALLBACK(ProfileTailcall) :
2126 // Everett or Whidbey hooks.
2129 // When using Everett or Whidbey hooks, the check looks like this:
2132 // THEN Use slow path
2136 // - If the profiler wants the old-style Whidbey or Everett hooks, we need a wrapper
2137 // to convert from the ELT3 prototype the JIT expects to the Whidbey or Everett
2138 // prototype the profiler expects. It applies to Whidbey fast-path hooks. And due
2139 // to the overhead of looking up FunctionID from cache and using lock to synchronize
2140 // cache accesses, the so-called Whidbey fast-path hooks are much slower than they
2141 // used to be. Whidbey and Everett hooks are supported to keep existing profiler
2142 // running, but the profiler writers are encouraged to use ELT3 interface for the
2143 // best performance.
2145 // Implicit in the above logic is if one of the hook types has no hook pointer
2146 // specified, then we pass NULL as the hook pointer to the JIT, in which case the JIT
2147 // just generates a call to the default stub (a single ret) w/out invoking the slow-path
2148 // wrapper. I call this the "fast path to nowhere"
2150 BOOL fEnter = (m_pEnter != NULL) || (m_pEnter2 != NULL);
2151 BOOL fLeave = (m_pLeave != NULL) || (m_pLeave2 != NULL);
2152 BOOL fTailcall = (m_pTailcall != NULL) || (m_pTailcall2 != NULL);
2154 hr = SetEnterLeaveFunctionHooksForJit(
2156 PROFILECALLBACK(ProfileEnter) :
2159 PROFILECALLBACK(ProfileLeave) :
2162 PROFILECALLBACK(ProfileTailcall) :
2170 // We need to swallow all exceptions, because we will lock otherwise (in addition to
2171 // the IA64-only lock while allocating stub space!). For example, specifying
2172 // RethrowTerminalExceptions forces us to test to see if the caught exception is
2173 // terminal and Exception::IsTerminal() can lock if we get a handle table cache miss
2174 // while getting a handle for the exception. It is good to minimize locks from
2175 // profiler Info functions (and their callees), and this is a dumb lock to have,
2176 // given that we can avoid it altogether by just having terminal exceptions be
2177 // swallowed here, and returning the failure to the profiler. For those who don't
2178 // like swallowing terminal exceptions, this is mitigated by the fact that,
2179 // currently, an exception only gets thrown from SetEnterLeaveFunctionHooksForJit on
2180 // IA64. But to keep consistent (and in case the world changes), we'll do this on
2182 EX_END_CATCH(SwallowAllExceptions);
2188 //---------------------------------------------------------------------------------------
2190 // The Info method SetEventMask() simply defers to this function to do the real work.
2193 // dwEventMask - Event mask specified by the profiler
2196 // HRESULT indicating success / failure to return straight through to the profiler
2199 HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMaskHigh)
2206 EE_THREAD_NOT_REQUIRED;
2211 static const DWORD kEventFlagsRequiringSlowPathEnterLeaveHooks =
2212 COR_PRF_ENABLE_FUNCTION_ARGS |
2213 COR_PRF_ENABLE_FUNCTION_RETVAL |
2214 COR_PRF_ENABLE_FRAME_INFO
2217 static const DWORD kEventFlagsAffectingEnterLeaveHooks =
2218 COR_PRF_MONITOR_ENTERLEAVE |
2219 kEventFlagsRequiringSlowPathEnterLeaveHooks
2225 // Some tests need to enable immutable flags after startup, when a profiler is
2226 // attached. These flags enable features that are used solely to verify the
2227 // correctness of other, MUTABLE features. Examples: enable immutable ELT to create
2228 // shadow stacks to verify stack walks (which can be done mutably via manual
2229 // EBP-frame walking), or enable immutable DSS to gather IP addresses to verify the
2230 // mutable GetFunctionFromIP.
2232 // Similarly, test profilers may need to extend the set of flags allowable on attach
2233 // to enable features that help verify other parts of the profapi that ARE allowed
2236 // See code:#P2CLRRestrictionsOverview for more information
2237 DWORD dwImmutableEventFlags = COR_PRF_MONITOR_IMMUTABLE;
2238 DWORD dwAllowableAfterAttachEventFlags = COR_PRF_ALLOWABLE_AFTER_ATTACH;
2239 DWORD dwTestOnlyAllowedEventMask = 0;
2240 dwTestOnlyAllowedEventMask = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TestOnlyAllowedEventMask);
2241 if (dwTestOnlyAllowedEventMask != 0)
2243 // Remove from the immutable flag list those flags that a test-only profiler may
2244 // need to set post-startup (specified via COMPlus_TestOnlyAllowedEventMask)
2245 dwImmutableEventFlags &= ~dwTestOnlyAllowedEventMask;
2247 // And add to the "allowable after attach" list the same test-only flags.
2248 dwAllowableAfterAttachEventFlags |= dwTestOnlyAllowedEventMask;
2250 LOG((LF_CORPROF, LL_INFO10, "**PROF: TestOnlyAllowedEventMask=0x%x. New immutable flags=0x%x. New AllowableAfterAttach flags=0x%x\n",
2251 dwTestOnlyAllowedEventMask,
2252 dwImmutableEventFlags,
2253 dwAllowableAfterAttachEventFlags));
2257 // If we're not in initialization or shutdown, make sure profiler is
2258 // not trying to set an immutable attribute
2259 // FUTURE: If we add immutable flags to the high event mask, this would be a good
2260 // place to check for them as well.
2261 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2264 if (((dwEventMask & dwImmutableEventFlags) !=
2265 (g_profControlBlock.dwEventMask & dwImmutableEventFlags)) ||
2267 if (((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
2268 (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE)) ||
2270 ((dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) !=
2271 (g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE)))
2273 // FUTURE: Should we have a dedicated HRESULT for setting immutable flag?
2278 // If this is an attaching profiler, make sure the profiler only sets flags
2279 // allowable after an attach
2280 if (m_fLoadedViaAttach &&
2282 (((dwEventMask & (~dwAllowableAfterAttachEventFlags)) != 0) ||
2284 (((dwEventMask & (~COR_PRF_ALLOWABLE_AFTER_ATTACH)) != 0) ||
2286 (dwEventMaskHigh & (~COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH))))
2288 return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;
2291 // After fast path ELT hooks are set in Initial callback, the startup profiler is not allowed to change flags
2292 // that require slow path ELT hooks or disable ELT hooks.
2293 if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
2295 (m_pEnter3 != NULL) ||
2296 (m_pLeave3 != NULL) ||
2297 (m_pTailcall3 != NULL)
2300 ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0) ||
2301 ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2305 _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0);
2306 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2309 // After slow path ELT hooks are set in Initial callback, the startup profiler is not allowed to remove
2310 // all flags that require slow path ELT hooks or to change the flag to disable the ELT hooks.
2311 if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) &&
2313 (m_pEnter3WithInfo != NULL) ||
2314 (m_pLeave3WithInfo != NULL) ||
2315 (m_pTailcall3WithInfo != NULL)
2318 ((dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0) ||
2319 ((dwEventMask & COR_PRF_MONITOR_ENTERLEAVE) == 0)
2323 _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0);
2324 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2328 // Note whether the caller is changing flags that affect enter leave hooks
2329 BOOL fEnterLeaveHooksAffected =
2330 // Did any of the relevant flags change?
2334 ((g_profControlBlock.dwEventMask & kEventFlagsAffectingEnterLeaveHooks) ^
2335 // XORed w/ the new flags
2336 (dwEventMask & kEventFlagsAffectingEnterLeaveHooks))
2339 // And are any enter/leave hooks set?
2341 (m_pEnter3 != NULL) ||
2342 (m_pEnter3WithInfo != NULL) ||
2343 (m_pEnter2 != NULL) ||
2344 (m_pEnter != NULL) ||
2345 (m_pLeave3 != NULL) ||
2346 (m_pLeave3WithInfo != NULL) ||
2347 (m_pLeave2 != NULL) ||
2348 (m_pLeave != NULL) ||
2349 (m_pTailcall3 != NULL) ||
2350 (m_pTailcall3WithInfo != NULL) ||
2351 (m_pTailcall2 != NULL) ||
2352 (m_pTailcall != NULL)
2355 BOOL fNeedToTurnOffConcurrentGC = FALSE;
2357 if (((dwEventMask & COR_PRF_MONITOR_GC) != 0) &&
2358 ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_GC) == 0))
2360 // We don't need to worry about startup load as we'll turn off concurrent GC later
2361 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
2363 // Since we're not an initializing startup profiler, the EE must be fully started up
2364 // so we can check whether concurrent GC is on
2367 return CORPROF_E_RUNTIME_UNINITIALIZED;
2370 // We don't want to change the flag before GC is fully initialized,
2371 // otherwise the concurrent GC setting would be overwritten
2372 // Make sure GC is fully initialized before proceed
2373 if (!IsGarbageCollectorFullyInitialized())
2375 return CORPROF_E_NOT_YET_AVAILABLE;
2378 // If we are attaching and we are turning on COR_PRF_MONITOR_GC, turn off concurrent GC later
2380 if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForAttachLoad)
2382 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2384 // We only allow turning off concurrent GC in the profiler attach thread inside
2385 // InitializeForAttach, otherwise we would be vulnerable to weird races such as
2386 // SetEventMask running on a separate thread and trying to turn off concurrent GC.
2387 // The best option here is to fail with CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE.
2388 // Existing Dev10 profilers should be prepared to handle such case.
2389 if (IsProfilerAttachThread())
2391 fNeedToTurnOffConcurrentGC = TRUE;
2395 return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2401 // Fail if concurrent GC is enabled
2402 // This should only happen for attach profilers if user didn't turn on COR_PRF_MONITOR_GC
2404 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled())
2406 return CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE;
2412 if ((dwEventMask & COR_PRF_ENABLE_REJIT) != 0)
2414 if ((g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad) && !ReJitManager::IsReJITEnabled())
2416 return CORPROF_E_REJIT_NOT_ENABLED;
2419 g_profControlBlock.pProfInterface->SetModifiedRejitState();
2424 if (((dwEventMaskHigh & COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES) != 0) &&
2425 !IsCallback6Supported())
2427 return CORPROF_E_CALLBACK6_REQUIRED;
2430 if (((dwEventMaskHigh & COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED) != 0) &&
2431 !IsCallback7Supported())
2433 return CORPROF_E_CALLBACK7_REQUIRED;
2436 // Now save the modified masks
2437 g_profControlBlock.dwEventMask = dwEventMask;
2438 g_profControlBlock.dwEventMaskHigh = dwEventMaskHigh;
2440 if (fEnterLeaveHooksAffected)
2442 hr = DetermineAndSetEnterLeaveFunctionHooksForJit();
2449 if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad)
2451 // If the profiler has requested remoting cookies so that it can
2452 // track logical call stacks, then we must initialize the cookie
2454 if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_REMOTING_COOKIE)
2455 == COR_PRF_MONITOR_REMOTING_COOKIE)
2465 // Turn off concurrent GC as the last step so that we don't need to turn it back on if something
2466 // else failed after that
2467 if (fNeedToTurnOffConcurrentGC)
2469 // Turn off concurrent GC if it is on so that user can walk the heap safely in GC callbacks
2470 IGCHeap * pGCHeap = GCHeapUtilities::GetGCHeap();
2472 LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at attach.\n"));
2474 // First turn off concurrent GC
2475 pGCHeap->TemporaryDisableConcurrentGC();
2478 // Then wait until concurrent GC to finish if concurrent GC is in progress
2479 // User can use a timeout that can be set by environment variable if the GC turns out
2480 // to be too long. The default value is INFINITE.
2483 // If we don't do it in this order there might be a new concurrent GC started
2484 // before we actually turn off concurrent GC
2486 hr = pGCHeap->WaitUntilConcurrentGCCompleteAsync(m_dwConcurrentGCWaitTimeoutInMs);
2489 if (hr == HRESULT_FROM_WIN32(ERROR_TIMEOUT))
2491 // Convert it to a more specific HRESULT
2492 hr = CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC;
2494 // Since we cannot call LogProfEvent here due to contact violations, we'll need to
2495 // remember the fact that we've failed, and report the failure later after InitializeForAttach
2496 m_bHasTimedOutWaitingForConcurrentGC = TRUE;
2499 pGCHeap->TemporaryEnableConcurrentGC();
2503 // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling
2504 g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE;
2506 LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at attach.\n"));
2513 //---------------------------------------------------------------------------------------
2515 // The Info method SetEnterLeaveFunctionHooks() simply defers to this function to do the
2519 // (same as specified in the public API docs)
2522 // HRESULT indicating success / failure to return straight through to the profiler
2525 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
2526 FunctionLeave * pFuncLeave,
2527 FunctionTailcall * pFuncTailcall)
2534 EE_THREAD_NOT_REQUIRED;
2539 // You have to be setting at least one hook
2540 if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2542 return E_INVALIDARG;
2545 // ELT3 hooks beat Whidbey and Whidbey hooks beat Everett hooks. So if any ELT3 or
2546 // Whidbey hooks were set (SetEnterLeaveFunctionHooks3(WithInfo) or SetEnterLeaveFunctionHooks2),
2547 // this should be a noop
2548 if ((m_pEnter3 != NULL) ||
2549 (m_pEnter3WithInfo != NULL) ||
2550 (m_pLeave3 != NULL) ||
2551 (m_pLeave3WithInfo != NULL) ||
2552 (m_pTailcall3 != NULL) ||
2553 (m_pTailcall3WithInfo != NULL) ||
2554 (m_pEnter2 != NULL) ||
2555 (m_pLeave2 != NULL) ||
2556 (m_pTailcall2 != NULL))
2561 // Always save onto the function pointers, since we won't know if the profiler
2562 // is going to tracking enter/leave until after it returns from Initialize
2563 m_pEnter = pFuncEnter;
2564 m_pLeave = pFuncLeave;
2565 m_pTailcall = pFuncTailcall;
2567 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2570 //---------------------------------------------------------------------------------------
2572 // The Info method SetEnterLeaveFunctionHooks2() simply defers to this function to do the
2576 // (same as specified in the public API docs)
2579 // HRESULT indicating success / failure to return straight through to the profiler
2582 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
2583 FunctionLeave2 * pFuncLeave,
2584 FunctionTailcall2 * pFuncTailcall)
2591 EE_THREAD_NOT_REQUIRED;
2596 // You have to be setting at least one hook
2597 if ((pFuncEnter == NULL) && (pFuncLeave == NULL) && (pFuncTailcall == NULL))
2599 return E_INVALIDARG;
2602 // ELT3 hooks beat Whidbey. So if any ELT3 hooks were set (SetEnterLeaveFunctionHooks3(WithInfo)),
2603 // this should be a noop
2604 if ((m_pEnter3 != NULL) ||
2605 (m_pEnter3WithInfo != NULL) ||
2606 (m_pLeave3 != NULL) ||
2607 (m_pLeave3WithInfo != NULL) ||
2608 (m_pTailcall3 != NULL) ||
2609 (m_pTailcall3WithInfo != NULL))
2614 // Always save onto the function pointers, since we won't know if the profiler
2615 // is going to track enter/leave until after it returns from Initialize
2616 m_pEnter2 = pFuncEnter;
2617 m_pLeave2 = pFuncLeave;
2618 m_pTailcall2 = pFuncTailcall;
2620 // Whidbey hooks override Everett hooks
2625 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2628 //---------------------------------------------------------------------------------------
2630 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2634 // (same as specified in the public API docs)
2637 // HRESULT indicating success / failure to return straight through to the profiler
2640 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
2641 FunctionLeave3 * pFuncLeave3,
2642 FunctionTailcall3 * pFuncTailcall3)
2649 EE_THREAD_NOT_REQUIRED;
2654 // You have to be setting at least one hook
2655 if ((pFuncEnter3 == NULL) &&
2656 (pFuncLeave3 == NULL) &&
2657 (pFuncTailcall3 == NULL))
2659 return E_INVALIDARG;
2662 if (CORProfilerELT3SlowPathEnabled())
2664 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2667 // Always save onto the function pointers, since we won't know if the profiler
2668 // is going to track enter/leave until after it returns from Initialize
2669 m_pEnter3 = pFuncEnter3;
2670 m_pLeave3 = pFuncLeave3;
2671 m_pTailcall3 = pFuncTailcall3;
2672 m_pEnter3WithInfo = NULL;
2673 m_pLeave3WithInfo = NULL;
2674 m_pTailcall3WithInfo = NULL;
2676 // ELT3 hooks override Whidbey hooks and Everett hooks.
2679 m_pTailcall2 = NULL;
2684 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2688 //---------------------------------------------------------------------------------------
2690 // The Info method SetEnterLeaveFunctionHooks3() simply defers to this function to do the
2694 // (same as specified in the public API docs)
2697 // HRESULT indicating success / failure to return straight through to the profiler
2700 HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
2701 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
2702 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
2709 EE_THREAD_NOT_REQUIRED;
2714 // You have to be setting at least one hook
2715 if ((pFuncEnter3WithInfo == NULL) &&
2716 (pFuncLeave3WithInfo == NULL) &&
2717 (pFuncTailcall3WithInfo == NULL))
2719 return E_INVALIDARG;
2722 if (!CORProfilerELT3SlowPathEnabled())
2724 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
2727 // Always save onto the function pointers, since we won't know if the profiler
2728 // is going to track enter/leave until after it returns from Initialize
2729 m_pEnter3WithInfo = pFuncEnter3WithInfo;
2730 m_pLeave3WithInfo = pFuncLeave3WithInfo;
2731 m_pTailcall3WithInfo = pFuncTailcall3WithInfo;
2734 m_pTailcall3 = NULL;
2736 // ELT3 hooks override Whidbey hooks and Everett hooks.
2739 m_pTailcall2 = NULL;
2744 return DetermineAndSetEnterLeaveFunctionHooksForJit();
2749 //---------------------------------------------------------------------------------------
2751 // ************************
2752 // Public callback wrappers
2753 // ************************
2755 // NOTE: All public callback wrappers must follow the rules stated at the top
2758 // See corprof.idl / MSDN for detailed comments about each of these public
2759 // functions, their parameters, return values, etc.
2763 //---------------------------------------------------------------------------------------
2764 // INITIALIZE CALLBACKS
2767 HRESULT EEToProfInterfaceImpl::Initialize()
2784 ASSERT_NO_EE_LOCKS_HELD();
2789 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2792 "**PROF: Calling profiler's Initialize() method.\n"));
2794 _ASSERTE(m_pProfToEE != NULL);
2796 // Startup initialization occurs before an EEThread object is created for this
2798 _ASSERTE(GetThreadNULLOk() == NULL);
2801 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2802 // whose try/catch blocks aren't visible to the contract system
2803 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2804 return m_pCallback2->Initialize(m_pProfToEE);
2809 HRESULT EEToProfInterfaceImpl::InitializeForAttach(void * pvClientData, UINT cbClientData)
2826 ASSERT_NO_EE_LOCKS_HELD();
2831 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileInitializing,
2834 "**PROF: Calling profiler's InitializeForAttach() method.\n"));
2836 _ASSERTE(m_pProfToEE != NULL);
2838 // Attach initialization occurs on the AttachThread, which does not have an EEThread
2840 _ASSERTE(GetThreadNULLOk() == NULL);
2842 // Should only be called on profilers that support ICorProfilerCallback3
2843 _ASSERTE(m_pCallback3 != NULL);
2845 HRESULT hr = E_UNEXPECTED;
2847 // This wraps the profiler's InitializeForAttach callback in a try / catch. Although
2848 // most profiler calls are not protected, this initial callback IS, since it's cheap
2849 // to do so (this is only called once per attach of a profiler), and it would be nice to
2850 // avoid tearing down the entire process when attaching a profiler that may pass back
2854 hr = m_pCallback3->InitializeForAttach(m_pProfToEE, pvClientData, cbClientData);
2860 // Intentionally swallowing all exceptions, as we don't want a poorly-written
2861 // profiler that throws or AVs on attach to cause the entire process to go away.
2862 EX_END_CATCH(SwallowAllExceptions);
2867 HRESULT EEToProfInterfaceImpl::ProfilerAttachComplete()
2884 ASSERT_NO_EE_LOCKS_HELD();
2889 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
2891 "**PROF: Calling profiler's ProfilerAttachComplete() method.\n"));
2893 // Attach initialization occurs on the AttachThread, which does not have an EEThread
2895 _ASSERTE(GetThreadNULLOk() == NULL);
2897 // Should only be called on profilers that support ICorProfilerCallback3
2898 _ASSERTE(m_pCallback3 != NULL);
2900 HRESULT hr = E_UNEXPECTED;
2902 // This wraps the profiler's ProfilerAttachComplete callback in a try / catch.
2903 // Although most profiler calls are not protected, this early callback IS, since it's
2904 // cheap to do so (this is only called once per attach of a profiler), and it would be
2905 // nice to avoid tearing down the entire process when attaching a profiler that has
2906 // serious troubles initializing itself (e.g., in this case, with processing catch-up
2910 hr = m_pCallback3->ProfilerAttachComplete();
2916 // Intentionally swallowing all exceptions, as we don't want a poorly-written
2917 // profiler that throws or AVs on attach to cause the entire process to go away.
2918 EX_END_CATCH(SwallowAllExceptions);
2924 //---------------------------------------------------------------------------------------
2929 HRESULT EEToProfInterfaceImpl::ThreadCreated(ThreadID threadId)
2939 // Preemptive mode is particularly important here. See comment in
2940 // EEToProfInterfaceImpl::ThreadDestroyed for more information.
2947 ASSERT_NO_EE_LOCKS_HELD();
2952 // Normally these callback wrappers ask IsGCSpecial() and return without calling the
2953 // profiler if true. However, ThreadCreated() is the special case where no caller
2954 // should even get this far for GC Special threads, since our callers need to know to
2955 // avoid the GCX_PREEMP around the call to this function in the first place. See
2956 // code:Thread::m_fGCSpecial
2957 _ASSERTE(!reinterpret_cast<Thread *>(threadId)->IsGCSpecial());
2959 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
2962 "**PROF: Notifying profiler of created thread. ThreadId: 0x%p.\n",
2965 // Notify the profiler of the newly created thread.
2967 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
2968 // whose try/catch blocks aren't visible to the contract system
2969 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
2970 return m_pCallback2->ThreadCreated(threadId);
2974 HRESULT EEToProfInterfaceImpl::ThreadDestroyed(ThreadID threadId)
2984 // See comment below
2990 // Thread store lock is typically held during this callback
2995 if (reinterpret_cast<Thread *>(threadId)->IsGCSpecial())
2998 // In general, we like callbacks to switch to preemptive before calling into the
2999 // profiler. And this is particularly important to do in the ThreadCreated &
3000 // ThreadDestroyed callbacks.
3002 // The profiler will typically block in the ThreadDestroyed callback, because
3003 // it must coordinate the use of this threadid amongst all profiler
3004 // threads. For instance, if a separate thread A is walking "this" (via DoStackSnapshot),
3005 // then the profiler must block in ThreadDestroyed until A is finished. Otherwise,
3006 // "this" will complete its destruction before A's walk is complete.
3008 // Since the profiler will block indefinitely in ThreadDestroyed, we need
3009 // to switch to preemptive mode. Otherwise, if another thread B needs to suspend
3010 // the runtime (due to appdomain unload, GC, etc.), thread B will block
3011 // waiting for "this" (assuming we allow "this" to remain in cooperative mode),
3012 // while the profiler forces "this" to block on thread A from
3013 // the example above. And thread A may need to block on thread B, since
3014 // the stackwalking occasionally needs to switch to cooperative to access a
3015 // hash map (thus DoStackSnapshot forces the switch to cooperative up-front, before
3016 // the target thread to be walked gets suspended (yet another deadlock possibility)),
3017 // and switching to cooperative requires a wait until an in-progress GC or
3018 // EE suspension is complete. In other words, allowing "this" to remain
3019 // in cooperative mode could lead to a 3-way deadlock:
3020 // "this" waits on A
3022 // B waits on "this".
3023 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(threadId,
3026 "**PROF: Notifying profiler of destroyed thread. ThreadId: 0x%p.\n",
3029 // From now on, issue no more callbacks for this thread
3030 SetProfilerCallbacksAllowedForThread((Thread *) threadId, FALSE);
3032 // Notify the profiler of the destroyed thread
3034 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3035 // whose try/catch blocks aren't visible to the contract system
3036 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3037 return m_pCallback2->ThreadDestroyed(threadId);
3041 HRESULT EEToProfInterfaceImpl::ThreadAssignedToOSThread(ThreadID managedThreadId,
3049 // Called by notrigger Thread::DetachThread & CorHost::SwitchOutLogicalThreadState
3050 // which do look to be dangerous times to be triggering a GC
3053 // This is called in notrigger zones (see above), so it's not safe to switch to preemptive
3060 ASSERT_NO_EE_LOCKS_HELD();
3065 if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3068 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD_EX(
3073 "**PROF: Notifying profiler of thread assignment. ThreadId: 0x%p, OSThreadId: 0x%08x\n",
3077 // Notify the profiler of the thread being assigned to the OS thread
3079 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3080 // whose try/catch blocks aren't visible to the contract system
3081 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3082 return m_pCallback2->ThreadAssignedToOSThread(managedThreadId, osThreadId);
3086 HRESULT EEToProfInterfaceImpl::ThreadNameChanged(ThreadID managedThreadId,
3088 __in_ecount_opt(cchName) WCHAR name[])
3105 ASSERT_NO_EE_LOCKS_HELD();
3110 if (reinterpret_cast<Thread *>(managedThreadId)->IsGCSpecial())
3113 CLR_TO_PROFILER_ENTRYPOINT_FOR_THREAD(managedThreadId,
3116 "**PROF: Notifying profiler of thread name change.\n"));
3119 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3120 // whose try/catch blocks aren't visible to the contract system
3121 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3122 return m_pCallback2->ThreadNameChanged(managedThreadId, cchName, name);
3126 //---------------------------------------------------------------------------------------
3127 // EE STARTUP/SHUTDOWN EVENTS
3130 HRESULT EEToProfInterfaceImpl::Shutdown()
3147 ASSERT_NO_EE_LOCKS_HELD();
3152 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3154 "**PROF: Notifying profiler that shutdown is beginning.\n"));
3157 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3158 // whose try/catch blocks aren't visible to the contract system
3159 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3160 return m_pCallback2->Shutdown();
3164 //---------------------------------------------------------------------------------------
3165 // JIT/FUNCTION EVENTS
3168 HRESULT EEToProfInterfaceImpl::FunctionUnloadStarted(FunctionID functionId)
3170 _ASSERTE(!"FunctionUnloadStarted() callback no longer issued");
3174 HRESULT EEToProfInterfaceImpl::JITCompilationFinished(FunctionID functionId,
3176 BOOL fIsSafeToBlock)
3192 // The JIT / MethodDesc code likely hold locks while this callback is made
3197 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3199 "**PROF: JITCompilationFinished 0x%p, hr=0x%08x.\n",
3203 _ASSERTE(functionId);
3206 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3207 // whose try/catch blocks aren't visible to the contract system
3208 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3209 return m_pCallback2->JITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3214 HRESULT EEToProfInterfaceImpl::JITCompilationStarted(FunctionID functionId,
3215 BOOL fIsSafeToBlock)
3231 // The JIT / MethodDesc code likely hold locks while this callback is made
3236 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3238 "**PROF: JITCompilationStarted 0x%p.\n",
3241 // Currently JITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3242 // it's safe to remove this assert, but this should serve as a trigger to change our
3243 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3244 _ASSERTE(fIsSafeToBlock);
3246 _ASSERTE(functionId);
3249 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3250 // whose try/catch blocks aren't visible to the contract system
3251 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3252 return m_pCallback2->JITCompilationStarted(functionId, fIsSafeToBlock);
3256 HRESULT EEToProfInterfaceImpl::DynamicMethodUnloaded(FunctionID functionId)
3262 MODE_COOPERATIVE; // RuntimeMethodHandle::Destroy (the caller) moves from QCALL to GCX_COOP
3267 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3269 "**PROF: DynamicMethodUnloaded 0x%p.\n",
3272 _ASSERTE(functionId);
3274 if (m_pCallback9 == NULL)
3280 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3281 // whose try/catch blocks aren't visible to the contract system
3282 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3283 return m_pCallback9->DynamicMethodUnloaded(functionId);
3287 HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationFinished(FunctionID functionId,
3289 BOOL fIsSafeToBlock)
3298 // The JIT / MethodDesc code likely hold locks while this callback is made
3303 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3305 "**PROF: DynamicMethodJITCompilationFinished 0x%p.\n",
3308 _ASSERTE(functionId);
3310 if (m_pCallback8 == NULL)
3316 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3317 // whose try/catch blocks aren't visible to the contract system
3318 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3319 return m_pCallback8->DynamicMethodJITCompilationFinished(functionId, hrStatus, fIsSafeToBlock);
3323 HRESULT EEToProfInterfaceImpl::DynamicMethodJITCompilationStarted(FunctionID functionId,
3324 BOOL fIsSafeToBlock,
3335 // The JIT / MethodDesc code likely hold locks while this callback is made
3340 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3342 "**PROF: DynamicMethodJITCompilationStarted 0x%p.\n",
3345 _ASSERTE(functionId);
3347 // Currently DynamicMethodJITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3348 // it's safe to remove this assert, but this should serve as a trigger to change our
3349 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3350 _ASSERTE(fIsSafeToBlock);
3352 if (m_pCallback8 == NULL)
3358 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3359 // whose try/catch blocks aren't visible to the contract system
3360 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3361 return m_pCallback8->DynamicMethodJITCompilationStarted(functionId, fIsSafeToBlock, pILHeader, cbILHeader);
3365 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchStarted(
3366 /* [in] */ FunctionID functionId,
3367 /* [out] */ BOOL *pbUseCachedFunction)
3383 // The JIT / MethodDesc code likely hold locks while this callback is made
3388 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3390 "**PROF: JITCachedFunctionSearchStarted 0x%p.\n",
3392 _ASSERTE(functionId);
3393 _ASSERTE(pbUseCachedFunction != NULL);
3396 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3397 // whose try/catch blocks aren't visible to the contract system
3398 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3399 return m_pCallback2->JITCachedFunctionSearchStarted(functionId, pbUseCachedFunction);
3403 HRESULT EEToProfInterfaceImpl::JITCachedFunctionSearchFinished(
3404 /* [in] */ FunctionID functionId,
3405 /* [in] */ COR_PRF_JIT_CACHE result)
3421 // The JIT / MethodDesc code likely hold locks while this callback is made
3426 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3428 "**PROF: JITCachedFunctionSearchFinished 0x%p, %s.\n",
3430 (result == COR_PRF_CACHED_FUNCTION_FOUND ?
3431 "Cached function found" :
3432 "Cached function not found")));
3434 _ASSERTE(functionId);
3437 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3438 // whose try/catch blocks aren't visible to the contract system
3439 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3440 return m_pCallback2->JITCachedFunctionSearchFinished(functionId, result);
3445 HRESULT EEToProfInterfaceImpl::JITFunctionPitched(FunctionID functionId)
3447 _ASSERTE(!"JITFunctionPitched() callback no longer issued");
3451 HRESULT EEToProfInterfaceImpl::JITInlining(
3452 /* [in] */ FunctionID callerId,
3453 /* [in] */ FunctionID calleeId,
3454 /* [out] */ BOOL * pfShouldInline)
3470 // The JIT / MethodDesc code likely hold locks while this callback is made
3475 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3477 "**PROF: JITInlining caller: 0x%p, callee: 0x%p.\n",
3485 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3486 // whose try/catch blocks aren't visible to the contract system
3487 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3488 return m_pCallback2->JITInlining(callerId, calleeId, pfShouldInline);
3492 HRESULT EEToProfInterfaceImpl::ReJITCompilationStarted(
3493 /* [in] */ FunctionID functionId,
3494 /* [in] */ ReJITID reJitId,
3495 /* [in] */ BOOL fIsSafeToBlock)
3511 // The JIT / MethodDesc code likely hold locks while this callback is made
3516 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3518 "**PROF: ReJITCompilationStarted 0x%p 0x%p.\n",
3519 functionId, reJitId));
3521 // Should only be called on profilers that support ICorProfilerCallback4
3522 _ASSERTE(m_pCallback4 != NULL);
3524 // Currently ReJITCompilationStarted is always called with fIsSafeToBlock==TRUE. If this ever changes,
3525 // it's safe to remove this assert, but this should serve as a trigger to change our
3526 // public documentation to state that this callback is no longer called in preemptive mode all the time.
3527 _ASSERTE(fIsSafeToBlock);
3529 _ASSERTE(functionId);
3533 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3534 // whose try/catch blocks aren't visible to the contract system
3535 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3536 return m_pCallback4->ReJITCompilationStarted(functionId, reJitId, fIsSafeToBlock);
3540 HRESULT EEToProfInterfaceImpl::GetReJITParameters(
3541 /* [in] */ ModuleID moduleId,
3542 /* [in] */ mdMethodDef methodId,
3543 /* [in] */ ICorProfilerFunctionControl *
3560 // The ReJIT code holds a lock while this callback is made
3565 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3567 "**PROF: GetReJITParameters 0x%p 0x%p.\n",
3568 moduleId, methodId));
3570 // Should only be called on profilers that support ICorProfilerCallback4
3571 _ASSERTE(m_pCallback4 != NULL);
3576 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3577 // whose try/catch blocks aren't visible to the contract system
3578 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3579 return m_pCallback4->GetReJITParameters(moduleId, methodId, pFunctionControl);
3583 HRESULT EEToProfInterfaceImpl::ReJITCompilationFinished(
3584 /* [in] */ FunctionID functionId,
3585 /* [in] */ ReJITID reJitId,
3586 /* [in] */ HRESULT hrStatus,
3587 /* [in] */ BOOL fIsSafeToBlock)
3603 // ReJit holds a lock as well as possibly others...
3608 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3610 "**PROF: ReJITCompilationFinished 0x%p 0x%p hr=0x%x.\n",
3611 functionId, reJitId, hrStatus));
3613 // Should only be called on profilers that support ICorProfilerCallback4
3614 _ASSERTE(m_pCallback4 != NULL);
3616 _ASSERTE(functionId);
3620 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3621 // whose try/catch blocks aren't visible to the contract system
3622 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3623 return m_pCallback4->ReJITCompilationFinished(functionId, reJitId, hrStatus, fIsSafeToBlock);
3628 HRESULT EEToProfInterfaceImpl::ReJITError(
3629 /* [in] */ ModuleID moduleId,
3630 /* [in] */ mdMethodDef methodId,
3631 /* [in] */ FunctionID functionId,
3632 /* [in] */ HRESULT hrStatus)
3651 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3653 "**PROF: ReJITError 0x%p 0x%x 0x%p 0x%x.\n",
3654 moduleId, methodId, functionId, hrStatus));
3656 // Should only be called on profilers that support ICorProfilerCallback4
3657 _ASSERTE(m_pCallback4 != NULL);
3660 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3661 // whose try/catch blocks aren't visible to the contract system
3662 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3663 return m_pCallback4->ReJITError(moduleId, methodId, functionId, hrStatus);
3667 //---------------------------------------------------------------------------------------
3671 HRESULT EEToProfInterfaceImpl::ModuleLoadStarted(ModuleID moduleId)
3681 // This has historically not run in preemptive, and is called from cooperative-mode
3682 // functions. However, since we're triggers, it might actually be safe to consider
3683 // letting this run in preemptive mode.
3690 ASSERT_NO_EE_LOCKS_HELD();
3695 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3697 "**PROF: ModuleLoadStarted 0x%p.\n",
3700 _ASSERTE(moduleId != 0);
3703 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3704 // whose try/catch blocks aren't visible to the contract system
3705 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3706 return m_pCallback2->ModuleLoadStarted(moduleId);
3711 HRESULT EEToProfInterfaceImpl::ModuleLoadFinished(
3730 ASSERT_NO_EE_LOCKS_HELD();
3735 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3737 "**PROF: ModuleLoadFinished 0x%p.\n",
3740 _ASSERTE(moduleId != 0);
3743 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3744 // whose try/catch blocks aren't visible to the contract system
3745 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3746 return m_pCallback2->ModuleLoadFinished(moduleId, hrStatus);
3752 HRESULT EEToProfInterfaceImpl::ModuleUnloadStarted(
3770 ASSERT_NO_EE_LOCKS_HELD();
3775 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3777 "**PROF: ModuleUnloadStarted 0x%p.\n",
3780 _ASSERTE(moduleId != 0);
3783 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3784 // whose try/catch blocks aren't visible to the contract system
3785 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3786 return m_pCallback2->ModuleUnloadStarted(moduleId);
3791 HRESULT EEToProfInterfaceImpl::ModuleUnloadFinished(
3810 ASSERT_NO_EE_LOCKS_HELD();
3815 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3817 "**PROF: ModuleUnloadFinished 0x%p.\n",
3819 _ASSERTE(moduleId != 0);
3821 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3822 // whose try/catch blocks aren't visible to the contract system
3823 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3824 return m_pCallback2->ModuleUnloadFinished(moduleId, hrStatus);
3829 HRESULT EEToProfInterfaceImpl::ModuleAttachedToAssembly(
3831 AssemblyID AssemblyId)
3848 ASSERT_NO_EE_LOCKS_HELD();
3853 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3855 "**PROF: ModuleAttachedToAssembly 0x%p, 0x%p.\n",
3859 _ASSERTE(moduleId != 0);
3862 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3863 // whose try/catch blocks aren't visible to the contract system
3864 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3865 return m_pCallback2->ModuleAttachedToAssembly(moduleId, AssemblyId);
3869 HRESULT EEToProfInterfaceImpl::ModuleInMemorySymbolsUpdated(ModuleID moduleId)
3888 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3890 "**PROF: ModuleInMemorySymbolsUpdated. moduleId: 0x%p.\n",
3895 _ASSERTE(IsCallback7Supported());
3898 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3899 // whose try/catch blocks aren't visible to the contract system
3900 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3901 hr = m_pCallback7->ModuleInMemorySymbolsUpdated(moduleId);
3907 //---------------------------------------------------------------------------------------
3911 HRESULT EEToProfInterfaceImpl::ClassLoadStarted(
3928 // UnresolvedClassLock typically held during this callback
3933 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3935 "**PROF: ClassLoadStarted 0x%p.\n",
3941 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3942 // whose try/catch blocks aren't visible to the contract system
3943 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3944 return m_pCallback2->ClassLoadStarted(classId);
3949 HRESULT EEToProfInterfaceImpl::ClassLoadFinished(
3967 // UnresolvedClassLock typically held during this callback
3972 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
3974 "**PROF: ClassLoadFinished 0x%p, 0x%08x.\n",
3981 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
3982 // whose try/catch blocks aren't visible to the contract system
3983 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
3984 return m_pCallback2->ClassLoadFinished(classId, hrStatus);
3989 HRESULT EEToProfInterfaceImpl::ClassUnloadStarted(
4006 // Although not typical, it's possible for UnresolvedClassLock to be held
4007 // during this callback. This can occur if, during the class load, an
4008 // exception is thrown, and EEClass::Destruct is called from the catch clause
4009 // inside ClassLoader::CreateTypeHandleForTypeDefThrowing.
4014 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4016 "**PROF: ClassUnloadStarted 0x%p.\n",
4022 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4023 // whose try/catch blocks aren't visible to the contract system
4024 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4025 return m_pCallback2->ClassUnloadStarted(classId);
4030 HRESULT EEToProfInterfaceImpl::ClassUnloadFinished(
4048 // Locks can be held when this is called. See comment in ClassUnloadStarted
4053 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4055 "**PROF: ClassUnloadFinished 0x%p, 0x%08x.\n",
4062 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4063 // whose try/catch blocks aren't visible to the contract system
4064 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4065 return m_pCallback2->ClassUnloadFinished(classId, hrStatus);
4069 //---------------------------------------------------------------------------------------
4073 HRESULT EEToProfInterfaceImpl::AppDomainCreationStarted(
4074 AppDomainID appDomainId)
4091 ASSERT_NO_EE_LOCKS_HELD();
4096 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4098 "**PROF: AppDomainCreationStarted 0x%p.\n",
4101 _ASSERTE(appDomainId != 0);
4104 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4105 // whose try/catch blocks aren't visible to the contract system
4106 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4107 return m_pCallback2->AppDomainCreationStarted(appDomainId);
4112 HRESULT EEToProfInterfaceImpl::AppDomainCreationFinished(
4113 AppDomainID appDomainId,
4131 ASSERT_NO_EE_LOCKS_HELD();
4136 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4138 "**PROF: AppDomainCreationFinished 0x%p, 0x%08x.\n",
4142 _ASSERTE(appDomainId != 0);
4145 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4146 // whose try/catch blocks aren't visible to the contract system
4147 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4148 return m_pCallback2->AppDomainCreationFinished(appDomainId, hrStatus);
4152 HRESULT EEToProfInterfaceImpl::AppDomainShutdownStarted(
4153 AppDomainID appDomainId)
4170 ASSERT_NO_EE_LOCKS_HELD();
4175 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4177 "**PROF: AppDomainShutdownStarted 0x%p.\n",
4180 _ASSERTE(appDomainId != 0);
4183 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4184 // whose try/catch blocks aren't visible to the contract system
4185 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4186 return m_pCallback2->AppDomainShutdownStarted(appDomainId);
4190 HRESULT EEToProfInterfaceImpl::AppDomainShutdownFinished(
4191 AppDomainID appDomainId,
4209 ASSERT_NO_EE_LOCKS_HELD();
4214 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4216 "**PROF: AppDomainShutdownFinished 0x%p, 0x%08x.\n",
4220 _ASSERTE(appDomainId != 0);
4223 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4224 // whose try/catch blocks aren't visible to the contract system
4225 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4226 return m_pCallback2->AppDomainShutdownFinished(appDomainId, hrStatus);
4230 //---------------------------------------------------------------------------------------
4234 HRESULT EEToProfInterfaceImpl::AssemblyLoadStarted(
4235 AssemblyID assemblyId)
4245 // This has historically not run in preemptive, and is called from cooperative-mode
4246 // functions. However, since we're triggers, it might actually be safe to consider
4247 // letting this run in preemptive mode.
4254 ASSERT_NO_EE_LOCKS_HELD();
4259 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4261 "**PROF: AssemblyLoadStarted 0x%p.\n",
4264 _ASSERTE(assemblyId != 0);
4267 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4268 // whose try/catch blocks aren't visible to the contract system
4269 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4270 return m_pCallback2->AssemblyLoadStarted(assemblyId);
4274 HRESULT EEToProfInterfaceImpl::AssemblyLoadFinished(
4275 AssemblyID assemblyId,
4286 // This has historically not run in preemptive, and is called from cooperative-mode
4287 // functions. However, since we're triggers, it might actually be safe to consider
4288 // letting this run in preemptive mode.
4295 ASSERT_NO_EE_LOCKS_HELD();
4300 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4302 "**PROF: AssemblyLoadFinished 0x%p, 0x%08x.\n",
4306 _ASSERTE(assemblyId != 0);
4309 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4310 // whose try/catch blocks aren't visible to the contract system
4311 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4312 return m_pCallback2->AssemblyLoadFinished(assemblyId, hrStatus);
4316 HRESULT EEToProfInterfaceImpl::AssemblyUnloadStarted(
4317 AssemblyID assemblyId)
4334 ASSERT_NO_EE_LOCKS_HELD();
4339 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4341 "**PROF: AssemblyUnloadStarted 0x%p.\n",
4344 _ASSERTE(assemblyId != 0);
4347 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4348 // whose try/catch blocks aren't visible to the contract system
4349 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4350 return m_pCallback2->AssemblyUnloadStarted(assemblyId);
4354 HRESULT EEToProfInterfaceImpl::AssemblyUnloadFinished(
4355 AssemblyID assemblyId,
4373 ASSERT_NO_EE_LOCKS_HELD();
4378 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4380 "**PROF: AssemblyUnloadFinished 0x%p, 0x%08x.\n",
4384 _ASSERTE(assemblyId != 0);
4387 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4388 // whose try/catch blocks aren't visible to the contract system
4389 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4390 return m_pCallback2->AssemblyUnloadFinished(assemblyId, hrStatus);
4394 //---------------------------------------------------------------------------------------
4395 // TRANSITION EVENTS
4398 HRESULT EEToProfInterfaceImpl::UnmanagedToManagedTransition(
4399 FunctionID functionId,
4400 COR_PRF_TRANSITION_REASON reason)
4417 ASSERT_NO_EE_LOCKS_HELD();
4422 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4424 "**PROF: UnmanagedToManagedTransition 0x%p.\n",
4427 _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4430 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4431 // whose try/catch blocks aren't visible to the contract system
4432 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4433 return m_pCallback2->UnmanagedToManagedTransition(functionId, reason);
4437 HRESULT EEToProfInterfaceImpl::ManagedToUnmanagedTransition(
4438 FunctionID functionId,
4439 COR_PRF_TRANSITION_REASON reason)
4456 ASSERT_NO_EE_LOCKS_HELD();
4461 _ASSERTE(reason == COR_PRF_TRANSITION_CALL || reason == COR_PRF_TRANSITION_RETURN);
4463 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4465 "**PROF: ManagedToUnmanagedTransition 0x%p.\n",
4469 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4470 // whose try/catch blocks aren't visible to the contract system
4471 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4472 return m_pCallback2->ManagedToUnmanagedTransition(functionId, reason);
4476 //---------------------------------------------------------------------------------------
4480 HRESULT EEToProfInterfaceImpl::ExceptionThrown(
4481 ObjectID thrownObjectId)
4491 // Preemptive mode would be bad, dude. There's an objectId in the param list!
4498 ASSERT_NO_EE_LOCKS_HELD();
4503 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4505 "**PROF: ExceptionThrown. ObjectID: 0x%p. ThreadID: 0x%p\n",
4510 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4511 // whose try/catch blocks aren't visible to the contract system
4512 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4513 return m_pCallback2->ExceptionThrown(thrownObjectId);
4517 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionEnter(
4518 FunctionID functionId)
4535 ASSERT_NO_EE_LOCKS_HELD();
4540 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4542 "**PROF: ExceptionSearchFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4547 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4548 // whose try/catch blocks aren't visible to the contract system
4549 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4550 return m_pCallback2->ExceptionSearchFunctionEnter(functionId);
4554 HRESULT EEToProfInterfaceImpl::ExceptionSearchFunctionLeave()
4571 ASSERT_NO_EE_LOCKS_HELD();
4576 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4578 "**PROF: ExceptionSearchFunctionLeave. ThreadID: 0x%p\n",
4582 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4583 // whose try/catch blocks aren't visible to the contract system
4584 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4585 return m_pCallback2->ExceptionSearchFunctionLeave();
4589 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterEnter(FunctionID functionId)
4606 ASSERT_NO_EE_LOCKS_HELD();
4611 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4613 "**PROF: ExceptionSearchFilterEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4618 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4619 // whose try/catch blocks aren't visible to the contract system
4620 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4621 return m_pCallback2->ExceptionSearchFilterEnter(functionId);
4625 HRESULT EEToProfInterfaceImpl::ExceptionSearchFilterLeave()
4642 ASSERT_NO_EE_LOCKS_HELD();
4647 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4649 "**PROF: ExceptionFilterLeave. ThreadID: 0x%p\n",
4653 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4654 // whose try/catch blocks aren't visible to the contract system
4655 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4656 return m_pCallback2->ExceptionSearchFilterLeave();
4660 HRESULT EEToProfInterfaceImpl::ExceptionSearchCatcherFound(FunctionID functionId)
4677 ASSERT_NO_EE_LOCKS_HELD();
4682 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4684 "**PROF: ExceptionSearchCatcherFound. ThreadID: 0x%p\n",
4688 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4689 // whose try/catch blocks aren't visible to the contract system
4690 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4691 return m_pCallback2->ExceptionSearchCatcherFound(functionId);
4695 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerEnter(FunctionID functionId)
4697 _ASSERTE(!"ExceptionOSHandlerEnter() callback no longer issued");
4701 HRESULT EEToProfInterfaceImpl::ExceptionOSHandlerLeave(FunctionID functionId)
4703 _ASSERTE(!"ExceptionOSHandlerLeave() callback no longer issued");
4707 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionEnter(FunctionID functionId)
4714 // Called by COMPlusUnwindCallback, which is notrigger
4717 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4718 // Thus, the profiler cannot block on this call.
4725 ASSERT_NO_EE_LOCKS_HELD();
4730 CLR_TO_PROFILER_ENTRYPOINT_EX(
4734 "**PROF: ExceptionUnwindFunctionEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4739 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4740 // whose try/catch blocks aren't visible to the contract system
4741 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4742 return m_pCallback2->ExceptionUnwindFunctionEnter(functionId);
4746 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFunctionLeave()
4753 // Called by COMPlusUnwindCallback, which is notrigger
4756 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4757 // Thus, the profiler cannot block on this call.
4764 ASSERT_NO_EE_LOCKS_HELD();
4769 CLR_TO_PROFILER_ENTRYPOINT_EX(
4773 "**PROF: ExceptionUnwindFunctionLeave. ThreadID: 0x%p\n",
4777 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4778 // whose try/catch blocks aren't visible to the contract system
4779 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4780 return m_pCallback2->ExceptionUnwindFunctionLeave();
4784 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyEnter(FunctionID functionId)
4791 // Called by COMPlusUnwindCallback, which is notrigger
4794 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4795 // Thus, the profiler cannot block on this call.
4802 ASSERT_NO_EE_LOCKS_HELD();
4807 CLR_TO_PROFILER_ENTRYPOINT_EX(
4811 "**PROF: ExceptionUnwindFinallyEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4816 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4817 // whose try/catch blocks aren't visible to the contract system
4818 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4819 return m_pCallback2->ExceptionUnwindFinallyEnter(functionId);
4823 HRESULT EEToProfInterfaceImpl::ExceptionUnwindFinallyLeave()
4830 // Called by COMPlusUnwindCallback, which is notrigger
4833 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4834 // Thus, the profiler cannot block on this call.
4841 ASSERT_NO_EE_LOCKS_HELD();
4846 CLR_TO_PROFILER_ENTRYPOINT_EX(
4850 "**PROF: ExceptionUnwindFinallyLeave. ThreadID: 0x%p\n",
4854 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4855 // whose try/catch blocks aren't visible to the contract system
4856 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4857 return m_pCallback2->ExceptionUnwindFinallyLeave();
4861 HRESULT EEToProfInterfaceImpl::ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId)
4868 // Called by COMPlusUnwindCallback, which is notrigger
4871 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4872 // Thus, the profiler cannot block on this call.
4879 ASSERT_NO_EE_LOCKS_HELD();
4884 CLR_TO_PROFILER_ENTRYPOINT_EX(
4887 LL_INFO1000, "**PROF: ExceptionCatcherEnter. ThreadID: 0x%p, functionId: 0x%p\n",
4892 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4893 // whose try/catch blocks aren't visible to the contract system
4894 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4895 return m_pCallback2->ExceptionCatcherEnter(functionId, objectId);
4899 HRESULT EEToProfInterfaceImpl::ExceptionCatcherLeave()
4909 // Cannot enable preemptive GC here, since the stack may not be in a GC-friendly state.
4910 // Thus, the profiler cannot block on this call.
4917 ASSERT_NO_EE_LOCKS_HELD();
4922 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4924 "**PROF: ExceptionCatcherLeave. ThreadID: 0x%p\n",
4929 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4930 // whose try/catch blocks aren't visible to the contract system
4931 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4932 return m_pCallback2->ExceptionCatcherLeave();
4937 //---------------------------------------------------------------------------------------
4938 // COM Callable Wrapper EVENTS
4941 HRESULT EEToProfInterfaceImpl::COMClassicVTableCreated(
4942 /* [in] */ ClassID classId,
4943 /* [in] */ REFGUID implementedIID,
4944 /* [in] */ void *pVTable,
4945 /* [in] */ ULONG cSlots)
4962 ASSERT_NO_EE_LOCKS_HELD();
4967 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
4969 "**PROF: COMClassicWrapperCreated %#x %#08x... %#x %d.\n",
4971 implementedIID.Data1,
4976 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
4977 // whose try/catch blocks aren't visible to the contract system
4978 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
4979 return m_pCallback2->COMClassicVTableCreated(classId, implementedIID, pVTable, cSlots);
4983 HRESULT EEToProfInterfaceImpl::COMClassicVTableDestroyed(
4984 /* [in] */ ClassID classId,
4985 /* [in] */ REFGUID implementedIID,
4986 /* [in] */ void *pVTable)
5003 ASSERT_NO_EE_LOCKS_HELD();
5008 // NOTE: There is no problem with this code, and it is ready and willing
5009 // to be called. However, this callback is intentionally not being
5010 // issued currently. See comment in ComMethodTable::Cleanup() for more
5013 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5015 "**PROF: COMClassicWrapperDestroyed %#x %#08x... %#x.\n",
5017 implementedIID.Data1,
5021 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5022 // whose try/catch blocks aren't visible to the contract system
5023 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5024 return m_pCallback2->COMClassicVTableDestroyed(classId, implementedIID, pVTable);
5029 //---------------------------------------------------------------------------------------
5030 // GC THREADING EVENTS
5033 HRESULT EEToProfInterfaceImpl::RuntimeSuspendStarted(
5034 COR_PRF_SUSPEND_REASON suspendReason)
5041 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5042 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5043 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
5044 // this thread at this time, we might see potential recursion or deadlock.
5052 // Thread store lock is typically held during this callback
5057 CLR_TO_PROFILER_ENTRYPOINT_EX(
5061 "**PROF: RuntimeSuspendStarted. ThreadID 0x%p.\n",
5065 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5066 // whose try/catch blocks aren't visible to the contract system
5067 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5068 return m_pCallback2->RuntimeSuspendStarted(suspendReason);
5072 HRESULT EEToProfInterfaceImpl::RuntimeSuspendFinished()
5079 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5080 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5081 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
5082 // this thread at this time, we might see potential recursion or deadlock.
5090 // Thread store lock is typically held during this callback
5095 CLR_TO_PROFILER_ENTRYPOINT_EX(
5099 "**PROF: RuntimeSuspendFinished. ThreadID 0x%p.\n",
5104 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5105 // whose try/catch blocks aren't visible to the contract system
5106 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5107 return m_pCallback2->RuntimeSuspendFinished();
5111 HRESULT EEToProfInterfaceImpl::RuntimeSuspendAborted()
5118 // Although the contract system doesn't yell if I mark this GC_TRIGGERS, it's safest
5119 // not to allow a GC to occur while we're suspending / resuming the runtime, this is
5120 // the thread trying to do a GC. So if the profiler tries to trigger another GC from
5121 // this thread at this time, we might see potential recursion or deadlock.
5124 // NOTE: I have no empirical data for gc mode: none of the self-host BVTs call this
5125 // So for now, assume this is callable in any mode.
5126 // This has historically not caused a mode change to preemptive, and is called from
5127 // cooperative-mode functions. Also, switching to preemptive while we're suspending
5128 // the runtime just seems like a bad idea.
5134 // Thread store lock is typically held during this callback
5139 CLR_TO_PROFILER_ENTRYPOINT_EX(
5143 "**PROF: RuntimeSuspendAborted. ThreadID 0x%p.\n",
5147 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5148 // whose try/catch blocks aren't visible to the contract system
5149 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5150 return m_pCallback2->RuntimeSuspendAborted();
5154 HRESULT EEToProfInterfaceImpl::RuntimeResumeStarted()
5164 // This has historically not caused a mode change to preemptive, and is called from
5165 // cooperative-mode functions. Also, switching to preemptive while we're resuming
5166 // the runtime just seems like a bad idea.
5172 // Thread store lock is typically held during this callback
5177 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5179 "**PROF: RuntimeResumeStarted. ThreadID 0x%p.\n",
5183 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5184 // whose try/catch blocks aren't visible to the contract system
5185 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5186 return m_pCallback2->RuntimeResumeStarted();
5190 HRESULT EEToProfInterfaceImpl::RuntimeResumeFinished()
5206 // Thread store lock is typically held during this callback
5211 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5213 "**PROF: RuntimeResumeFinished. ThreadID 0x%p.\n",
5217 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5218 // whose try/catch blocks aren't visible to the contract system
5219 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5220 return m_pCallback2->RuntimeResumeFinished();
5224 HRESULT EEToProfInterfaceImpl::RuntimeThreadSuspended(ThreadID suspendedThreadId)
5231 // Called by Thread::SuspendThread, which is notrigger.
5234 // Although I've verified we're called from both coop and preemp, we need to
5235 // avoid switching to preemptive to satisfy our notrigger paths.
5241 // Thread store lock is typically held during this callback
5246 if (reinterpret_cast<Thread *>(suspendedThreadId)->IsGCSpecial())
5249 // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5250 // we might be called at a time when profiler callbacks have been disallowed for
5251 // this thread. So we cannot simply ASSERT that callbacks are allowed (as this macro
5252 // does). Instead, we must explicitly check for this condition and return gracefully
5253 // if callbacks are disallowed. So the macro is unwrapped here manually
5255 CHECK_PROFILER_STATUS(kEE2PNone);
5257 LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadSuspended. ThreadID 0x%p.\n",
5258 suspendedThreadId));
5260 // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5262 // We may have already indicated to the profiler that this thread has died, but
5263 // the runtime may continue to suspend this thread during the process of destroying
5264 // the thread, so we do not want to indicate to the profiler these suspensions.
5265 if (!ProfilerCallbacksAllowedForThread((Thread *) suspendedThreadId))
5270 // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5271 SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5272 _ASSERTE(m_pCallback2 != NULL);
5275 // SCOPE: ForbidSuspendThreadHolder
5277 // The ForbidSuspendThreadHolder prevents deadlocks under the following scenario:
5278 // 1) Thread A blocks waiting for the current GC to complete (this can happen if A is trying to
5279 // switch to cooperative during a GC).
5280 // 2) This causes us to send a RuntimeThreadSuspended callback to the profiler. (Although
5281 // A isn't technically being "suspended", this blocking is considered suspension as far as the
5282 // profapi is concerned.)
5283 // 3) Profiler, in turn, may take one of its own private locks to synchronize this callback with
5284 // the profiler's attempt to hijack thread A. Specifically, the profiler knows it's not allowed
5285 // to hijack A if A is getting suspended by the runtime, because this suspension might be due to
5286 // the GC trying to hijack A. And if the GC tries to hijack A at the same time as the profiler
5287 // hijacking A and the profiler wins, then GC asserts because A is no longer at the IP that
5288 // the GC thought (VsWhidbey 428477, 429741)
5289 // 4) Meanwhile, thread B (GC thread) is suspending the runtime, and calls Thread::SuspendThread()
5290 // on A. This is the bad thing we're trying to avoid, because when this happens, we call into
5291 // the profiler AGAIN with RuntimeThreadSuspended for thread A, and the profiler again
5292 // tries to grab the lock it acquired in step 3). Yes, at this point we now have two simultaneous
5293 // calls into the profiler's RuntimeThreadSuspended() callback. One saying A is suspending A
5294 // (3 above), and one saying B is suspending A (this step (4)). The problem is that A is now officially
5295 // hard suspended, OS-style, so the lock acquired on 3) ain't never getting released until
5296 // A is resumed. But A won't be resumed until B resumes it. And B won't resume A until
5297 // the profiler returns from its RuntimeThreadSuspended callback. And the profiler
5298 // can't return from its RuntimeThreadSuspended callback until it acquires this lock it tried to
5299 // acquire in 4). And it can't acquire this lock until A is finally resumed so that the acquire
5300 // from 3) is released. Have we gone in a circle yet?
5301 // In order to avoid 4) we inc the ForbidSuspendThread count during 3) to prevent the hard suspension
5302 // (4) from occurring until 3) is completely done. It's sufficient to determine we're in 3) by noting
5303 // whether the callback is reporting that a thread is "suspending itself" (i.e., suspendedThreadId == threadId)
5305 ForbidSuspendThreadHolder forbidSuspendThread((Thread *) suspendedThreadId == GetThread());
5308 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5309 // whose try/catch blocks aren't visible to the contract system
5310 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5311 return m_pCallback2->RuntimeThreadSuspended(suspendedThreadId);
5316 HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId)
5323 // This gets called in response to another profapi function:
5324 // ICorProfilerInfo2::DoStackSnapshot! And that dude is called asynchronously and
5325 // must therefore never cause a GC.
5326 // Other reasons for notrigger: also called by notrigger dudes Thread::SysStartSuspendForDebug,
5327 // CheckSuspended, Thread::IsExecutingWithinCer, Thread::IsExecutingWithinCer,
5331 // Although we cannot trigger, verified empirically that this called coop & preemp
5337 // Thread store lock is typically held during this callback
5342 if (reinterpret_cast<Thread *>(resumedThreadId)->IsGCSpecial())
5345 // NOTE: We cannot use the standard CLR_TO_PROFILER_ENTRYPOINT macro here because
5346 // we might be called at a time when profiler callbacks have been disallowed for
5347 // this thread. So we cannot simply ASSERT that callbacks are allowed (as this macro
5348 // does). Instead, we must explicitly check for this condition and return gracefully
5349 // if callbacks are disallowed. So the macro is unwrapped here manually
5351 CHECK_PROFILER_STATUS(kEE2PNone);
5353 LOG((LF_CORPROF, LL_INFO1000, "**PROF: RuntimeThreadResumed. ThreadID 0x%p.\n", resumedThreadId));
5355 // NOTE: We're notrigger, so we cannot switch to preemptive mode.
5357 // We may have already indicated to the profiler that this thread has died, but
5358 // the runtime may resume this thread during the process of destroying
5359 // the thread, so we do not want to indicate to the profiler these resumes.
5360 if (!ProfilerCallbacksAllowedForThread((Thread *) resumedThreadId))
5365 // Remaining essentials from our entrypoint macros with kEE2PNoTrigger flag
5366 SetCallbackStateFlagsHolder csf(COR_PRF_CALLBACKSTATE_INCALLBACK);
5367 _ASSERTE(m_pCallback2 != NULL);
5370 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5371 // whose try/catch blocks aren't visible to the contract system
5372 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5373 return m_pCallback2->RuntimeThreadResumed(resumedThreadId);
5377 //---------------------------------------------------------------------------------------
5381 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationStarted()
5398 ASSERT_NO_EE_LOCKS_HELD();
5403 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5405 "**PROF: RemotingClientInvocationStarted. ThreadID: 0x%p\n",
5409 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5410 // whose try/catch blocks aren't visible to the contract system
5411 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5412 return m_pCallback2->RemotingClientInvocationStarted();
5416 HRESULT EEToProfInterfaceImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync)
5433 ASSERT_NO_EE_LOCKS_HELD();
5438 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5440 "**PROF: RemotingClientSendingMessage. ThreadID: 0x%p\n",
5444 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5445 // whose try/catch blocks aren't visible to the contract system
5446 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5447 return m_pCallback2->RemotingClientSendingMessage(pCookie, fIsAsync);
5451 HRESULT EEToProfInterfaceImpl::RemotingClientReceivingReply(GUID * pCookie, BOOL fIsAsync)
5468 ASSERT_NO_EE_LOCKS_HELD();
5473 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5475 "**PROF: RemotingClientReceivingReply. ThreadID: 0x%p\n",
5479 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5480 // whose try/catch blocks aren't visible to the contract system
5481 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5482 return m_pCallback2->RemotingClientReceivingReply(pCookie, fIsAsync);
5486 HRESULT EEToProfInterfaceImpl::RemotingClientInvocationFinished()
5503 ASSERT_NO_EE_LOCKS_HELD();
5508 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5510 "**PROF: RemotingClientInvocationFinished. ThreadID: 0x%p\n",
5514 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5515 // whose try/catch blocks aren't visible to the contract system
5516 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5517 return m_pCallback2->RemotingClientInvocationFinished();
5521 HRESULT EEToProfInterfaceImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync)
5538 ASSERT_NO_EE_LOCKS_HELD();
5543 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5545 "**PROF: RemotingServerReceivingMessage. ThreadID: 0x%p\n",
5549 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5550 // whose try/catch blocks aren't visible to the contract system
5551 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5552 return m_pCallback2->RemotingServerReceivingMessage(pCookie, fIsAsync);
5556 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationStarted()
5573 ASSERT_NO_EE_LOCKS_HELD();
5578 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5580 "**PROF: RemotingServerInvocationStarted. ThreadID: 0x%p\n",
5584 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5585 // whose try/catch blocks aren't visible to the contract system
5586 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5587 return m_pCallback2->RemotingServerInvocationStarted();
5591 HRESULT EEToProfInterfaceImpl::RemotingServerInvocationReturned()
5608 ASSERT_NO_EE_LOCKS_HELD();
5613 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5615 "**PROF: RemotingServerInvocationReturned. ThreadID: 0x%p\n",
5619 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5620 // whose try/catch blocks aren't visible to the contract system
5621 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5622 return m_pCallback2->RemotingServerInvocationReturned();
5626 HRESULT EEToProfInterfaceImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync)
5643 ASSERT_NO_EE_LOCKS_HELD();
5648 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5650 "**PROF: RemotingServerSendingReply. ThreadID: 0x%p\n",
5654 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5655 // whose try/catch blocks aren't visible to the contract system
5656 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5657 return m_pCallback2->RemotingServerSendingReply(pCookie, fIsAsync);
5661 //---------------------------------------------------------------------------------------
5665 HRESULT EEToProfInterfaceImpl::ObjectAllocated(
5666 /* [in] */ ObjectID objectId,
5667 /* [in] */ ClassID classId)
5677 // Preemptive mode would be bad, dude. There's an objectId in the param list!
5683 // CrstAppDomainHandleTable can be held while this is called
5688 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5690 "**PROF: ObjectAllocated. ObjectID: 0x%p. ClassID: 0x%p\n",
5695 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5696 // whose try/catch blocks aren't visible to the contract system
5697 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5698 return m_pCallback2->ObjectAllocated(objectId, classId);
5703 HRESULT EEToProfInterfaceImpl::MovedReferences(GCReferencesData *pData)
5710 // This is called by the thread doing a GC WHILE it does the GC
5713 // This is called by the thread doing a GC WHILE it does the GC
5714 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5719 // Thread store lock normally held during this callback
5724 CLR_TO_PROFILER_ENTRYPOINT_EX(
5728 "**PROF: MovedReferences.\n"));
5730 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5732 if (pData->curIdx == 0)
5739 if (pData->compactingCount != 0)
5741 _ASSERTE(pData->curIdx == pData->compactingCount);
5743 if (m_pCallback4 != NULL)
5745 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5746 // whose try/catch blocks aren't visible to the contract system
5747 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5748 hr = m_pCallback4->MovedReferences2((ULONG)pData->curIdx,
5749 (ObjectID *)pData->arrpbMemBlockStartOld,
5750 (ObjectID *)pData->arrpbMemBlockStartNew,
5751 (SIZE_T *)pData->arrMemBlockSize);
5757 // Recompute sizes as ULONGs for legacy callback
5758 for (ULONG i = 0; i < pData->curIdx; i++)
5759 pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5763 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5764 // whose try/catch blocks aren't visible to the contract system
5765 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5766 hr = m_pCallback2->MovedReferences((ULONG)pData->curIdx,
5767 (ObjectID *)pData->arrpbMemBlockStartOld,
5768 (ObjectID *)pData->arrpbMemBlockStartNew,
5774 if (m_pCallback4 != NULL)
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 hr = m_pCallback4->SurvivingReferences2((ULONG)pData->curIdx,
5780 (ObjectID *)pData->arrpbMemBlockStartOld,
5781 (SIZE_T *)pData->arrMemBlockSize);
5787 // Recompute sizes as ULONGs for legacy callback
5788 for (ULONG i = 0; i < pData->curIdx; i++)
5789 pData->arrULONG[i] = (pData->arrMemBlockSize[i] > ULONG_MAX) ? ULONG_MAX : (ULONG)pData->arrMemBlockSize[i];
5793 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5794 // whose try/catch blocks aren't visible to the contract system
5795 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5796 hr = m_pCallback2->SurvivingReferences((ULONG)pData->curIdx,
5797 (ObjectID *)pData->arrpbMemBlockStartOld,
5805 HRESULT EEToProfInterfaceImpl::NotifyAllocByClass(AllocByClassData *pData)
5812 // This is called by the thread doing a GC WHILE it does the GC
5815 // This is called by the thread doing a GC WHILE it does the GC
5816 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5821 // Thread store lock normally held during this callback
5826 CLR_TO_PROFILER_ENTRYPOINT_EX(
5830 "**PROF: ObjectsAllocatedByClass.\n"));
5832 _ASSERTE(pData != NULL);
5833 _ASSERTE(pData->iHash > 0);
5835 // If the arrays are not long enough, get rid of them.
5836 if (pData->cLength != 0 && pData->iHash > pData->cLength)
5838 _ASSERTE(pData->arrClsId != NULL && pData->arrcObjects != NULL);
5839 delete [] pData->arrClsId;
5840 delete [] pData->arrcObjects;
5844 // If there are no arrays, must allocate them.
5845 if (pData->cLength == 0)
5847 pData->arrClsId = new (nothrow) ClassID[pData->iHash];
5848 if (pData->arrClsId == NULL)
5850 return E_OUTOFMEMORY;
5853 pData->arrcObjects = new (nothrow) ULONG[pData->iHash];
5854 if (pData->arrcObjects == NULL)
5856 delete [] pData->arrClsId;
5857 pData->arrClsId= NULL;
5859 return E_OUTOFMEMORY;
5862 // Indicate that the memory was successfully allocated
5863 pData->cLength = pData->iHash;
5866 // Now copy all the data
5868 CLASSHASHENTRY * pCur = (CLASSHASHENTRY *) pData->pHashTable->FindFirstEntry(&hFind);
5869 size_t iCur = 0; // current index for arrays
5871 while (pCur != NULL)
5873 _ASSERTE(iCur < pData->iHash);
5875 pData->arrClsId[iCur] = pCur->m_clsId;
5876 pData->arrcObjects[iCur] = (DWORD) pCur->m_count;
5878 // Move to the next entry
5880 pCur = (CLASSHASHENTRY *) pData->pHashTable->FindNextEntry(&hFind);
5883 _ASSERTE(iCur == pData->iHash);
5885 // Now communicate the results to the profiler
5887 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5888 // whose try/catch blocks aren't visible to the contract system
5889 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5890 return m_pCallback2->ObjectsAllocatedByClass((ULONG)pData->iHash, pData->arrClsId, pData->arrcObjects);
5894 HRESULT EEToProfInterfaceImpl::ObjectReference(ObjectID objId,
5897 ObjectID *arrObjRef)
5904 // This is called by the thread doing a GC WHILE it does the GC
5907 // This is called by the thread doing a GC WHILE it does the GC
5908 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5913 // Thread store lock normally held during this callback
5918 CLR_TO_PROFILER_ENTRYPOINT_EX(
5922 "**PROF: ObjectReferences.\n"));
5924 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5927 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5928 // whose try/catch blocks aren't visible to the contract system
5929 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5930 return m_pCallback2->ObjectReferences(objId, classId, cNumRefs, arrObjRef);
5935 HRESULT EEToProfInterfaceImpl::FinalizeableObjectQueued(BOOL isCritical, ObjectID objectID)
5945 // Can't be in preemptive when we're dealing in objectIDs!
5946 // However, it's possible we're on a non-EE Thread--that happens when this
5947 // is a server-mode GC thread.
5953 // Thread store lock normally held during this callback
5958 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
5960 "**PROF: Notifying profiler of finalizeable object.\n"));
5962 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
5965 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
5966 // whose try/catch blocks aren't visible to the contract system
5967 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
5968 return m_pCallback2->FinalizeableObjectQueued(isCritical ? COR_PRF_FINALIZER_CRITICAL : 0, objectID);
5973 HRESULT EEToProfInterfaceImpl::RootReferences2(GCReferencesData *pData)
5980 // This is called by the thread doing a GC WHILE it does the GC
5983 // This is called by the thread doing a GC WHILE it does the GC
5984 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
5989 // Thread store lock normally held during this callback
5994 CLR_TO_PROFILER_ENTRYPOINT_EX(
5998 "**PROF: RootReferences2.\n"));
6000 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6004 COR_PRF_GC_ROOT_FLAGS flags[kcReferencesMax];
6006 _ASSERTE(pData->curIdx <= kcReferencesMax);
6007 for (ULONG i = 0; i < pData->curIdx; i++)
6009 flags[i] = (COR_PRF_GC_ROOT_FLAGS)(pData->arrULONG[i] & 0xffff);
6010 pData->arrULONG[i] >>= 16;
6014 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6015 // whose try/catch blocks aren't visible to the contract system
6016 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6017 hr = m_pCallback2->RootReferences2((ULONG)pData->curIdx,
6018 (ObjectID *)pData->arrpbMemBlockStartOld,
6019 (COR_PRF_GC_ROOT_KIND *)pData->arrULONG,
6021 (ObjectID *)pData->arrpbMemBlockStartNew);
6027 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6028 // whose try/catch blocks aren't visible to the contract system
6029 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6030 hr = m_pCallback2->RootReferences((ULONG)pData->curIdx, (ObjectID *)pData->arrpbMemBlockStartOld);
6037 HRESULT EEToProfInterfaceImpl::ConditionalWeakTableElementReferences(GCReferencesData * pData)
6044 // This is called by the thread doing a GC WHILE it does the GC
6047 // This is called by the thread doing a GC WHILE it does the GC
6048 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6053 // Thread store lock normally held during this callback
6058 CLR_TO_PROFILER_ENTRYPOINT_EX(
6062 "**PROF: ConditionalWeakTableElementReferences.\n"));
6064 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6068 _ASSERTE(pData->curIdx <= kcReferencesMax);
6071 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6072 // whose try/catch blocks aren't visible to the contract system
6073 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6074 hr = m_pCallback5->ConditionalWeakTableElementReferences(
6075 (ULONG)pData->curIdx,
6076 (ObjectID *)pData->arrpbMemBlockStartOld,
6077 (ObjectID *)pData->arrpbMemBlockStartNew,
6078 (GCHandleID *)pData->arrpbRootId);
6084 HRESULT EEToProfInterfaceImpl::HandleCreated(UINT_PTR handleId, ObjectID initialObjectId)
6091 // Called by HndCreateHandle which is notrigger
6094 // This can be called in preemptive mode if initialObjectId is NULL.
6095 // Otherwise, this will be in cooperative mode. Note that, although this
6096 // can be called in preemptive, when it's called in cooperative we must not
6097 // switch to preemptive (as we normally do in callbacks) and must not trigger,
6098 // as this would really tick off some of our callers (as well as invalidating
6099 // initialObjectId).
6100 if (initialObjectId != NULL)
6112 // CrstAppDomainHandleTable can be held during this callback
6117 CLR_TO_PROFILER_ENTRYPOINT_EX(
6121 "**PROF: HandleCreated.\n"));
6124 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6125 // whose try/catch blocks aren't visible to the contract system
6126 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6127 return m_pCallback2->HandleCreated(handleId, initialObjectId);
6131 HRESULT EEToProfInterfaceImpl::HandleDestroyed(UINT_PTR handleId)
6138 // Called by HndDestroyHandle, which is notrigger. But HndDestroyHandle is also
6139 // MODE_ANY, so perhaps we can change the whole call path to be triggers?
6142 // Although we're called from a notrigger function, I verified empirically that
6143 // this is called coop & preemp
6149 // Thread store lock is typically held during this callback
6154 CLR_TO_PROFILER_ENTRYPOINT_EX(
6158 "**PROF: HandleDestroyed.\n"));
6161 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6162 // whose try/catch blocks aren't visible to the contract system
6163 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6164 return m_pCallback2->HandleDestroyed(handleId);
6168 HRESULT EEToProfInterfaceImpl::GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason)
6175 // This is called by the thread doing a GC WHILE it does the GC
6178 // This is called by the thread doing a GC WHILE it does the GC
6179 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6184 // Thread store lock normally held during this callback
6189 CLR_TO_PROFILER_ENTRYPOINT_EX(
6193 "**PROF: GarbageCollectionStarted.\n"));
6195 _ASSERTE(!CORProfilerTrackGC() || !GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6198 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6199 // whose try/catch blocks aren't visible to the contract system
6200 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6201 return m_pCallback2->GarbageCollectionStarted(cGenerations, generationCollected, reason);
6205 HRESULT EEToProfInterfaceImpl::GarbageCollectionFinished()
6212 // This is called by the thread doing a GC WHILE it does the GC
6215 // This is called by the thread doing a GC WHILE it does the GC
6216 if (GetThreadNULLOk()) { MODE_COOPERATIVE; }
6221 // Thread store lock normally held during this callback
6226 CLR_TO_PROFILER_ENTRYPOINT_EX(
6230 "**PROF: GarbageCollectionFinished.\n"));
6232 _ASSERTE(!CORProfilerTrackGC() || !GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled());
6235 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6236 // whose try/catch blocks aren't visible to the contract system
6237 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6238 return m_pCallback2->GarbageCollectionFinished();
6242 HRESULT EEToProfInterfaceImpl::ProfilerDetachSucceeded()
6258 // ProfilingAPIUtility::s_csStatus is held while this callback is issued.
6263 CLR_TO_PROFILER_ENTRYPOINT_EX(kEE2PAllowableWhileDetaching,
6266 "**PROF: ProfilerDetachSucceeded.\n"));
6268 // Should only be called on profilers that support ICorProfilerCallback3
6269 _ASSERTE(m_pCallback3 != NULL);
6272 // All callbacks are really NOTHROW, but that's enforced partially by the profiler,
6273 // whose try/catch blocks aren't visible to the contract system
6274 PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout);
6275 return m_pCallback3->ProfilerDetachSucceeded();
6281 HRESULT EEToProfInterfaceImpl::GetAssemblyReferences(LPCWSTR wszAssemblyPath, IAssemblyBindingClosure * pClosure, AssemblyReferenceClosureWalkContextForProfAPI * pContext)
6300 CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF,
6302 "**PROF: AssemblyReferenceClosureWalkStarted. wszAssemblyPath: 0x%p.\n",
6312 #endif // PROFILING_SUPPORTED